前言
在我们日常开发的过程中,如果无脑的使用长事务(运行时间长,长时间未提交的事务,都可以称之为长事务),引发如下的一些危害:
- 数据库连接池被占满,应用无法获取连接资源
- 容易引发数据库死锁
- 数据库回滚时间长
综上,合理的对事务进行拆分,尽量让事务变小,变快,减小事务的颗粒度显得尤为重要;如下,提供三种常见的解决方案;
1、编程式事务
基于底层的API,开发者在代码中手动的管理事务的开启、提交、回滚等操作。在spring项目中我们可以使用TransactionTemplate类的对象,手动控制事务。
@Autowired
private TransactionTemplate transactionTemplate;
...
public void save(ArtisanDto artisanDto) {
transactionTemplate.execute(transactionStatus -> {
artisanDao.save(artisanDto);
//....
// .....
return Boolean.TRUE;
});
}
使用编程式事务最大的好处就是可以精细化控制事务范围, 所以避免长事务最简单的方法就是不要使用声明式事务@Transactional,而是使用编程式事务手动控制事务范围。
2、手动管理事务
有些情况下,可能需要手动控制事务的开始、提交和回滚等操作。可以通过注入 PlatformTransactionManager
依赖来手动管理事务。
@Autowired
private PlatformTransactionManager transactionManager;
public void longTransactionMethod() {
TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
try {
// 长事务的处理逻辑
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
throw e;
}
}
3、方法拆分
使用@Transactional 又想避免产生长事务,建议对我们的方法进行拆分,将不需要事务管理的逻辑与事务操作分开。
@Service
public class ArtisanService{
public void create(ArtisanDto dto){
queryData();
biz();
save(dto);
}
//事务操作
@Transactional(rollbackFor = Throwable.class)
public void save(ArtisanDto dto){
artisanDao.insert(dto);
}
}
queryData()与biz()不需要事务,我们将其与事务方法save()拆开.