问题
I have written below code doing below activities I created one transaction using Spring classes. Inserted one row. Created other transaction. Inserted another row. committed outer transaction. Rolledback inner transaction.
TransactionStatus trxstsOuter= dsTrxMngr.getTransaction(null);
jdbcTemplate.update("insert into kau_emp values(6,'xyz' )");
TransactionStatus trxstsInner= dsTrxMngr.getTransaction(null);
jdbcTemplate.update("insert into kau_emp values(7,'pqr' )");
dsTrxMngr.commit(trxstsOuter);
System.out.println("trxstsOuter.isCompleted()" + trxstsOuter.isCompleted());
System.out.println("trxstsInner.isCompleted()" + trxstsInner.isCompleted());
dsTrxMngr.rollback(trxstsInner);
System.out.println("trxstsInner.isCompleted()" + trxstsInner.isCompleted());
I observed that both the rows are committed to DB !! The output is
trxstsOuter.isCompleted()true
trxstsInner.isCompleted()false
trxstsInner.isCompleted()true
Is it correct behavior ? Should not inner transaction be first committed/rollbacked before allowing outer transaction to commit ? If outer transaction was committed, should rollback of inner thrown an error ?
回答1:
In your example transaction Propagation.REQUIRED
is used as the default value, and all the logic transactions are mapped to the single physical transaction
When the propagation setting is PROPAGATION_REQUIRED, a logical transaction scope is created for each method upon which the setting is applied. Each such logical transaction scope can determine rollback-only status individually, with an outer transaction scope being logically independent from the inner transaction scope. Of course, in case of standard PROPAGATION_REQUIRED behavior, all these scopes will be mapped to the same physical transaction. So a rollback-only marker set in the inner transaction scope does affect the outer transaction's chance to actually commit (as you would expect it to).
So in your example two logical transactions are mapped to one physical transaction.
See the documentation
回答2:
In the current code the second getTransaction call is a noop. This behavior is controlled by an attribute called PropagationBehavior. The default propagation behavior is PROPAGATION_REQUIRED - which means that start a new transaction if none exists or else join the existing transaction. Which is what is happening in your case.
If you change the propagation behavior attribute for the second transaction to PROPAGATION_REQUIRES_NEW - you will get the behavior you are expected. The outer transaction is suspended and a new transaction is created once the inner transaction is committed/rolled back the outer transaction is resumed automatically. I have modified your code to incorporate this behavior, you should get an exception now when you try to commit the outer transaction before the inner one. If you fix the sequence then the commits will happen independently.
TransactionStatus trxstsOuter= dsTrxMngr.getTransaction(null);
jdbcTemplate.update("insert into kau_emp values(6,'xyz' )");
// start a new transaction.
DefaultTransactionDefinition nestedTransDef = new DefaultTransactionDefinition();
nestedTransDef.setPropagationBehavior(
TransactionDefinition.PROPAGATION_REQUIRES_NEW);
TransactionStatus trxstsInner= dsTrxMngr.getTransaction(nestedTransDef);
System.out.println("trxstsInner.isNewTransaction()"+ trxstsInner.isNewTransaction());
jdbcTemplate.update("insert into kau_emp values(7,'pqr' )");
dsTrxMngr.commit(trxstsOuter);
System.out.println("trxstsOuter.isCompleted()" + trxstsOuter.isCompleted());
System.out.println("trxstsInner.isCompleted()" + trxstsInner.isCompleted());
dsTrxMngr.rollback(trxstsInner);
System.out.println("trxstsInner.isCompleted()" + trxstsInner.isCompleted());
As an aside you should be using annotations for managing transactions -that is a much cleaner / nicer way of incorporating transactions in your code. Programmatic transactions are only for those rare cases where you need more control. Also while doing programmatic transaction using the TransactionTemplate is recommended.
来源:https://stackoverflow.com/questions/13786816/spring-programmatic-transaction-within-transaction