2017-01-31 3 views
0

Ich habe Probleme beim Umgang mit Nebenläufigkeitsproblemen beim Einfügen in eine Postgres-Datenbank. Das Modell verfügt über eine Eindeutigkeitseinschränkung für eine Indexspalte. Dies gilt auch für die Postgres-Tabelle. Manchmal versuchen zwei Threads, den gleichen Datensatz zur gleichen Zeit einzufügen (dies ist unvermeidlich), in welchem ​​Fall beide die Modellvalidierung bestehen, aber der zweite die Postgres-Validierung verletzt. Also ich fange die Ausnahme und alles ist in Ordnung. Das ist nicht das Problem.Wie kann ich die Datenbank nach einer Postgres-Ausnahme abfragen?

Das Problem ist, meine Methode muss das Objekt aus der Datenbank zurückgeben, so dass ich die db abfragen, um den Datensatz vom ersten Thread eingefügt zu bekommen (ich kann sicher annehmen, es ist das gleiche wie das im zweiten Thread). Dies schlägt jedoch fehl, da sich die Transaktion aufgrund des fehlgeschlagenen Einfügens immer noch in einem ungültigen Zustand befindet.

Meine Frage ist: Wie kann ich die zweite Ausnahme vermeiden, die innerhalb des Rettungsblocks ausgelöst wird, und/oder die Methode aktivieren, um den Datensatz zurückzugeben, der vom ersten Thread eingefügt wurde?

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

Was genau ist Ihre zweite Ausnahme? – archana

+0

@archana ActiveRecord :: AnweisungInvalid: PG :: InFailedSqlTransaction: FEHLER: aktuelle Transaktion wird abgebrochen, Befehle bis Ende des Transaktionsblocks ignoriert: SELECT "Orte". * FROM "Orte" WO "Orte". "ID" = "Some_id" LIMIT 1 –

+0

@archana Also im Grunde ist die Transaktion nicht beendet. Ich habe keine Transaktion gestartet, aber 'save' hat es getan. Die Implementierung von 'after_rollback' wird nicht helfen, da ich einen Wert von' create_and_insert' zurückgeben muss. Kann ich es aus 'create_and_insert' zurückholen? –

Antwort

1

In PostgreSQL, stellen Sie innerhalb einer Transaktion eine savepoint so, dass Sie den Teil der Transaktion zurückrollen kann, die den Fehler verursacht hat; dies wird als Subtransaktion bezeichnet.

Sie können dies in Ruby on Rails verwenden, siehe the documentation.

Verwandte Themen