TransactionTemplate transactionTemplate;
ExecutorService executorService = Executors.newFixedThreadPool(4);
SessionFactory sessionFactory = ZsCoreEnvironment.getService(SessionFactory.class);
OpenSessionInterceptor openSessionInterceptor = new OpenSessionInterceptor();
openSessionInterceptor.setSessionFactory(sessionFactory);
List<CompletableFuture<Void>> futures = ListUtils.partition(applies, 40).stream().map(apps -> CompletableFuture.runAsync(() -> {
for (long c : apps) {
Assert.isTrue(!TransactionSynchronizationManager.hasResource(sessionFactory), "不是新线程");
try {
openSessionInterceptor.invoke(new SimpleMethodInvocation() {
@Override
public Object proceed() {
transactionTemplate.executeWithoutResult(transactionStatus -> {
try {
Session session = ZsCoreEnvironment.getCurrentSession();
Apply apply = session.get(Apply.class, c);
if (apply != null) {
FlowInstance flowInstance = apply.getFlowInstance();
if (flowInstance != null) {
flowInstance.removeItCascade(Void.class);
} else {
apply.removeItCascade();
}
}
} catch (Exception e) {
transactionStatus.setRollbackOnly();
logger.error("删除错误", e);
}
});
return null;
}
});
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}, executorService)).toList();
try {
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(30, TimeUnit.MINUTES);
} catch (Exception e) {
throw new RuntimeException(e);
}
思路大概是以下所列:
- 通过Executors设置本次并发操作所用的线程模式和数量
- 通过org.apache.commons.collections4.ListUtils把一个待处理的集合拆分成特定大小的部份
- 创建CompletableFuture#runAsync 异步可返回Future实例并归集为CompletableFuture#allOf表示等待所有工作结束,你也可以根据需求换成无需返回模式Runnable方式
- 通过OpenSessionInterceptor拦截器打开一个Hibernate Session会话并绑定到当前事务同步管理器TransactionSynchronizationManager的上下文中
- 通过事务模板类TransactionTemplate 启动事务,事务粒度大小可通过逻辑控制,例子是以每一个清除(包含十几条SQL)操作一个事务,你可以多个操作一个事务,但经验法则删除事务不能包含过多
- 根据执行业务逻辑 ,控制事务提交还是回滚,这里不抛异常则正常提交
下面分析下OpenSessionInterceptor
public Object invoke(MethodInvocation invocation) throws Throwable {
SessionFactory sf = getSessionFactory();
Assert.state(sf != null, "No SessionFactory set");
if (!TransactionSynchronizationManager.hasResource(sf)) {
// New Session to be bound for the current method's scope...
Session session = openSession(sf);
try {
TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session));
return invocation.proceed();
}
finally {
SessionFactoryUtils.closeSession(session);
TransactionSynchronizationManager.unbindResource(sf);
}
}
else {
// Pre-bound Session found -> simply proceed.
return invocation.proceed();
}
}
Spring事务管理器TransactionTemplate实际是HibernateTransactionManager需要在上下文中通过TransactionSynchronizationManager获取当前会话getCurrentSession创建并管理事务,所在在TransactionTemplate启动事务前必须绑定SessionHolder 通过TransactionSynchronizationManager#bindResource,最终TransactionTemplate实例负责提交事务或回滚,OenSessionInterceptor关闭session和取消当前线程unbindResource资源