1、事务里面不要进行远程RPC调用
首先事务里面进行远程的接口调用,如果不采用分布式事务框架,本身就会存在事务不一致的情况,无法进行数据的回滚操作,并发情况下远程服务响应不及时,会出现接口返回不一致问题,当然必须采用异步调用
2、编程型事务更加灵活
声明式事务只需要加在方法头加@Transactional注解即可开启事务,但是还是不太灵活,意味着整个方法所进行对数据库操作都要加进事务,当然一次查询也要进入事务,这并不是我们想要的,我们在update、insert操作上进行事务操作,方便进行回滚。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public Boolean transactionCommit(String userName) { SysUser sysUser = userMapper.selectUserByUserName(userName,null);
transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { try { if (null != sysUser) { userMapper.updateStatus(userName); } } catch (Exception e){ transactionStatus.setRollbackOnly(); } } }); SysUser sysUser1 = userMapper.selectUserByUserName(userName,"1"); /log/.info("状态为1的用户信息"+JSON./toJSONString/(sysUser1)); return true; }
|
编程式事务的灵活点在于可以控制事务执行方法,运用transactionTemplate类进行事务操作,查询操作可以写在外面,这样查询获取数据的操作就不会进入mysql事务表。
3、数据分批处理
对于事务的更新或者插入,前端可能会有批量操作,大规模数据的批量更新、插入也会对事务接口产生影响,一旦其中有更新或插入失败,为了保证事务的一致性,整个操作都要进行回滚;
- 前端:可以限制数据,对后端接口的访问,可以将数据进行分页,多次请求,可以避免事务提交大量数据。
- 后端:也可以去数据进行分页处理,例如每次可以限制50条进行操作,如果是新增逻辑,使用Mybatis的批量更新大大提升效率
1
| List<List<ReceivableFeeSaveDTO>> partition = Lists.partition(receivableFeeSaveDTOList, 50);
|
4、大事务拆分小事务
可以将一个事务接口,拆分成多个事务接口,并且每个事务接口只做一件事,比如上面的收款单生成接口,金额回写、第三方接口调用、调用后的结果回写都可以抽成一个哥小事务接口。
5、异步并行处理
重中之重,事务里如果无法避免远程调用,那么肯定是需要进行异步调用,因为无法保证远程接口的及时响应性,CompletableFuture异步编排特性可以用到,task1和task2任务结束后,执行task3。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| CompletableFuture<Object> task1 =CompletableFuture.supplyAsync(() -> { System.out.println("单号check线程" + Thread.currentThread().getId());
return "账单实体信息"; }, executor); CompletableFuture<Object> task2 = CompletableFuture.supplyAsync(() -> { System.out.println("收款单生成线程" + Thread.currentThread().getId()); try {
return “账单编号”; Thread.sleep(3000); System.out.println("任务2结束:"); } catch (InterruptedException e) { e.printStackTrace(); }
}, executor);
CompletableFuture<Boolean> future = task1.thenCombineAsync(task2, (t1, t2) -> {
System.out.println("账单金额回写线程" + Thread.currentThread().getId());
return ture; }, executor);
|