1.大事务:
总体任务对应的事务运行时间比较长,长时间未提交的事务。
2.大事务的危害:
a.并发情况下,数据库连接池资源占满。大事务提交不及时,导致连接资源释放缓慢。
b.数据库死锁和锁等待。mysql innodb存储引擎背景下,事务如果占用了排他锁,会容易导致并发情况下数据死锁或者锁等待。
c.大事务Rt时间长,容易导致接口超时。
d.大事务回滚时间长。
e.数据库主从架构下,数据同步延迟
3.解决办法
3.1 将声明式事务的@Transactional方式 合理的替换为 编程式事务TransactionTemplate 的方式
声明式事务的粒度最小是整个方法,可能会导致业务里不必要的逻辑都加了事务。编程式事务细化需要加事务的逻辑上,形成实际有用的事务块。
@Autowired
private TransactionTemplate transactionTemplate;public void testTransaction() {transactionTemplate.execute(new TransactionCallbackWithoutResult() {@Overrideprotected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {try {// .... 业务代码} catch (Exception e){//回滚transactionStatus.setRollbackOnly();}}});
}
3.2 将查询放在事务方法外
使用@Transactional 又想避免产生大事务,需对方法进行拆分,将不需要事务管理的逻辑与事务操作分开
@Service
public class TransactionTestService{// 避免同一个类内部方法相互调用,实例方法调用代理方法而导致事务失效@Resourceprivate TransactionTestService service;public void create(ParamDto dto){queryData1();queryData2();service.save(dto);}//事务操作@Transactional(rollbackFor = Exception.class)public void save(ParamDto dto){paramDao.insert(dto);}
}
3.3 避免跨服务间的远程调用
服务间的通讯及服务之间的调用时间 受网络环境和远端接口Rt时间的影响,可能会比较耗时。
反例://事务操作@Transactional(rollbackFor = Exception.class)public void save(ParamDto dto){// 调用了其他服务otherRemoteApi();paramDao.insert(dto);}修改为:@Autowiredprivate TransactionTemplate transactionTemplate;public void save(ParamDto dto){// 调用了其他服务otherRemoteApi();transactionTemplate.execute(new TransactionCallbackWithoutResult() {@Overrideprotected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {try {paramDao.insert(dto);} catch (Exception e){//回滚transactionStatus.setRollbackOnly();}}});}
3.4 事务中不应该一次性处理太多的数据,可以使用分批执行
3.5事务中的方法可以根据业务使用异步执行