1. 程式人生 > >Junit4 spring註解事務不會滾問題

Junit4 spring註解事務不會滾問題

前言

  這事兒吧,機緣巧合。我的專案是用springboot搭建的,junit用的4.12。最近在進行RabbitMQ相關功能的測試,打算測下nginx對訊息佇列的負載和叢集本身的可用,想著,如果client呼叫失敗了,就把插入的資料回滾掉,於是就配置了註解事務,然後,坑就出現了。

狀態介紹

  註解的配置如下,很常規:

    <!-- (事務管理)transaction manager, use JtaTransactionManager for global tx -->
    <bean id="transactionManager"
          class
="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" /> </bean> <!-- enable transaction annotation support --> <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="false"
/>

  測試類大概如下:

/**
 * @author nature
 * @create 2018-01-09 14:35
 */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = TestApplication.class)
public class MessageQueueDaoTest {

    @Test
    @Transactional
    //@Rollback(false)
    public void testTransaction(){
        //FblockContext.getBean(TransactionTest.class).test();//FblockContext是我自己封裝的spring上下文,這個getBean就是spring的,TransactionTest類原始碼在後面
MessageQueueDao messageQueueDao= FblockContext.getBean(MessageQueueDao.class); RabbitMQRecord record=new RabbitMQRecord(); record.setId(KeyWorker.nextId()); record.setRecordType(0); record.setRemark("testTransaction單元測試"); messageQueueDao.insertRabbitMQRecord(record); throw new MessageQueueTestException("異常出現,需要回滾。"); } } /** * @author nature * @create 2018-01-10 12:52 */ @Component public class TransactionTest { @Transactional public void test(){ MessageQueueDao messageQueueDao= FblockContext.getBean(MessageQueueDao.class); RabbitMQRecord record=new RabbitMQRecord(); record.setId(KeyWorker.nextId()); record.setRecordType(0); record.setRemark("testTransaction單元測試"); messageQueueDao.insertRabbitMQRecord(record); throw new MessageQueueTestException("異常出現,需要回滾。"); } }

問題描述

  上述程式碼其實就是我最初的程式碼,在測試方法類上打了@Transactional,內部丟擲異常,然後期望回滾。結果也如我所願,確實資料庫裡沒插進去。然後,我說試試不丟擲異常的,能不能插進去吧。結果也沒插進去。。。。見了鬼了。查了半天,我一直以為是我的事務配置不對,於是我寫了TransactionTest類,結果表現都是正常的,有異常回滾,無異常不會滾。機緣巧合,讓我帶了junit關鍵字去查詢,找到了罪魁禍首。
  在junit中有個註解是@Rollback,這個,預設是true,也就是,只要是我配置了註解,就會回滾,不管有沒有異常。這個註解可以設定成false,@Rollback(false),那就變成了不管有沒有異常都不會滾——蛋好疼。於是做了下面一組測試,具體探明下具體的規則吧,畢竟在做測試,沒時間根原始碼了,前面說了在MessageQueueDaoTest內操作資料庫的情況,其實如果MessageQueueDaoTest不配置事務,TransactionTest裡面打事務註解,就是我們期待的結果了,為了探明規則,測過的接下來就不試了,接下來的資料庫操作都在,TransactionTest內,MessageQueueDaoTest通過獲取bean獲取例項。

測試

  
* MessageQueueDaoTest有事務註解,TransactionTest有事務註解,無異常,這個結果是回滾的,那有有異常的我們不試了,肯定也回滾。
* MessageQueueDaoTest有事務註解,TransactionTest無事務註解,無異常,這個結果也是回滾的,有異常的也就不試了,肯定也回滾。
  只要外面異常,裡面都回滾,那我們試試@Rollback(false)的呢。
* MessageQueueDaoTest有事務註解,@Rollback(false),TransactionTest有事務註解,無異常,不會滾
* MessageQueueDaoTest有事務註解,@Rollback(false),TransactionTest有事務註解,有異常,回滾了。但是,按照Rollback的尿性,應該不會滾呀。於是推測,在裡面有事務註解,按照自己的規則,攔截了異常回滾了,沒有輪到Rollback生效。為了證實我們的猜測,我們把異常挪到MessageQueueDaoTest中去丟擲
* MessageQueueDaoTest有事務註解,@Rollback(false),TransactionTest有事務註解,MessageQueueDaoTest拋異常 ,沒有回滾,與我們的猜測一致

結論

  junit4的測試類中打事務註解,預設會按照@Rollback(true)來進行處理,無論如何都會回滾,裡面呼叫的方法打不打事務註解已經不重要了。而@Rollback(false)之後,似乎,也只控制在該層方法中出現的異常,就好像是這一層沒有打事務似的,而不會傳播到巢狀的事務內。根據上面的推測,我懷疑@Rollback(true)時想要提交,裡面的傳播級別就必須變成會新開事務的,這個,我這次就不證實了。
  此篇部落格,今證明,在下填過此坑了。。。。好了,下一個