当前位置:主页 > java教程 > Java @Transactional与synchronized

Java @Transactional与synchronized使用的问题

发布:2023-04-20 18:00:01 59


本站精选了一篇相关的编程文章,网友姜建同根据主题投稿了本篇教程内容,涉及到Java @Transactional、Java synchronized、Java @Transactional与synchronized相关内容,已被150网友关注,如果对知识点想更进一步了解可以在下方电子资料中获取。

Java @Transactional与synchronized

引言

@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与CAS使用方式详解

    发布:2023-03-14

    提到Java的知识点一定会有多线程,JDK版本不断的更迭很多新的概念和方法也都响应提出,但是多线程和线程安全一直是一个重要的关注点。比如说我们一入门就学习的synchronized怎么个实现和原理,还有总是被提到的CAS是啥,他和synchronized关系是啥?请往下看


  • Java synchronized轻量级锁实现过程浅析

    发布:2023-04-06

    这篇文章主要介绍了Java synchronized轻量级锁实现过程,synchronized是Java里的一个关键字,起到的一个效果是"监视器锁",它的功能就是保证操作的原子性,同时禁止指令重排序和保证内存的可见性


  • Java synchronized与死锁深入探究

    发布:2023-04-20

    这篇文章主要介绍了Java synchronized与死锁,Java中提供了synchronized关键字,将可能引发安全问题的代码包裹在synchronized代码块中,表示这些代码需要进行线程同步


  • Java synchronized同步关键字工作原理

    发布:2023-04-06

    synchronized作为Java程序员最常用同步工具,很多人却对它的用法和实现原理一知半解,以至于还有不少人认为synchronized是重量级锁,性能较差,尽量少用。但不可否认的是synchronized依然是并发首选工具,本文就来详细讲讲


  • Java synchronized重量级锁实现过程浅析

    发布:2023-04-06

    这篇文章主要介绍了Java synchronized重量级锁实现过程,synchronized是Java里的一个关键字,起到的一个效果是"监视器锁",它的功能就是保证操作的原子性,同时禁止指令重排序和保证内存的可见性


  • Java synchronized偏向锁的概念与使用

    发布:2023-04-06

    因为在我们写的程序当中可能会经常使用到synchronized关键字,因此JVM对synchronized做出了很多优化,而在本篇文章当中我们将仔细介绍JVM对synchronized的偏向锁的细节


网友讨论