Table of Contents
Assume your project has the following JPA transaction requirements
- Start long a running JTA transaction
- Within the same thread which starts the JTA transaction you need to integrate a JAVA package which runs JDBC initiated COMMITs
- The transaction outcome of this local transaction should be independent from our global JTA traansaction
Test Environment
12:09:59.294 Hibernate Version: 4.3.7.Final 12:09:59.294 Driver Name : Oracle JDBC driver 12:09:59.294 Driver Version : 12.1.0.2.0 12:09:59.294 Database Product Version: Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP, Advanced Analytics and Real Application Testing options 12:10:01.448 DB Name: BANKA 12:10:01.449 1. Instance Name: bankA_1 - Host: hract21.example.com - Pooled XA Connections: 34 12:10:01.449 2. Instance Name: bankA_3 - Host: hract22.example.com - Pooled XA Connections: 33
Call Flow using UserTransaction API [ not working ]
Global JPA transaction: ut = (UserTransaction)new InitialContext().lookup("java:comp/UserTransaction"); ut.begin(); em=getEntityManager(); em.joinTransaction(); em.persist(e); em.flush(); // Insert record into our RAC DB em.merge(e); // Update new record Start local transaction which is independent from global transaction !! Connection c1 = ds1.getConnection(); preparedStmt.executeUpdate(); c1.commit(); -> Local Commit fails with following error Error 11:13:57.087 Error in writelog() 11:13:57.090 You cannot commit during a managed transaction! 11:13:57.091 java.sql.SQLException: You cannot commit during a managed transaction! at org.jboss.jca.adapters.jdbc.BaseWrapperManagedConnection.jdbcCommit(BaseWrapperManagedConnection.java:1065) at org.jboss.jca.adapters.jdbc.WrappedConnection.commit(WrappedConnection.java:758) at com.hhu.wfjpa2el.JPATestBean.writeLog(JPATestBean.java:1729) at com.hhu.wfjpa2el.JPATestBean.increaseSalary(JPATestBean.java:1221) at com.hhu.wfjpa2el.JPATestBean.testSuspend(JPATestBean.java:630) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-> Your are not allowed to call commit() or rollback() when a JTA transaction is ACTIVE !
Fix : Use the JEE 6 introduced TM API and suspend/resume the JTA transaction
Call Flow tm = (TransactionManager)ctx.lookup("java:/TransactionManager"); tm.setTransactionTimeout(txTimeout); tm.begin(); em=getEntityManager(); em.joinTransaction(); em.persist(e); em.flush(); // Insert record into our RAC DB em.merge(e); // Update new record tx = tm.suspend(); // Save the transaction handle - we need to resume the transaction again -> Global Transaction is suspended now Start local transaction which is independent from global transaction !! Connection c1 = ds1.getConnection(); c1.setAutoCommit(false); preparedStmt.executeUpdate(); c1.commit(); -> Local Transaction is commited Resume global JTA transaction tm.resume(tx); em.merge(e); tm.commit(); -> Global JTA transaction is now commited
Working Log
2:14:31.826 Calling increaseSalary() in progress - ID: 9997 - isUseSuspend : true 12:14:31.826 ------- Testing Suspend/Resume Operation ---------- 12:14:31.826 Lookup Transactionmanager: ctx.lookup(java:/TransactionManager) - Tx Timeout: 120 12:14:31.827 Begin Transaction: tm.begin() - Before [TM status: 6 - STATUS_NO_TRANSACTION] - After [TM status: 0 - STATUS_ACTIVE] 12:14:41.569 checkEntity() - : empno: 1000001 - Record not yet found in Database ! 12:14:41.569 :: After First Salary Change - Old Sal : 1000 - Salary Increase I : 500 - Current Salary: 1500 12:14:41.570 Suspended Transaction: tm.suspend() - Before [TM status: 0 - STATUS_ACTIVE] - After [TM status: 6 - STATUS_NO_TRANSACTION] 12:14:41.570 writelog():: Message: 12:14:41.570 :: After First Salary Change - Old Sal : 1000 - Salary Increase I : 500 - Current Salary: 1500 - ENO: 1000001 12:14:41.624 Leaving writelog() without Exceptions - Data commited ! 12:14:41.624 Resumed Transaction: tm.resume(transaction) - Before [TM status: 6 - STATUS_NO_TRANSACTION] - After [TM status: 0 - STATUS_ACTIVE] 12:14:41.692 :: Commit Tx: tm.commit() done - Before [TM status: 0 - STATUS_ACTIVE] - After [TM status: 6 - STATUS_NO_TRANSACTION] 12:14:41.692 writelog():: Message: 12:14:41.692 :: 2nd Salary Change - Old Sal : 1000 - Salary Increase II : 99 - Current Salary: 1599 Need to Rollback : false - ENO: 1000001 12:14:41.779 Leaving writelog() without Exceptions - Data commited ! 12:14:41.780 writelog():: Message: 12:14:41.780 :: Commit Tx: tm.commit() done - Before [TM status: 0 - STATUS_ACTIVE] - After [TM status: 6 - STATUS_NO_TRANSACTION] - ENO: 1000001 12:14:41.801 Leaving writelog() without Exceptions - Data commited ! 12:14:41.801 ------- Clear an reread Entity after TX completion ---------- 12:14:41.848 checkEntity() - : empno: 1000001 - Sal: 1599 - Entity Salary Persistence : 1599 - Managed Entity Status : true - STALE Data: false 12:14:41.940 -->readLog(): [empno=1000001] - Found 3 Records 12:14:41.940 : LogID: 20 - 12:14:41.570 :: After First Salary Change - Old Sal : 1000 - Salary Increase I : 500 - Current Salary: 1500 12:14:41.940 : LogID: 21 - 12:14:41.692 :: 2nd Salary Change - Old Sal : 1000 - Salary Increase II : 99 - Current Salary: 1599 Need to Rollback : false 12:14:41.940 : LogID: 22 - 12:14:41.780 :: Commit Tx: tm.commit() done - Before [TM status: 0 - STATUS_ACTIVE] - After [TM status: 6 - STATUS_NO_TRANSACTION] 12:14:41.940 Leaving increaseSalary() without Exceptions ! 12:14:41.940 Leaving increaseSalary() - Entity manager closed !