Wie funktionieren Savepoints mit Hibernate?

X5-599

Grünschnabel
Hallo zusammen,

Ich benutze Hibernate erstmal zur Probe mit einer sehr einfachen Tabelle. Alle CRUD Operationen funktionieren auch soweit. Nun versuche ich die Savepoints zu nutzen. Leider ignoriert Hibernate den Rollback zu einem solchen.

Code:
Transaction tx = HibernateUtil.getSessionFactory().getCurrentSession().beginTransaction();

Benutzer benutzer1 = benutzerDAO.findById(new Integer(1), false);
benutzer1.setVorname("Jane");
benutzerDAO.saveOrUpdate(benutzer1);

SetSavepointWork work = new SetSavepointWork("my_savepoint");
HibernateUtil.getSessionFactory().getCurrentSession().doWork(work);
Savepoint savepoint = work.getSavepoint();

benutzer1.setVorname("John");
benutzerDAO.saveOrUpdate(benutzer1);
HibernateUtil.getSessionFactory().getCurrentSession().doWork(new Work(){
         public void execute(Connection connection) throws SQLException
         {
            connection.rollback(savepoint);
         }
      });
tx.commit();

Die SetSavepointWork Klasse ist eine simple Implementierung des Work Interfaces. Sie hält zusätzlich den Savepoint und kann ihn per Getter zurückgeben.

Wo liegt also mein Fehler? Ich erwarte, dass ich den Vornamen auf 'Jane' setze, in die DB schreibe, dann einen Befehl absetze der den Vornamen auf 'John' setzt und in die DB schreibt. Aber dann einen Rollback auf den Zeitpunkt macht zu dem nur 'Jane' gesetzt sein sollte.
Leider wird das ignoriert und der finale Eintrag in der DB ist die Aktion des letzten Setters ('John')...

Ich hoffe ihr könnt mir da etwas weiterhelfen.

Gruß,
Michael
 
Es is teine PostgreSQL DB... Soweit ic hweiss funktionieren "normale" SAVEPOINTS per SQL Befehl...

Danke aber trotzdem für deine Antwort.

Gruß,
Michael
 
Zuletzt bearbeitet:
Jetzt mal ganz blöd gefragt: macht das was aus? Vermutlich schon (wenn du es so sagst)

Wenn PostgreSQL tatsächlich autocommit als Standard hat, müsste doch eine Einstellung in der hibernate.cfg.xml dieses verhalten auschalten können, richtig? Ich denke da an: hibernate.connection.autocommit

Ich werde es gleich mal ausprobieren. Danke schonmal für den Tipp!
 
Hab es gerade probiert. Leider gibt es keine Änderung im Verhalten. Ich habe autocommit auf false gestellt und versucht per Hibernate einen Rollback auf einen Savepoint zu machen... doch leider ohne Erfolg. Änderungen an Entities (.setname("xyz")) werden trotz rollback beim commit() in die DB geschrieben.

Gibt es noch eine andere Möglichkeit, warum es nicht funktioniert?
 
Hi,
an anderer Stelle habe ich ein etwas anderes Anwenden von Savepoints gefunden :

Java:
  String savepointName = "mySavePoint";
  Savepoint savePoint = conn.setSavepoint(savepointName);
  try {
     stmt.execute();
  } catch (SQLException sqle) {
      conn.rollback(savePoint);
  }

Versuch das doch mal zu adaptieren bzw. in der Hibernate Doku nachzuschlagen. Es sieht so aus, als wenn Deine Savepointverdrahtung gar nicht richtig funktioniert.

Grüße
gore
 
Hi,

doch doch, sie funktioniert schon. Ich hatte leider fehlendes Verständnis betrefflich des flush Mechanismus. Bei mir funktioniert es jetzt so:

Code:
Transaction tx = HibernateUtil.getSessionFactory().getCurrentSession().beginTransaction();

User user1 = userDAO.findById(new Integer(1), false);
user1.setFirstname("Jane");
userDAO.flush();


Savepoint savepoint = userDAO.setSavepoint("my_savepoint");

user1.setFirstname("John");
userDAO.flush();

userDAO.rollbackSavepoint(savepoint);
tx.commit();

nach dem commit steht als Vorname in der Datenbank jetzt: "Jane" (wie erwartet)
Die Savepoint Methoden des DAOs sehen übrigens so aus:

Code:
private Savepoint savepoint;

public Savepoint setSavepoint(final String savePoint)
{
   getSession().doWork(new Work()
   {
      public void execute(Connection connection) throws SQLException
      {
         savepoint = connection.setSavepoint(savePoint);
      }
   });
   return savepoint;
}

public void rollbackSavepoint(final Savepoint savepoint)
{
   getSession().doWork(new Work(){
      public void execute(Connection connection) throws SQLException
      {
         connection.rollback(savepoint);
      }
   });
}

So wie ich es verstehe ist das doWork() von Hibernate vorgesehen um JDBC bezogene Arbeiten mit der von dieser Session gemanage'ten Connection auszuführen...

Vielen Dank für die Hilfe. Bis zum nächsten Mal.

Gruß,
Michael
 
Zurück