比如有100条数据要处理,每条数据可能插入N个表。
现状:service开事务,出错回滚,也就说,前99条成功了,最后一条失败了,全都回滚了。
目标:每条数据开一个事务,失败了只回滚自己,其他数据该成功还成功。
大概代码:
AAAService: @Transactional public void excute(String start, String folder) {
// 不要随便抓异常,异常不抛出去,事务不会回滚 //读取订单数据,每次处理一个订单 List<OldOrderData> orderList = readInfo(start, folder); for (OldOrderData order : orderList) { try { saveDataService.syncSingleOrder(order); } catch (Exception e) { e.printStackTrace(); System.out.print("error:" + order.getMains().getOrderno()); } }
}
BBBService: @Transactional(propagation=Propagation.REQUIRES_NEW) public void syncSingleOrder(OldOrderData oldOrder) { ....//有异常往出抛,别catch住 }
执行时日志: ... Suspending current transaction, creating new transaction with name ---成功了会提交Committing JDBC transaction on Connection Resuming suspended transaction after completion of inner transaction Suspending current transaction, creating new transaction with name ---失败了会回滚Rolling back JDBC transaction on Connection ...
要点: (1)事务传播应该使用propagation=Propagation.REQUIRES_NEW,而不是Nested那个。 new的话,每个是独立的事务,可以自己提交回滚。 nested的,得外层控制提交回滚,具体没试验。
(2)处理每个数据的方法,要放到另外一个类里面。 如果两个方法在一个java类里,事务传播被忽略,根本不生效。spring这么设计的。
(3)方法得是public的,非public的事务也不生效。spring这么设计的。
(4)处理每个数据的方法里,不要catch异常,尽管让它出错,这样事务才会回滚。 外层可以catch每个数据的处理,抓异常,然后写日志,发信提醒等等。 这样,出错的数据不影响大局。
参考: https://www.credera.com/blog/technology-insights/java/common-oversights-utilizing-nested-transactions-spring/
|