场景
有时候我们需要在事务提交后处理一个Task,这个Task又要依赖事务提交的结果,这时候会使用到TransactionSynchronizationManager。
这里我是简单封装了一个工具类:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/****
- 事物后置处理
*/
public class TransactionSyncManagerUtil {
<span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">private</span></span> <span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">static</span></span> <span data-slate-leaf="true"><span class="token class-name" data-slate-string="true">ExecutorService</span></span><span data-slate-leaf="true"><span data-slate-string="true"> executorService </span></span><span data-slate-leaf="true"><span class="token operator" data-slate-string="true">=</span></span> <span data-slate-leaf="true"><span class="token class-name" data-slate-string="true">Executors</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">.</span></span><span data-slate-leaf="true"><span class="token function" data-slate-string="true">newFixedThreadPool</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">(</span></span><span data-slate-leaf="true"><span class="token number" data-slate-string="true">20</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">)</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">;</span></span>
<span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">public</span></span> <span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">static</span></span> <span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">void</span></span> <span data-slate-leaf="true"><span class="token function" data-slate-string="true">registerSynchronization</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">(</span></span><span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">final</span></span> <span data-slate-leaf="true"><span class="token class-name" data-slate-string="true">Runnable</span></span><span data-slate-leaf="true"><span data-slate-string="true"> task</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">)</span></span> <span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">{</span></span>
<span data-slate-leaf="true"><span class="token class-name" data-slate-string="true">TransactionSynchronizationManager</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">.</span></span><span data-slate-leaf="true"><span class="token function" data-slate-string="true">registerSynchronization</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">(</span></span><span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">new</span></span> <span data-slate-leaf="true"><span class="token class-name" data-slate-string="true">TransactionSynchronizationAdapter</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">(</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">)</span></span> <span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">{</span></span>
<span data-slate-leaf="true"><span data-slate-string="true">@Override</span></span>
<span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">public</span></span> <span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">void</span></span> <span data-slate-leaf="true"><span class="token function" data-slate-string="true">afterCommit</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">(</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">)</span></span> <span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">{</span></span><span data-slate-leaf="true"><span data-slate-string="true">
executorService</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">.</span></span><span data-slate-leaf="true"><span class="token function" data-slate-string="true">execute</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">(</span></span><span data-slate-leaf="true"><span data-slate-string="true">task</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">)</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">;</span></span>
<span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">}</span></span>
<span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">}</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">)</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">;</span></span>
<span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">}</span></span>
}
具体使用示例如下:
@Transactional
public void fun() {
// 数据库的一系列操作
// ...
// 事务提交后任务
TransactionSyncManagerUtil.registerSynchronization(new Runnable() {
@Override
public void run() {
// 后置处理
}
});
}
问题
然后在对方法编写单测的时候遇到报错如下:
java.lang.IllegalStateException: Transaction synchronization is not active
解决方案
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.core.NamedThreadLocal;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
public class XXXServiceTest {
<span data-slate-leaf="true"><span class="token operator" data-slate-string="true">@InjectMocks</span></span>
<span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">private</span></span> <span data-slate-leaf="true"><span class="token class-name" data-slate-string="true">XXXService</span></span><span data-slate-leaf="true"><span class="token class-name" data-slate-string="true"> xxxService</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">;</span></span>
<span data-slate-leaf="true"><span class="token string" data-slate-string="true">@Mock</span></span>
<span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">private</span></span> <span data-slate-leaf="true"><span class="token class-name" data-slate-string="true">TransactionSynchronization</span></span><span data-slate-leaf="true"><span class="token keyword" data-slate-string="true"> transactionSynchronization</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">;</span></span>
<span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">private</span></span> <span data-slate-leaf="true"><span class="token class-name" data-slate-string="true">Set</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true"><TransactionSynchronization></span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true"> synchronizationSet </span></span><span data-slate-leaf="true"><span class="token operator" data-slate-string="true">=</span></span> <span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">new</span></span> <span data-slate-leaf="true"><span class="token class-name" data-slate-string="true">HashSet</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true"><></span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">(</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">)</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">;</span></span>
<span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">private</span></span> <span data-slate-leaf="true"><span class="token class-name" data-slate-string="true">ThreadLocal</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true"><Set<TransactionSynchronization>></span></span><span data-slate-leaf="true"><span class="token keyword" data-slate-string="true"> synchronizations
</span></span><span data-slate-leaf="true"><span class="token operator" data-slate-string="true">=</span></span> <span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">new</span></span> <span data-slate-leaf="true"><span class="token class-name" data-slate-string="true">NamedThreadLocal</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true"><></span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">(</span></span><span data-slate-leaf="true"><span class="token string" data-slate-string="true">"Transaction synchronizations"</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">)</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">;</span></span>
@Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
<span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">this</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">.</span></span><span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">synchronizationSet</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">.</span></span><span data-slate-leaf="true"><span class="token function" data-slate-string="true">add</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">(</span></span><span data-slate-leaf="true"><span class="token function" data-slate-string="true">transactionSynchronization</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">)</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">;</span></span>
<span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">this</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">.</span></span><span data-slate-leaf="true"><span class="token class-name" data-slate-string="true">synchronizations</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">.</span></span><span data-slate-leaf="true"><span class="token function" data-slate-string="true">set</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">(</span></span><span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">synchronizationSet</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">)</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">;</span></span>
<span data-slate-leaf="true"><span class="token function" data-slate-string="true">setFinalStatic</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">(</span></span><span data-slate-leaf="true"><span class="token class-name" data-slate-string="true">TransactionSynchronizationManager</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">.</span></span><span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">class</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">.</span></span><span data-slate-leaf="true"><span class="token function" data-slate-string="true">getDeclaredField</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">(</span></span><span data-slate-leaf="true"><span class="token string" data-slate-string="true">"synchronizations"</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">)</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">,</span></span><span data-slate-leaf="true"><span class="token operator" data-slate-string="true"> synchronizations</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">)</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">;</span></span>
<span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">}</span></span>
<span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">static</span></span> <span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">void</span></span> <span data-slate-leaf="true"><span class="token function" data-slate-string="true">setFinalStatic</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">(</span></span><span data-slate-leaf="true"><span class="token class-name" data-slate-string="true">Field</span></span><span data-slate-leaf="true"><span class="token function" data-slate-string="true"> field</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">,</span></span> <span data-slate-leaf="true"><span class="token class-name" data-slate-string="true">Object</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true"> newValue</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">)</span></span> <span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">throws</span></span> <span data-slate-leaf="true"><span class="token class-name" data-slate-string="true">Exception</span></span> <span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">{</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">
field</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">.</span></span><span data-slate-leaf="true"><span class="token function" data-slate-string="true">setAccessible</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">(</span></span><span data-slate-leaf="true"><span class="token boolean" data-slate-string="true">true</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">)</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">;</span></span>
<span data-slate-leaf="true"><span class="token class-name" data-slate-string="true">Field</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true"> modifiersField </span></span><span data-slate-leaf="true"><span class="token operator" data-slate-string="true">=</span></span> <span data-slate-leaf="true"><span class="token class-name" data-slate-string="true">Field</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">.</span></span><span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">class</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">.</span></span><span data-slate-leaf="true"><span class="token function" data-slate-string="true">getDeclaredField</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">(</span></span><span data-slate-leaf="true"><span class="token string" data-slate-string="true">"modifiers"</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">)</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">;</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">
modifiersField</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">.</span></span><span data-slate-leaf="true"><span class="token function" data-slate-string="true">setAccessible</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">(</span></span><span data-slate-leaf="true"><span class="token boolean" data-slate-string="true">true</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">)</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">;</span></span><span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">
modifiersField</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">.</span></span><span data-slate-leaf="true"><span class="token function" data-slate-string="true">setInt</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">(</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">field</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">,</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true"> field</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">.</span></span><span data-slate-leaf="true"><span class="token function" data-slate-string="true">getModifiers</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">(</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">)</span></span> <span data-slate-leaf="true"><span class="token operator" data-slate-string="true">&</span></span> <span data-slate-leaf="true"><span class="token operator" data-slate-string="true">~</span></span><span data-slate-leaf="true"><span class="token class-name" data-slate-string="true">Modifier</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">.</span></span><span data-slate-leaf="true"><span data-slate-string="true">FINAL</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">)</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">;</span></span><span data-slate-leaf="true"><span data-slate-string="true">
field</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">.</span></span><span data-slate-leaf="true"><span class="token function" data-slate-string="true">set</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">(</span></span><span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">null</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">,</span></span><span data-slate-leaf="true"><span data-slate-string="true"> newValue</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">)</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">;</span></span>
<span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">}</span></span>
<span data-slate-leaf="true"><span data-slate-string="true">@Test</span></span>
<span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">public</span></span> <span data-slate-leaf="true"><span class="token keyword" data-slate-string="true">void</span></span> <span data-slate-leaf="true"><span class="token function" data-slate-string="true">testFun</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">(</span></span><span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">)</span></span> <span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">{</span></span>
<span data-slate-leaf="true"><span class="token comment" data-slate-string="true">// 单元测试编写</span></span>
<span data-slate-leaf="true"><span class="token punctuation" data-slate-string="true">}</span></span>
}