简体   繁体   中英

What will happen if we begin transaction in hibernate but do not commit it?

What will happen if we begin transaction in hibernate, then do some transaction but do not commit it? Will it save tempervoraly or it will rollback immediately?

Thanks Chetan

Look at the following code, which accesses the database with transaction boundaries without use of commit:

Session session = sessionFactory.openSession();
session.beginTransaction(); 
session.get(Item.class, 123l); 
session.close(); 

By default, in a Java SE environment with a JDBC configuration, this is what happens if you execute this snippet:

  1. A new Session is opened. It doesn't obtain a database connection at this point.
  2. If a new underlying transaction is required, begin the transaction. Otherwise continue the new work in the context of the existing underlying transaction
  3. The call to get() triggers an SQL SELECT. The Session now obtains a JDBC Connection from the connection pool. Hibernate, by default, immediately turns off the autocommit mode on this connection with setAutoCommit(false). This effectively starts a JDBC transaction!
  4. The SELECT is executed inside this JDBC transaction. The Session is closed, and the connection is returned to the pool and released by Hibernate — Hibernate calls close() on the JDBC Connection.

    What happens to the uncommitted transaction?

The answer to that question is, “It depends!” The JDBC specification doesn't say anything about pending transactions when close() is called on a connection. What happens depends on how the vendors implement the specification. With Oracle JDBC drivers, for example, the call to close() commits the transaction! Most other JDBC vendors take the sane route and roll back any pending transaction when the JDBC Connection object is closed and the resource is returned to the pool.

Obviously, this won't be a problem for the SELECT you've executed, but look at this variation:

Session session = getSessionFactory().openSession(); 
session.beginTransaction();
Long generatedId = session.save(item); 
session.close(); 

This code results in an INSERT statement, executed inside a transaction that is never committed or rolled back. On Oracle, this piece of code inserts data permanently; in other databases, it may not. (This situation is slightly more complicated: The INSERT is executed only if the identifier generator requires it. For example, an identifier value can be obtained from a sequence without an INSERT. The persistent entity is then queued until flush-time insertion — which never happens in this code. An identity strategy requires an immediate INSERT for the value to be generated.)

Its depend on hibernate-config and the connection pool config.

When try to close a session with an open transaction hibernate by default will not call to close on connection proxy (if you want to change this you need to define - hibernate.ejb.discard_pc_on_close true)

public void close() {
    if ( !open ) {
        throw new IllegalStateException( "EntityManager is closed" );
    }
    if ( !discardOnClose && isTransactionInProgress() ) {

Now , suppose that you defined discard_pc_on_close than in this case hibernate will call to close on the connection proxy (connection pool wrap connections), so now we depend on how the connection pool implement this. You can see c3p0 implementation in : NewPooledConnection. You will see that its depend on this flag - FORCE_IGNORE_UNRESOLVED_TXNS (default is false), so by default it will reset the transaction.

static void resetTxnState( Connection pCon, 
               boolean forceIgnoreUnresolvedTransactions, 
               boolean autoCommitOnClose, 
               boolean txnKnownResolved ) throws SQLException
{
if ( !forceIgnoreUnresolvedTransactions && !pCon.getAutoCommit() )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM