javapostgresqljdbcbatch-updatesbatch-insert

Batch Update: connection.commit() at the very end, with setAutoCommit(false), but data doesn't get rolled back


My Java JDBC call for a Batch-Update is structured as

conn.setAutoCommit(false);

for (int i = 0; i < items.size(); i++) {
    //...
    ps.addBatch();
}

ps.executeBatch();

// Suppose an exception happens right before a Commit
if (someCondition)
   throw new Exception("test");

conn.commit(); // Commit at the very end

My understanding is, when that Exception happens, I never reached a commit. So my data shouldn't be persisted, right? As long as the commit is at the very end, and setAutoCommit(false); is specified, any exceptions don't require a rollback?

But I see that the data does get persisted. My question is why? And do I need a connection.rollback();? (This is with a Postgres DB)


Solution

  • Please take a look at the transaction isolation levels of PostgreSQL:

    https://www.postgresql.org/docs/9.5/transaction-iso.html

    The default is READ COMMITTED which is good for you.

    Reading back 'uncommited' changes depends on the JDBC connection you're using. Every connection will have a different 'view' on the data depending on the transaction isolation level.

    Best practice when setting

    conn.setAutoCommit(false);
    

    is to have a commit at success and a rollback in a catch clause:

    conn.setAutoCommit(false);
    try {
      ...
      ps.executeBatch();
      conn.commit();
    } catch (Exception e) {
      conn.rollback();
    }
    

    Calling neither commit nor rollback will keep the connection open, putting load on the database for maintaining uncommitted changes. The JVM will then some time close the connection and the database will roll back all data.

    JEE containers roll back transaction automatically when uncaught exceptions happen.