2017-01-31 5 views
0

У меня возникли проблемы с решением проблем параллелизма при вставке в базу данных Postgres. Модель имеет ограничение уникальности для столбца индекса, а также таблицу Postgres. Иногда два потока пытаются вставить одну и ту же запись одновременно (это неизбежно), и в этом случае оба передают проверку модели, а вторая нарушает проверку Postgres. Поэтому я поймаю исключение, и все в порядке. Это не проблема.Как я могу запросить базу данных после исключения Postgres?

Проблема заключается в том, что мой метод должен возвращать объект из базы данных, поэтому я запрашиваю db, чтобы получить запись, вставленную первым потоком (я могу смело предположить, что это то же самое, что и во втором потоке). Однако это не удается, поскольку транзакция по-прежнему находится в недопустимом состоянии из-за неудачной вставки.

Мой вопрос: Как я могу избежать второго исключения, брошенного в блок спасения, и/или включить метод для возврата записи, которая была вставлена ​​первым потоком?

class Place 
     validates :index_column, uniqueness: true, allow_nil: true 

    def self.create_and_insert(some_params) 
     more_params = additional_params(some_params) 
     place = Place.new(some_params, more_params) 

     begin 
     place.save # Insert into place table. This initiates a transaction. 
     rescue ActiveRecord::RecordNotUnique => e 
     # Oops! Another thread beat us to it. 
     # The transaction is now in an invalid state. 
     place = Place.find_by(index_column: some_params.id) # This throws a new exception 
     end 

     place 

    end 
    end 
+0

В чем же ваше второе исключение? – archana

+0

@archana ActiveRecord :: StatementInvalid: PG :: InFailedSqlTransaction: ERROR: текущая транзакция прерывается, команды игнорируются до конца транзакционного блока: SELECT "places". * FROM "places" WHERE "places". "Id" = 'some_id' LIMIT 1 –

+0

@archana Так что в принципе сделка не закончилась. Я не начал транзакцию, но «save» сделал. Реализация 'after_rollback' не поможет, потому что мне нужно вернуть значение из' create_and_insert'. Могу ли я откатить его обратно из 'create_and_insert'? –

ответ

1

В PostgreSQL, вы установили savepoint внутри транзакции, так что вы можете откатить часть сделки, которая вызвала ошибку; это называется subtransaction.

Вы можете использовать это в Ruby on Rails, см. the documentation.