> 文章列表 > 如何避免大事务问题

如何避免大事务问题

如何避免大事务问题

引言

原文:
让人头痛的大事务问题到底要如何解决?
读书笔记:担心大佬文章搬家,故整理此学习笔记


大事务可以引发的问题

如何避免大事务问题


1. 少用@Transactional注解

  • 原因:
  • @Transactional注解是通过spring的aop起作用的,使用不当,事务功能可能会失效。
  • @Transactional注解一般加在某个业务方法上,会导致整个业务方法都在同一个事务中,粒度太粗,不好控制事务范围,是出现大事务问题的最常见的原因。
  • 方案 改用声明式事务
    @Transactionalpublic void add(UserModel userModel) throws Exception {query1();query2();query3();roleService.save(userModel);update(userModel);}
   public void save(final User user) {queryData1();queryData2();transactionTemplate.execute((status) => {addData1();updateData2();return Boolean.TRUE;})}

2. 将查询(select)方法放到事务外

非事务内必须操作挪出去,典型就是查询操作

3. 事务中避免远程调用

由于网络不稳定,这种远程调的响应时间可能比较长,如果远程调用的代码放在某个事物中,这个事物就可能是大事务。当然,远程调用不仅仅是指调用接口,还有包括:发MQ消息,或者连接redismongodb保存数据等。

远程调用的代码不放在事务中如何保证数据一致性呢?
这就需要建立:重试+补偿机制,达到数据最终一致性了。

4. 事务中避免一次性处理太多数据

如果一个事务中需要处理的数据太多,也会造成大事务问题。比如为了操作方便,你可能会一次批量更新1000条数据,这样会导致大量数据锁等待,特别在高并发的系统中问题尤为明显。

解决办法是分页处理,1000条数据,分50页,一次只处理20条数据,这样可以大大减少大事务的出现。

5. 非事务执行

业务拆分,非必须放在一个事务里的save方法就不要放到一个事务里;

   public void save(final User user) {transactionTemplate.execute((status) => {addData();           return Boolean.TRUE;})addLog();updateCount();}

addLog增加操作日志方法 和 updateCount更新统计数量方法,是可以不在事务中执行的,因为操作日志和统计数量这种业务允许少量数据不一致的情况。

6. 异步处理

   @Autowiredprivate TransactionTemplate transactionTemplate;...public void save(final User user) {transactionTemplate.execute((status) => {order(); // 下订单return Boolean.TRUE;})sendMq(); // 发货}

order方法用于下单,delivery方法用于发货,是不是下单后就一定要马上发货呢?

答案是否定的。

这里发货功能其实可以走mq异步处理逻辑。