Spring事务传播机制实战

一篇文章带你精通Spring事务传播机制,三十个测试覆盖你所有常用场景。

Talk is cheap. Show me the code.

源代码地址

/**
 * 启动参数加上  -Dsun.misc.ProxyGenerator.saveGeneratedFiles=true -Dcglib.debugLocation=D:\cglib  以便查看动态代理生成的字节码文件
 */
@RunWith(SpringRunner.class)
@SpringBootTest
@FixMethodOrder()
public class TransactionPropagationTest {

    @Autowired
    private PhotoService photoService;

    @Autowired
    private PhotoMapperOne photoMapperOne;

    @Autowired
    private PhotoMapperTwo photoMapperTwo;

    @Autowired
    @Qualifier("jdbcTemplateOne")
    private JdbcTemplate jdbcTemplateOne;

    @Autowired
    @Qualifier("jdbcTemplateTwo")
    private JdbcTemplate jdbcTemplateTwo;

    private static PhotoBO photoBO = new PhotoBO();

    private String createTableSql = "" +
            "create table if not exists photo\n" +
            "(\n" +
            "  id bigint auto_increment,\n" +
            "  name varchar(64) default '' not null,\n" +
            "  url varchar(128) default '' not null\n" +
            ")";

    /**
     * 此处注意下 H2的truncate语句和MySQL的truncate语句有细微差别(H2 多了 table)
     */
    private String truncateTableSql = "truncate table photo";

    /**
     * 测试开始之前初始化需要的数据
     */
    @BeforeClass
    public static void testBeforeClass() {
        photoBO.setName("transaction");
        photoBO.setUrl("xxx/xxx/transaction");
    }

    /**
     * 每个测试方法运行之前都清空两个数据库中对应的表中的数据
     */
    @Before
    public void testBefore() {
        jdbcTemplateOne.execute(createTableSql);
        jdbcTemplateTwo.execute(createTableSql);
        jdbcTemplateOne.execute(truncateTableSql);
        jdbcTemplateTwo.execute(truncateTableSql);
    }

    /**
     * 接下来就开始进行单数据源,单事务管理器,多数据源,多事务管理器,以及不同数据源配合不同事务管理器的实验
     * 

* 首先进行单数据源,单事务管理器情况下,Spring事务传播的特性测试 * * @see org.springframework.transaction.annotation.Propagation#REQUIRED *

* 第一个测试 REQUIRED 机制下外方法抛出异常之后事务的回滚情况 */ @Test() public void test1() { try { photoService.baseTwo(photoBO, Propagation.REQUIRED, true, false); } catch (Exception e) { } Assert.assertEquals(0, selectCountSameTable()); } /** * @see org.springframework.transaction.annotation.Propagation#REQUIRED *

* 测试 REQUIRED 机制下内方法抛出异常之后事务的回滚情况 */ @Test() public void test2() { try { photoService.baseTwo(photoBO, Propagation.REQUIRED, false, true); } catch (Exception e) { } Assert.assertEquals(0, selectCountSameTable()); } /** * @see org.springframework.transaction.annotation.Propagation#REQUIRES_NEW *

* 测试 REQUIRES_NEW 机制下外方法抛出异常之后事务的回滚情况 */ @Test() public void test3() { try { photoService.baseTwo(photoBO, Propagation.REQUIRES_NEW, true, false); } catch (Exception e) { } Assert.assertEquals(1, selectCountSameTable()); } /** * @see org.springframework.transaction.annotation.Propagation#REQUIRES_NEW *

* 测试 REQUIRES_NEW 机制下内方法抛出异常之后事务的回滚情况 */ @Test() public void test4() { try { photoService.baseTwo(photoBO, Propagation.REQUIRES_NEW, false, true); } catch (Exception e) { } Assert.assertEquals(1, selectCountSameTable()); } /** * @see org.springframework.transaction.annotation.Propagation#SUPPORTS *

* 测试 SUPPORTS 机制下外方法抛出异常之后事务的回滚情况 */ @Test() public void test5() { try { photoService.baseTwo(photoBO, Propagation.SUPPORTS, true, false); } catch (Exception e) { } Assert.assertEquals(0, selectCountSameTable()); } /** * @see org.springframework.transaction.annotation.Propagation#SUPPORTS *

* 测试 SUPPORTS 机制下内方法抛出异常之后事务的回滚情况 */ @Test() public void test6() { try { photoService.baseTwo(photoBO, Propagation.SUPPORTS, false, true); } catch (Exception e) { } Assert.assertEquals(0, selectCountSameTable()); } /** * @see org.springframework.transaction.annotation.Propagation#NOT_SUPPORTED *

* 测试 NOT_SUPPORTED 机制下外方法抛出异常之后事务的回滚情况 */ @Test() public void test7() { try { photoService.baseTwo(photoBO, Propagation.NOT_SUPPORTED, true, false); } catch (Exception e) { } Assert.assertEquals(1, selectCountSameTable()); } /** * @see org.springframework.transaction.annotation.Propagation#NOT_SUPPORTED *

* 测试 NOT_SUPPORTED 机制下内方法抛出异常之后事务的回滚情况 */ @Test() public void test8() { try { photoService.baseTwo(photoBO, Propagation.NOT_SUPPORTED, false, true); } catch (Exception e) { } Assert.assertEquals(2, selectCountSameTable()); } /** * @see org.springframework.transaction.annotation.Propagation#NEVER *

* 测试 NEVER 机制下抛出异常之后事务的回滚情况 *

* 注意当调用 NEVER 机制下的方法时有事务上下文将抛出异常 */ @Test() public void test9() { try { photoService.baseTwo(photoBO, Propagation.NEVER, false, false); } catch (Exception e) { } Assert.assertEquals(1, selectCountSameTable()); } /** * @see org.springframework.transaction.annotation.Propagation#NEVER *

* 测试 NEVER 机制下抛出异常之后事务的回滚情况 *

* 注意当调用 NEVER 机制下的方法时有事务上下文将抛出异常 */ @Test() public void test10() { try { photoService.testNever(photoBO, true); } catch (Exception e) { } Assert.assertEquals(1, selectCountSameTable()); } /** * @see org.springframework.transaction.annotation.Propagation#MANDATORY *

* 测试 MANDATORY 机制下外方法抛出异常之后事务的回滚情况 *

* 注意当调用 MANDATORY 机制下的方法时没有事务上下文将抛出异常 */ @Test() public void test11() { try { photoService.baseTwo(photoBO, Propagation.MANDATORY, true, false); } catch (Exception e) { } Assert.assertEquals(0, selectCountSameTable()); } /** * @see org.springframework.transaction.annotation.Propagation#MANDATORY *

* 测试 MANDATORY 机制下内方法抛出异常之后事务的回滚情况 *

* 注意当调用 MANDATORY 机制下的方法时没有事务上下文将抛出异常 */ @Test() public void test12() { try { photoService.baseTwo(photoBO, Propagation.MANDATORY, false, true); } catch (Exception e) { } Assert.assertEquals(0, selectCountSameTable()); } /** * @see org.springframework.transaction.annotation.Propagation#MANDATORY *

* 测试 MANDATORY 机制下抛出异常之后事务的回滚情况 *

* 注意当调用 MANDATORY 机制下的方法时没有事务上下文将抛出异常 */ @Test() public void test13() { try { photoService.testMandatory(photoBO, false); } catch (Exception e) { } Assert.assertEquals(0, selectCountSameTable()); } /** * @see org.springframework.transaction.annotation.Propagation#NESTED *

* 测试 NESTED 机制下外方法抛出异常之后事务的回滚情况 */ @Test() public void test14() { try { photoService.baseTwo(photoBO, Propagation.NESTED, true, false); } catch (Exception e) { } Assert.assertEquals(0, selectCountSameTable()); } /** * @see org.springframework.transaction.annotation.Propagation#NESTED *

* 测试 NESTED 机制下内方法抛出异常之后事务的回滚情况 */ @Test() public void test15() { try { photoService.baseTwo(photoBO, Propagation.NESTED, false, true); } catch (Exception e) { } Assert.assertEquals(1, selectCountSameTable()); } /** * 有了上面的单数据源,单事务管理器的经验,我们再来看下多数据源,多事务管理器,不同数据源对应不同事务管理器情况下事务的机制 *

* 首先看下多数据源,多事务管理器的情况 * * @see Propagation#REQUIRED */ @Test public void test16() { try { photoService.baseOne(photoBO, Propagation.REQUIRED, true, false); } catch (Exception e) { } int[] result = {0, 1}; Assert.assertArrayEquals(result, selectCountDifferentTable()); } /** * @see Propagation#REQUIRED */ @Test public void test17() { try { photoService.baseOne(photoBO, Propagation.REQUIRED, false, true); } catch (Exception e) { } int[] result = {1, 0}; Assert.assertArrayEquals(result, selectCountDifferentTable()); } /** * @see Propagation#REQUIRES_NEW */ @Test public void test18() { try { photoService.baseOne(photoBO, Propagation.REQUIRES_NEW, true, false); } catch (Exception e) { } int[] result = {0, 1}; Assert.assertArrayEquals(result, selectCountDifferentTable()); } /** * @see Propagation#REQUIRES_NEW */ @Test public void test19() { try { photoService.baseOne(photoBO, Propagation.REQUIRES_NEW, false, true); } catch (Exception e) { } int[] result = {1, 0}; Assert.assertArrayEquals(result, selectCountDifferentTable()); } /** * @see Propagation#SUPPORTS */ @Test public void test20() { try { photoService.baseOne(photoBO, Propagation.SUPPORTS, true, false); } catch (Exception e) { } int[] result = {0, 1}; Assert.assertArrayEquals(result, selectCountDifferentTable()); } /** * @see Propagation#SUPPORTS */ @Test public void test21() { try { photoService.baseOne(photoBO, Propagation.SUPPORTS, false, true); } catch (Exception e) { } int[] result = {1, 1}; Assert.assertArrayEquals(result, selectCountDifferentTable()); } /** * @see Propagation#NOT_SUPPORTED */ @Test public void test22() { try { photoService.baseOne(photoBO, Propagation.NOT_SUPPORTED, true, false); } catch (Exception e) { } int[] result = {0, 1}; Assert.assertArrayEquals(result, selectCountDifferentTable()); } /** * @see Propagation#NOT_SUPPORTED */ @Test public void test23() { try { photoService.baseOne(photoBO, Propagation.NOT_SUPPORTED, false, true); } catch (Exception e) { } int[] result = {1, 1}; Assert.assertArrayEquals(result, selectCountDifferentTable()); } /** * @see Propagation#NEVER */ @Test public void test24() { try { photoService.baseOne(photoBO, Propagation.NEVER, true, false); } catch (Exception e) { } int[] result = {0, 1}; Assert.assertArrayEquals(result, selectCountDifferentTable()); } /** * @see Propagation#NEVER */ @Test public void test25() { try { photoService.baseOne(photoBO, Propagation.NEVER, false, true); } catch (Exception e) { } int[] result = {1, 1}; Assert.assertArrayEquals(result, selectCountDifferentTable()); } /** * @see Propagation#MANDATORY */ @Test public void test26() { try { photoService.baseOne(photoBO, Propagation.MANDATORY, true, false); } catch (Exception e) { } int[] result = {0, 0}; Assert.assertArrayEquals(result, selectCountDifferentTable()); } /** * @see Propagation#MANDATORY */ @Test public void test27() { try { photoService.baseOne(photoBO, Propagation.MANDATORY, false, true); } catch (Exception e) { } int[] result = {1, 0}; Assert.assertArrayEquals(result, selectCountDifferentTable()); } /** * @see Propagation#NESTED */ @Test public void test28() { try { photoService.baseOne(photoBO, Propagation.NESTED, true, false); } catch (Exception e) { } int[] result = {0, 1}; Assert.assertArrayEquals(result, selectCountDifferentTable()); } /** * @see Propagation#NESTED */ @Test public void test29() { try { photoService.baseOne(photoBO, Propagation.NESTED, false, true); } catch (Exception e) { } int[] result = {1, 0}; Assert.assertArrayEquals(result, selectCountDifferentTable()); } /** * 通过上面的测试,现在我们知道了Spring中不同的事务管理器之间不会遵循原本的事务传播机制 *

* 下面我们再来看下不同数据源对应的不同事务管理器的情况 *

* 通过下面的测试可以得出结论:不同数据源的事务管理器不会对当前数据源上的操作产生影响 */ @Test public void test30() { try { photoService.differentDataSourceDifferentTransactionManager(photoBO, true); } catch (Exception e) { } Assert.assertEquals(1, selectCountSameTable()); } private int selectCountSameTable() { return photoMapperTwo.selectCount(null); } private int[] selectCountDifferentTable() { int[] result = new int[2]; result[0] = photoMapperOne.selectCount(null); result[1] = photoMapperTwo.selectCount(null); return result; } }

你可能感兴趣的:(Spring事务传播机制实战)