Spring的事务传播机制 1. REQUIRED Support a current transaction, create a new one if none exists.
存在事务则加入当前事务,不存在则创建事务。spring事务默认传播级别
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Test { @Transactional(propagation = Propagation.REQUIRED) public void methodA () { jdbcTemplate.execute("insert into user values(null, 'songbiao', 20)" ); } @Test public void test () { ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext ("spring.xml" ); TransactionStudy tx = app.getBean(TransactionStudy.class); DataSourceTransactionManager transactionManager = app.getBean(DataSourceTransactionManager.class); DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition (); defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); TransactionStatus status = transactionManager.getTransaction(defaultTransactionDefinition); tx.methodA(); tx.methodA(); if (true ) throw new RuntimeException (); transactionManager.commit(status); } }
测试结果: tx1和tx2加入存在的事务,tx1和tx2执行的sql语句会被一起回滚, catch异常也同样会回滚事务。
2. SUPPORTS Support a current transaction, execute non-transactionally if none exists.
存在事务则加入事务,不存在事务则非事务执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Test { @Transactional(propagation = Propagation.SUPPORTS) public void methodB () { jdbcTemplate.execute("insert into user values(null, 'xiaowang', 21)" ); if (true ) { throw new RuntimeException ("SUPPORTS 回滚测试" ); } } @Test public void test () { ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext ("spring.xml" ); TransactionStudy tx = app.getBean(TransactionStudy.class); DataSourceTransactionManager transactionManager = app.getBean(DataSourceTransactionManager.class); DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition (); defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); TransactionStatus status = transactionManager.getTransaction(defaultTransactionDefinition); tx.methodB(); transactionManager.commit(status); } }
测试结果: tx1加入存在的事务,tx1事务回滚,若不存在事务,tx1以非事务执行,tx1将成功添加一条数据。
3. MANDATORY Support a current transaction, throw an exception if none exists.
存在事务则加入当前事务,不存在事务则抛出异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Test { @Transactional(propagation = Propagation.MANDATORY) public void methodA () { jdbcTemplate.execute("insert into user values(null, 'songbiao', 20)" ); } @Test public void test () { ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext ("spring.xml" ); TransactionStudy tx = app.getBean(TransactionStudy.class); DataSourceTransactionManager transactionManager = app.getBean(DataSourceTransactionManager.class); DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition (); defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); tx.methodA(); } }
测试结果:org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'
4. REQUIRES_NEW Create a new transaction, and suspend the current transaction if one exists.
创建一个事务,如果存在事务则挂起存在的事务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Test { @Transactional(propagation = Propagation.REQUIRES_NEW) public void methodA () { jdbcTemplate.execute("insert into user values(null, 'songbiao', 20)" ); } public void methodC () { jdbcTemplate.execute("insert into user values(null, 'methodC', 22)" ); } @Test public void test () { ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext ("spring.xml" ); TransactionStudy tx = app.getBean(TransactionStudy.class); DataSourceTransactionManager transactionManager = app.getBean(DataSourceTransactionManager.class); DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition (); defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); TransactionStatus status = transactionManager.getTransaction(defaultTransactionDefinition); tx.methodC(); tx.methodA(); if (true ) throw new RuntimeException (); transactionManager.commit(status); } }
测试结果: tx1事务回滚,tx2创建了新事务,tx2事务成功添加一条数据
5. NOT_SUPPORTED Execute non-transactionally, suspend the current transaction if one exists.
非事务执行,如果存在事务则挂起存在的事务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Test { @Transactional(propagation = Propagation.NOT_SUPPORTED) public void methodA () { jdbcTemplate.execute("insert into user values(null, 'songbiao', 20)" ); } public void methodC () { jdbcTemplate.execute("insert into user values(null, 'methodC', 22)" ); } @Test public void test () { ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext ("spring.xml" ); TransactionStudy tx = app.getBean(TransactionStudy.class); DataSourceTransactionManager transactionManager = app.getBean(DataSourceTransactionManager.class); DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition (); defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); TransactionStatus status = transactionManager.getTransaction(defaultTransactionDefinition); tx.methodC(); tx.methodA(); if (true ) throw new RuntimeException (); transactionManager.commit(status); } }
测试结果: 由于tx2是非事务执行,tx1事务回滚,tx2事务添加一条数据
6. NEVER Execute non-transactionally, throw an exception if a transaction exists.
非事务执行,如果存在事务则抛出异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Test { @Transactional(propagation = Propagation.NEVER) public void methodA () { jdbcTemplate.execute("insert into user values(null, 'songbiao', 20)" ); } @Test public void test () { ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext ("spring.xml" ); TransactionStudy tx = app.getBean(TransactionStudy.class); DataSourceTransactionManager transactionManager = app.getBean(DataSourceTransactionManager.class); DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition (); defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); TransactionStatus status = transactionManager.getTransaction(defaultTransactionDefinition); tx.methodA(); transactionManager.commit(status); } }
测试结果: org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'
7. NESTED Execute within a nested transaction if a current transaction exists, behave like REQUIRED otherwise.
如果存在事务则嵌套执行事务,若不存在事务退化成REQUIRED传播行为
案例1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class Test { @Transactional(propagation = Propagation.NESTED) public void methodA () { jdbcTemplate.execute("insert into user values(null, 'songbiao', 20)" ); throw new RuntimeException ("nested exception." ); } public void methodC () { jdbcTemplate.execute("insert into user values(null, 'methodC', 22)" ); } @Test public void test () { ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext ("spring.xml" ); TransactionStudy tx = app.getBean(TransactionStudy.class); DataSourceTransactionManager transactionManager = app.getBean(DataSourceTransactionManager.class); DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition (); defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); TransactionStatus status = transactionManager.getTransaction(defaultTransactionDefinition); try { tx.methodC(); tx.methodA(); } catch (Exception e) { e.printStackTrace(); } transactionManager.commit(status); } }
若存在事务,保存当前事务状态点,加入存在的事务,执行完嵌套事务后恢复到保存的事务状态点完成事务执行。
测试结果:保存tx1事务状态点,tx2加入存在的事务,tx2抛出异常,回滚tx2的事务状态,恢复到tx1事务状态点,提交事务,tx1事务成功添加一条数据。 2. 案例2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class Test { public A a; @Transactional(propagation = Propagation.NESTED) public void methodA () { jdbcTemplate.execute("insert into user values(null, 'songbiao', 20)" ); a.nestTxTest(); } @Test public void test () { ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext ("spring.xml" ); TransactionStudy tx = app.getBean(TransactionStudy.class); DataSourceTransactionManager transactionManager = app.getBean(DataSourceTransactionManager.class); DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition (); defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); tx.methodA(); } } public class A { @Transactional(propagation = Propagation.NEVER) public void nestTxTest () { jdbcTemplate.execute("insert into user values(null, 'A', 20)" ); } }
当前不存在事务,NESTED传播行为退化成REQUIRED传播行为。
测试结果: org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'
,tx1事务回滚
总结 花了很多的时间来学习测试事务的传播机制,根据实际测试,跟之前的认知还是有一点偏差。 关于使用的场景,默认的传播行为一般用的最多,以后涉及到事务的传播行为需再三斟酌!