Java @Transactional与synchronized使用的问题

目录
  • 引言
  • 发现问题
  • 问题原因
  • 解决问题
    • 大致思路
    • @Transactional事务不生效问题
  • 总结

引言

@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内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java synchronized与死锁深入探究

    目录 1.synchronized的特性 2.synchronized使用示例: 3.Java标准库中的线程安全类 4.死锁是什么 5.如果避免死锁 1.synchronized的特性 1). 互斥性 当某个线程执行到 synchronized 所修饰的对象时 , 该线程对象会加锁(lock) , 其他线程如果执行到同一个对象的 synchronized 就会产生阻塞等待. 进入 synchronized 修饰的代码块 , 相当于加锁. 退出 synchronized 修饰着代码块 , 相当于解

  • Java必会的Synchronized底层原理剖析

    目录 1. synchronized作用 2. synchronized用法 3. synchronized加锁原理 synchronized作为Java程序员最常用同步工具,很多人却对它的用法和实现原理一知半解,以至于还有不少人认为synchronized是重量级锁,性能较差,尽量少用. 但不可否认的是synchronized依然是并发首选工具,连volatile.CAS.ReentrantLock都无法动摇synchronized的地位.synchronized是工作面试中的必备技能,今天就

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

    目录 一.什么是重量级锁 二.重量级锁的演示 三.重量级锁的原理 四.锁的优缺点对比 一.什么是重量级锁 当有大量的线程都在竞争同一把锁的时候,这个时候加的锁,就是重量级锁. 这个重量级锁其实指的就是JVM内部的ObjectMonitor监视器对象: ObjectMonitor() { _header = NULL; //锁对象的原始对象头 _count = 0; //抢占当前锁的线程数量 _waiters = 0, //调用wait方法后等待的线程数量 _recursions = 0; //记

  • Java Synchronized锁的使用详解

    目录 Synchronized的用法 同步示例方法 同步静态方法 同步代码块 Synchronized的用法 在多线程并发问题中,常用Synchronized锁解决问题.Synchronized锁通常用于同步示例方法,同步静态方法,同步代码块等. 同步示例方法 我们可能自己使用过在方法前加Synchronized锁修饰,在多线程并发同时调用同一个实例化对象时,如果这个方法加上了Synchronized锁,那么也是线程安全的.举个栗子: package Thread; import java.ut

  • java锁synchronized面试常问总结

    目录 synchronized都问啥? synchronized是什么? synchronized锁什么? synchronized怎么用? 结语 synchronized都问啥? 如果Java面试有什么是必问的,synchronized必定占据一席之地.初出茅庐时synchronized的用法,成长后synchronized的原理,可谓是Java工程师的“一生之敌”. 按照惯例,先来看synchronized的常见问题(在线Excel同步更新中): 根据统计数据可以总结出synchronize

  • Java @Transactional与synchronized使用的问题

    目录 引言 发现问题 问题原因 解决问题 大致思路 @Transactional事务不生效问题 总结 引言 @Transactional是spring通过aop让我们轻松实现事务控制的一个注解:而synchronized是实现同步的java关键字:但是它们两个不能一起使用,一起使用会出现 synchronized失效的问题,这里简单记录一下这个问题: 发现问题 我在impl中实现一个功能逻辑时,为了保证幂等性,在方法中使用synchronized保证同一个用户短时间内多次请求只能串行执行,因为数

  • 解析Java编程之Synchronized锁住的对象

    图片上传 密码修改为  synchronized是java中用于同步的关键字,一般我们通过Synchronized锁住一个对象,来进行线程同步.我们需要了解在程序执行过程中,synchronized锁住的到底是哪个对象,否则我们在多线程的程序就有可能出现问题. 看下面的代码,我们定义了一个静态变量n,在run方法中,我们使n增加10,然后在main方法中,我们开辟了100个线程,来执行n增加的操作,如果线程没有并发执行,那么n最后的值应该为1000,显然下面的程序执行完结果不是1000,因为我们

  • 解决Maven 项目报错 java.httpservlet和synchronized使用方法

    使用java8 的lanmbe表达式时,使用java1.8编译,则会报错 需要在pom.xml的<bulid></build>中添加 <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</versi

  • Java 同步锁(synchronized)详解及实例

    Java 同步锁(synchronized)详解及实例 Java中cpu分给每个线程的时间片是随机的并且在Java中好多都是多个线程共用一个资源,比如火车卖票,火车票是一定的,但卖火车票的窗口到处都有,每个窗口就相当于一个线程,这么多的线程共用所有的火车票这个资源.如果在一个时间点上,两个线程同时使用这个资源,那他们取出的火车票是一样的(座位号一样),这样就会给乘客造成麻烦.比如下面程序: package com.pakage.ThreadAndRunnable; public class Ru

  • 详细解读java同步之synchronized解析

    问题 (1)synchronized的特性? (2)synchronized的实现原理? (3)synchronized是否可重入? (4)synchronized是否是公平锁? (5)synchronized的优化? (6)synchronized的五种使用方式? 简介 synchronized关键字是Java里面最基本的同步手段,它经过编译之后,会在同步块的前后分别生成 monitorenter 和 monitorexit 字节码指令,这两个字节码指令都需要一个引用类型的参数来指明要锁定和解

  • 如何在JAVA中使用Synchronized

    <编程思想之多线程与多进程(1)--以操作系统的角度述说线程与进程>一文详细讲述了线程.进程的关系及在操作系统中的表现,这是多线程学习必须了解的基础.本文将接着讲一下Java线程同步中的一个重要的概念synchronized. 在Java中,synchronized关键字是用来控制线程同步的,就是在多线程的环境下,控制synchronized代码段不被多个线程同时执行. synchronized是Java中的关键字,是一种同步锁.它修饰的对象有以下几种: 1. 修饰一个代码块,被修饰的代码块称

  • Java开发中synchronized的定义及用法详解

    概念 是利用锁的机制来实现同步的. 互斥性:即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机制,这样在同一时间只有一个线程对需同步的代码块(复合操作)进行访问.互斥性我们也往往称为操作的原子性. 可见性:必须确保在锁被释放之前,对共享变量所做的修改,对于随后获得该锁的另一个线程是可见的(即在获得锁时应获得最新共享变量的值),否则另一个线程可能是在本地缓存的某个副本上继续操作从而引起不一致. 用法 修饰静态方法: //同步静态方法 public synchronized

  • 实例讲解Java中的synchronized

    一.使用场景 在负责后台开发的时候,很多时候都是提供接口给前端开发人员去调用,会遇到这样的场景: 需要提供一个领奖接口,每个用户名只能领取一次,我们可以将成功领取的用户在数据库用个标记保存起来.如果这个用户再来领取的时候,查询数据库看该用户是否领取过. 但是问题来了,假设用户手速很快,极短时间内点了两次领奖按钮(前端没有进行控制,我们也不能依赖前端去控制).那么可能掉了两次领奖接口,而且有可能第二次调用的时候查询数据库的时候,第一次领奖还没有执行完成更新领奖标记. 这种场景就可以使用到synch

  • java Volatile与Synchronized的区别

    引言 在研究并发程序时,我们可能都知道volatile和synchronized是用于多线程中,用于线程安全和变量可见性的,但是具体两者怎么使用,有何区别可能还是稀里糊涂一知半解,在此就自己简单的理解总结一下二者的区别,和大家一块儿学习!我们需要了解java中关键字volatile和synchronized关键字的使用以及lock类的用法. 首先,了解下java的内存模型: java的线程内存模型中定义了每个线程都有一份自己的共享变量副本(本地内存),里面存放自己私有的数据,其他线程不能直接访问

  • Java并发之synchronized实现原理深入理解

    目录 synchronized的三种应用方式 synchronized作用于实例方法 synchronized作用于静态方法 synchronized同步代码块 synchronized底层语义原理 理解Java对象头与Monitor synchronized代码块底层原理 synchronized方法底层原理 Java虚拟机对synchronized的优化 偏向锁 轻量级锁 自旋锁 锁消除 关于synchronized 可能需要了解的关键点 synchronized的可重入性 线程中断与syn

随机推荐