Java @Transactional与synchronized使用的问题
作者:YXXYX
引言
@Transactional是spring通过aop让我们轻松实现事务控制的一个注解;而synchronized是实现同步的java关键字;但是它们两个不能一起使用,一起使用会出现
synchronized失效的问题,这里简单记录一下这个问题;
发现问题
我在impl中实现一个功能逻辑时,为了保证幂等性,在方法中使用synchronized保证同一个用户短时间内多次请求只能串行执行,因为数据变动涉及多张表,所以我又加了一个@Transactional注解,伪代码如下:
@Transactional public void demo() { ...一些操作... synchronized(lock) { ...数据库读写操作... } }
然后测试时就发现synchronized没有生效,确认代码逻辑没有问题后,查询了资料发现了问题;
问题原因
这里不过多解释@Transactional注解底层,感兴趣可以自行查阅资料;
主要原因就是@Transactional注解通过aop实现事务管理,当标注该注解的方法执行完成后才提交事务,而synchronized代码块又是在一个事务内,就会出现第一个线程释放锁后但是事务还没提交,第二个线程就进入同步代码块获取到未提交的数据库数据;
大致如图:
解决问题
大致思路
解决方法很简单,既然问题出在事务未提交,那么只要把对应事务操作的代码单独抽取出来,封装成一个单独的方法,在synchronized中调用该方法即可;
如图:
伪代码为:
public void demo() { ...一些操作... synchronized(lock) { databaseOption(); // 调用数据库操作方法 } } @Transactional public void databaseOption() { ...数据库读写操作... }
注意:@Transactional注解修饰的方法需要是public权限;
虽然这样写好像解决了事务未提交的问题,但是这样写会存在新的问题;上面这种是这两种方法都写在serviceImpl中,但是这样调用databaseOption方法就会出现@Transactional事务不生效的情况;
@Transactional事务不生效问题
所以在同一个类内部调用@Transactional标注的方法事务也不会开启,原因是:
@Transactional事务管理是基于动态代理对象的代理逻辑实现的,那么如果在类内部调用类内部的事务方法,这个调用事务方法的过程并不是通过代理对象来调用的,而是直接通过this对象来调用方法,绕过的代理对象,肯定就是没有代理逻辑了
依然是@Transactional的底层原理,可以好好研究一下这个注解,面试就有的聊了;
那么解决方法就是:
不要把由@Transactional修饰的databaseOption方法和调用它的方法放到同一个类中;这里你可以多写个service放databaseOption方法,但是这样好像没有什么意义;我选择的是把同步代码块放到controller中,在controller中调用serviceImpl中的databaseOption方法;
伪代码:
controller类
@RestController public class TestController { @Resource private TestService testService; @PostMapping("/test") public String testInterface() { ...一些操作... synchronized(lock) { testService.databaseOption(); // 调用数据库操作方法 } } }
service类
@Service("testService") public class TestServiceImpl implements TestService { @Transactional public void databaseOption() { ...数据库读写操作... } }
这样就能保证@Transactional事务生效;但是这样写的缺点就是一些逻辑会被拆分到controller中,可读性会稍差点;
总结
这就是这两天我踩的坑,总的来说所有问题的出现都是由于对@Transactional这个注解理解的不透彻,以后还是要了解该注解的实现原理;
到此这篇关于Java @Transactional与synchronized使用的问题的文章就介绍到这了,更多相关Java @Transactional与synchronized内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
您可能感兴趣的文章:
- Java同步锁Synchronized底层源码和原理剖析(推荐)
- java同步锁的正确使用方法(必看篇)
- 95%的Java程序员人都用不好Synchronized详解
- Java synchronized同步关键字工作原理
- Java synchronized偏向锁的概念与使用
- Java synchronized轻量级锁实现过程浅析
- Java synchronized重量级锁实现过程浅析
- Java synchronized与死锁深入探究
- Java synchronized与CAS使用方式详解
- 浅析Java关键词synchronized的使用
- synchronized及JUC显式locks 使用原理解析
- java锁synchronized面试常问总结
- Java HashTable与Collections.synchronizedMap源码深入解析
- Java Synchronized锁的使用详解
- AQS加锁机制Synchronized相似点详解
- Java必会的Synchronized底层原理剖析
- 一个例子带你看懂Java中synchronized关键字到底怎么用
- 详解Java Synchronized的实现原理
- Synchronized 和 ReentrantLock 的实现原理及区别
- Java同步锁synchronized用法的最全总结