事务回滚原理
源码分析
在前文单测类注入中我们知道.JUnit提供了一些监听器,允许
当单测方法执行时候去对单测上下文进行调整。所以呢事务回滚也是基于
这里的特性完成的。

源码分析
Spring中为了适配不通的数据库,提供了事务平台的概念。 PlatformTransactionManager 只要实现了该接口
就允许对事务进行控制。具体事务的控制是通过工具类来处理的。 TransactionContextHolder 可以获取当前线程
执行的事务上下文。JUnit通过该工具拿到事务的上下文,然后对此做响应的修改。具体的
修改逻辑见下文注释。两句话解释清楚。
TransactionalTestExecutionListener
伪代码分析
java
1 // 单测方法执行前,移除容器原来的事务管理器,然后开启一个新的事务
2 @Override
3 public void beforeTestMethod(final TestContext testContext) throws Exception {
4 Method testMethod = testContext.getTestMethod();
5 Class<?> testClass = testContext.getTestClass();
6 Assert.notNull(testMethod, "Test method of supplied TestContext must not be null");
7
8 TransactionContext txContext = TransactionContextHolder.removeCurrentTransactionContext();
9 Assert.state(txContext == null, "Cannot start new transaction without ending existing transaction");
10
11 PlatformTransactionManager tm = null;
12 TransactionAttribute transactionAttribute = this.attributeSource.getTransactionAttribute(testMethod, testClass);
13
14 if (transactionAttribute != null) {
15 transactionAttribute = TestContextTransactionUtils.createDelegatingTransactionAttribute(testContext,
16 transactionAttribute);
17
18 if (logger.isDebugEnabled()) {
19 logger.debug("Explicit transaction definition [" + transactionAttribute +
20 "] found for test context " + testContext);
21 }
22
23 if (transactionAttribute.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
24 return;
25 }
26
27 tm = getTransactionManager(testContext, transactionAttribute.getQualifier());
28 Assert.state(tm != null,
29 () -> "Failed to retrieve PlatformTransactionManager for @Transactional test: " + testContext);
30 }
31
32 if (tm != null) {
33 txContext = new TransactionContext(testContext, tm, transactionAttribute, isRollback(testContext));
34 runBeforeTransactionMethods(testContext);
35 txContext.startTransaction();
36 TransactionContextHolder.setCurrentTransactionContext(txContext);
37 }
38 }
39
40 // 单测方法执行结束后,结束事务然后回滚或提交
41 @Override
42 public void afterTestMethod(TestContext testContext) throws Exception {
43 Method testMethod = testContext.getTestMethod();
44 Assert.notNull(testMethod, "The test method of the supplied TestContext must not be null");
45
46 TransactionContext txContext = TransactionContextHolder.removeCurrentTransactionContext();
47 // If there was (or perhaps still is) a transaction...
48 if (txContext != null) {
49 TransactionStatus transactionStatus = txContext.getTransactionStatus();
50 try {
51 // If the transaction is still active...
52 if (transactionStatus != null && !transactionStatus.isCompleted()) {
53 txContext.endTransaction();
54 }
55 }
56 finally {
57 runAfterTransactionMethods(testContext);
58 }
59 }
60 }