首页 > 其他分享 >当@Transactional遇上@synchronized生产问题

当@Transactional遇上@synchronized生产问题

时间:2024-07-20 17:01:06浏览次数:9  
标签:事务 调用 synchronized Transactional public 方法 遇上

近日遇到一个问题,就是一个订单被两个用户抢了问题,排查后发现是由于 @Transactional和@synchronized注解的使用问题

一、问题点:数据重复读

@Transactional注解用于开启事务,当在高并发情况下我们可能为了保证数据的安全使用悲观锁,可以在方法上使用@synchronized使用悲观锁。一个线程执行完方法并释放锁后,事务并未提交,第二个线程又获得了该锁,导致数据出问题

@Transactional注解通过AOP实现事务管理,当标注该注解的方法执行完成后才提交事务,而synchronized代码块又是在一个事务内,就会出现第一个线程释放锁后但是事务还没提交,第二个线程就进入同步代码块获取到未提交的数据库数

@Transactional控制事务的范围比sychronized 大,如图:

思路:既然事务下不能使用锁,那我们把锁和事务进行分开。使得在锁环境下包含事务,最终依然是线程安全的

方法一:将锁替换成数据库的锁比如select for update或者版本号version

方法二:在service下将事务代码的抽取单独使用,无事务方法调用有事务的方法

既然问题出在事务未提交,那么只要把对应事务操作的代码单独抽取出来,封装成一个单独的方法,在synchronized中调用该方法即可

@Service
public class OrderServiceImpl implements OrderServiceI {
	@Autowired
	private OrderDao orderDao;

	public sychronized Order updateOrder(int id) {  //加锁
		return updateOrderSafely(id); //调用数据库
	}

	@Transactional
	public Order updateOrderSafely(int id) {
		return orderDao.updateOrder(id);
	}
}

看起来好像是解决了事务未提交的问题,但会存在新的问题,可能会出现@Transactional事务不生效的情况

二、问题点 >》方法二引申:@Transactional事务不生效

在同一个类内部调用@Transactional标注的方法事务也不会开启,原因是:

@Transactional事务管理是基于动态代理对象的代理逻辑实现的,那么如果在类内部调用类内部的事务方法,这个调用事务方法的过程并不是通过代理对象来调用的,而是直接通过this对象来调用方法,绕过的代理对象,肯定就是没有代理逻辑了

方法:将锁提取到controller层,不包含任何事务

Controller类

 @RestController
 public class TestController {
     @Resource 
     private TestService testService;
     @PostMapping("/test")
     public synchronized void testInterface() {
          testService.functionA(); // 调用数据库操作方法
     }
 }

Service类

 @Service("testService")
 public class TestServiceImpl implements TestService {
    @Transactional(rollbackFor = Exception.class, 
                  propagation = Propagation.REQUIRES_NEW)
     public void functionA() {
         //数据库读写操作
     }
 }

标签:事务,调用,synchronized,Transactional,public,方法,遇上
From: https://blog.csdn.net/qq_36451127/article/details/140489022

相关文章

  • synchronized关键字
    在Java中,关键字synchronized可以保证在同一个时刻,只有一个线程可以执行某个方法或者某个代码块(主要是对方法或者代码块中存在共享数据的操作),同时我们还应该注意到synchronized的另外一个重要的作用,synchronized可保证一个线程的变化(主要是共享数据的变化)被其他线程......
  • @Transactional 中使用线程锁导致了锁失效
     当线程A将level设置为99时,此时锁已经释放了,但是事务还没提交!!线程B此时可以获取到锁并进行查询,查询出来的level还是线程A修改之前的100,所以出现了并发问题。 解决方案1、@Transactional单独一个方法privateLocklock=newReentrantLock();@Transactionalpublicvoid......
  • Synchronized
    Synchronized的表现形式普通同步方法普通同步方法使用 synchronized 关键字修饰,锁对象是当前实例对象(即方法所属对象的实例)。publicsynchronizedvoidmethod(){//锁对象是当前实例对象}静态同步方法静态同步方法使用 synchronized 关键字修饰,锁对象是当前......
  • [ABC339D]Synchronized Players
    题目大意给定一个N*N的地图,地图中#表示不能走,地图上有两个人,两个人每次走的方向都相同,每次只能向相同的方向走,,问最少几步就能相遇?题解这个题一看就是搜索,广搜,刚开始我陷入一个误区,让两个人分开记录状态,这个时候有个问题,当一个人能走,另一个人不能走的时候,步数就不同步,这个问题就......
  • JAVA@Transactional常用失效场景
    @Transactional(rollbackFor={RuntimeException.class,Error.class})@Overridepublicbooleancreate(){create1();create2();returntrue;}publicvoidcreate1(){Studentstudent=newStudent();student.setNa......
  • 【转】-synchronized与Lock的区别与使用
    详解synchronized与Lock的区别与使用该博客转载自​淳安郭富城​的​详解synchronized与Lock的区别与使用1.引言:昨天在学习别人分享的面试经验时,看到Lock的使用。想起自己在上次面试也遇到了synchronized与Lock的区别与使用。于是,我整理了两者的区别和使用情况,同时,对synchroni......
  • [Java并发]Synchronized
    publicclassAtomicTest01{publicstaticinti=0;publicstaticvoidmain(String[]args){Runnabletask=newRunnable(){@Overridepublicvoidrun(){synchronized(this){tr......
  • 关于事务回滚注解@Transactional
    在使用Spring的@Transactional注解时,有时会出现事务失效的情况。这通常是由于一些常见的配置或使用错误引起的。以下是事务失效的原因和处理方法:常见原因方法可见性@Transactional注解的方法必须是public的。SpringAOP代理只会拦截public方法,非public方法(如private、protect......
  • Stable Diffusion【艺术风格】:当游戏角色遇上古代纸莎草纸艺术
    提示词[character]asOnidemon参数设置大模型:RealVisXLV4.0Lightning采样器:DPM++SDEKarras采样迭代步数:5CFG:2反向提示词:(octanerender,render,drawing,anime,badphoto,badphotography:1.3),(worstquality,lowquality,blurry:1.2),(badteeth,deformedt......
  • 当非遗遇上AI,简直美不可言!
    本文由ChatMoney团队出品大家好,今天我要跟大家分享的是关于非遗与AI结合!我是用ChatmoneyAI-ChatAI聊天系统AI绘画制作的,你敢相信这些照片都是AI生成的吗?一、引言:随着科技的飞速发展,传统文化与现代科技的融合愈发引人注目。最近,非遗与人工智能(AI)的奇妙结合让我们目瞪口呆,简直......