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)時想要提交,裡面的傳播級別就必須變成會新開事務的,這個,我這次就不證實了。
此篇部落格,今證明,在下填過此坑了。。。。好了,下一個