同一@Transactional服务中未提交事务时读取未持久化数据的方案问询
问题描述
我的服务包含persistLatitude和findLatitude两个方法:
@Service @Transactional public class myservice1{ void persistLatitude (Long Latitude){ //some code } Long findLatitude (){ //some code }
假设我通过persistLatitude方法将纬度29° 52' N持久化到数据库表中,但该方法还在执行其他任务。由于@Transactional注解的存在,只有当整个方法执行完成后,修改才会提交到数据库。
此时,REST接口收到查询该数据库表中纬度29° 52' N的请求,由于事务因方法未执行完毕尚未提交,findLatitude方法无法查询到该纬度值。
请问有什么办法可以让findLatitude在创建该值的事务未完全完成时,就能检索到这个纬度?
解决方案
以下是几种可行的方案,可根据业务场景选择:
1. 给查询方法设置读未提交隔离级别
给findLatitude方法配置READ_UNCOMMITTED事务隔离级别,允许它读取其他未提交事务中的数据:
@Service public class myservice1{ @Transactional void persistLatitude (Long Latitude){ //some code } @Transactional(isolation = Isolation.READ_UNCOMMITTED) Long findLatitude (){ //some code }
注意:这种方式会引入脏读风险——如果persistLatitude最终回滚,findLatitude读到的就是无效数据,需评估业务是否能接受这种情况。
2. 将持久化逻辑拆分到独立子事务
把保存纬度的代码从主事务中拆分出来,用REQUIRES_NEW传播行为开启独立子事务,这样保存操作完成后立即提交,后续任务不影响这个提交结果:
@Service public class myservice1{ @Transactional void persistLatitude (Long Latitude){ // 调用独立保存方法,开启新事务 saveLatitudeInNewTransaction(Latitude); // 其他耗时任务 } @Transactional(propagation = Propagation.REQUIRES_NEW) private void saveLatitudeInNewTransaction(Long latitude) { // 执行纬度持久化操作 } Long findLatitude (){ //some code }
注意:子事务提交后无法和主事务一起回滚,需确保保存纬度的操作可独立提交,与后续任务无事务一致性要求。
3. 手动控制事务提交时机
借助Spring的TransactionTemplate,在保存纬度后手动提交事务,再执行后续任务:
@Service public class myservice1{ @Autowired private TransactionTemplate transactionTemplate; void persistLatitude (Long Latitude){ // 执行纬度持久化并提交事务 transactionTemplate.execute(status -> { // 保存纬度的代码 status.flush(); status.commit(); return null; }); // 其他不需要事务的耗时任务 } Long findLatitude (){ //some code }
注意:这种方式要确保后续任务不需要在同一个事务中执行,避免破坏事务原子性。
内容的提问来源于stack exchange,提问作者Gestalt
相关产品推荐
相关产品推荐

