Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring programmatic transaction management caveat?

Spring supports programmatic transaction which give us fine grained control over TX management. According to Spring Documentation, One can use programmatic TX management by:
1. utilizing Spring's TransactionTemplate:

transactionTemplate.execute(new TransactionCallbackWithoutResult() {

protected void doInTransactionWithoutResult(TransactionStatus status) {
    try {
        updateOperation1();
        updateOperation2();
    } catch (SomeBusinessExeption ex) {
        status.setRollbackOnly();
    }
} });

2. leveraging PlatformTransactionManager directly(inject a PlatformTransactionManager implementation into DAO):

DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

//txManager is a reference to PlatformTransactionManager
TransactionStatus status = txManager.getTransaction(def);
try {
  updateOperation1();
  updateOperation2();
}
catch (MyException ex) {
    txManager.rollback(status);
    throw ex;
}
txManager.commit(status);

for the sake of simplification, let's say we are dealing with JDBC database operation.

I am wondering for any database operations happened at updateOperation1(),updateOperation2() in the second snippet, either it is implemented with JDBCTemplate or JDBCDaoSupport, if not, the operation is actually not performed within any transaction, is it?

My analysis is that if we don't use JDBCTemplate or JDBCDaoSupport, we inevitably will create/retrieve connection from datasource management. the connection we get is of course not the connection used by PlatformTransactionManager underlying to manage transaction.

I dug Spring source code and skim related class found that PlatformTransactionManager will try to retrieve a connection contained in ConnectionHolder which in return retrieved from TransactionSynchronizationManager. I also found JDBCTemplate and JDBCDaoSupport, also try to get connection with similar routine from TransactionSynchronizationManager.

Because TransactionSynchronizationManager manages many resource including connection per thread(basically use Threadlocal to ensure one thread get its own unique instance of the managed resource)

So I think the connection retrieved by PlatformTransactionManager and JDBCTemplate or JDBCDaoSupport is just same, this can explain how spring programmatic transaction ensure updateOperation1(),updateOperation2() were guarded by transaction.

Is my analysis correct? if it is, why Spring documentation hasn't emphasized this caveat?

like image 741
didxga Avatar asked Jun 18 '12 17:06

didxga


1 Answers

Yes, it's correct.

Any code that uses raw Connections should obtain them from the DataSource in special way in order to participate in transactions managed by Spring (12.3.8 DataSourceTransactionManager):

Application code is required to retrieve the JDBC connection through DataSourceUtils.getConnection(DataSource) instead of Java EE's standard DataSource.getConnection.

Another option (if you cannot change code that calls getConnection()) is to wrap your DataSource with TransactionAwareDataSourceProxy.

like image 172
axtavt Avatar answered Sep 22 '22 13:09

axtavt