工作当中经常会遇到既需要开启事务管理,同时也需要同步保证线程安全的场景。

比如一个方法

@Transactional
public synchronized void test(){
//
}

不知道大家有没有这样写过?

这样写会有问题吗?

众所周知,spring使用动态代理加AOP实现事务管理。那么上面的方法实际上需要简化成3个步骤:

void begin();

@Transactional
public synchronized void test(){
//
} void commit();
// void rollback();

先看事务本身,这里简化为test()一个方法,从而忽略事务的传播来看,它是不受synchronized 影响的。因为它能正常commitrollback不受其它线程影响。

再看同步这一块,这里很明显就有点问题了。synchronized 至少无法作用于事务开启提交这一步骤。假设一个线程先在此方法做了update,在return之后commit之前,另一个线程进入了此方法,进行了select,

除非事务隔离级别为读未提交(READ_UNCOMMITTED)(话说回来谁会在生产环境用这种隔离级别呢),不然第二个线程读到的是未修改的值。

而这肯定并未与使用synchronized 的初衷相符。

口说无凭,show you me code。

@Transactional
public synchronized void test(){
log.info("表哥,我进来了哦!");
// select
Person person = personDao.selectByPrimaryKey("1");
log.info("person.name = " + person.getName());
// update
person.setName("你是谁?你根本不是我表哥!");
int result = personDao.updateByPrimaryKeySelective(person);
log.info("result = " + result);
}

然后在TransactionAspectSupport.commitTransactionAfterReturning()加个断点。

再模拟两个请求执行,在断点处观察第2次请求与第1次请求select到的值是不是一致。一致说明synchronized 在这里没有达到预期目的。

注意断点时选thread不要选all,不然第2个线程进不来。

通过执行结果,可以看到第2个线程执行的时候访问到了还是原值张三,并在update时等待锁超时。

通过什么方法可以让synchronized 达到预期效果呢?

手动开启事务?pass。

事务传播级别?无关。

事务隔离级别?

读未提交 不实用。还是试试效果。

加上隔离级别

看看效果

能满足要求,但是谁会在生产环境使用读未提交级别?

依次往上,

读已提交,经测试不满足,

可重复读,mysql默认级别,一开始就是,不满足。

SERIALIZABLE

这倒是走向了另一个极端,通过测试可以看到,由于在SERIALIZABLE隔离级别下,会给表加个锁,因此在第2个线程执行到Select的时候就会一直等待到锁超时。

在这一个固定的测试场景曲线满足了业务要求,但是它还是进入了test方法,因此不满足synchronized的要求。

而且这种隔离级别和读未提交一样属于两个极端,它会极大的抑制并发数,在生产环境中也极少使用,在这里属于既不实用也不好用。

for update

给select查询语句手动上锁。

测试结果就不截图了,这种是比SERIALIZABLE要实用一些,它只加行锁,其它的话类似,并不能完全达到synchronized的要求。

是否使用看场景。

给test方法加一层调用方法

transcationalsynchronized分开,作用在两个方法。比如synchronized在上层方法。

千万别写成这样,这样事务不生效了。

最好也别写到最顶层如controller层,这样感觉把通道门口就给堵死了的感觉。只是加个中间层。

这样,表哥有了第1次的经验过后,表妹在第2次来的时候就被小区安保直接给拦住啦,在表哥完全跑路之前没有撬锁的机会了。

另外,一定是synchronized在调用层,transcational在被调用层。不能弄反了,弄反了就和之前没区别了。

总结

当transcational遇上synchronized,不要搞在一起,会出事。

如果要用最好是分开。

当transcational遇上synchronized的更多相关文章

  1. 谁还没遇上过NoClassDefFoundError咋地——浅谈字节码生成与热部署

    谁还没遇上过NoClassDefFoundError咋地--浅谈字节码生成与热部署 前言 在Java程序员的世界里,NoClassDefFoundError是一类相当令人厌恶的错误,因为这类错误通常非 ...

  2. MVC遇上bootstrap后的ajax表单模型验证

    MVC遇上bootstrap后的ajax表单验证 使用bootstrap后他由他自带的样式has-error,想要使用它就会比较麻烦,往常使用jqueyr.validate的话只有使用他自己的样式了, ...

  3. 敏捷遇上UML-需求分析及软件设计最佳实践(郑州站 2014-6-7)

      邀请函: 尊敬的阁下:我们将在郑州为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实 ...

  4. 敏捷遇上UML—软创基地马年大会(广州站 2014-4-19)

        我们将在广州为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实战技巧. 时间:2 ...

  5. 敏捷遇上UML——软创基地马年大会(深圳站 2014-3-15)

    邀请函: 尊敬的阁下: 我们将在深圳为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实战 ...

  6. 初识genymotion安装遇上的VirtualBox问题

    想必做过Android开发的都讨厌那慢如蜗牛的 eclipse原生Android模拟器吧! 光是启动这个模拟器都得花上两三分钟,慢慢的用起来手机来调试,但那毕竟不是长久之计,也确实不方便,后来知道了g ...

  7. SQL SERVER 2008 R2 SP1更新时,遇上共享功能更新失败解决方案

    SQL SERVER 2008 R2 SP1更新时,遇上共享功能更新失败的问题,可作如下尝试: 更新失败后,在windows的[事件查看器→应用程序]中找到来源为MsiInstaller,事件ID为1 ...

  8. 当创业遇上O2O,新一批死亡名单,看完震惊了!

    当创业遇上O2O,故事就开始了,总投入1.6亿.半年开7家便利店.会员猛增至10万……2015半年过去后,很多故事在后面变成了一场创业“事故”,是模式错误还是烧钱过度?这些项目的失败能给国内创业者带来 ...

  9. LoadRunner - 当DiscuzNT遇上了Loadrunner(下) (转发)

    当DiscuzNT遇上了Loadrunner(下) 在之前的两篇文章中,基本上介绍了如何录制脚本和生成并发用户,同时还对测试报告中的几个图表做了简单的说明.今天这篇文章做为这个系列的最后一篇,将会介绍 ...

  10. LoadRunner - 当DiscuzNT遇上了Loadrunner(中) (转发)

    当DiscuzNT遇上了Loadrunner(中) 在上文中,介绍了如果录制脚本和设置脚本执行次数.如果经过调试脚本能够正常工作的话,就可以设置并发用户数并进行压力测试了. 首先我们通过脚本编辑界面上 ...

随机推荐

  1. 七牛云服务器debug

    400{ResponseInfo:com.qiniu.http.Response@16fd3806,status:400, reqId:uzcAADGFlzHUE-kW, xlog:-, xvia:, ...

  2. 将map转为Bean的工具类 BeanUtil

    Map<String,Object> pbclwhMainMap = (Map<String,Object>)param.get("pbclwhMain") ...

  3. Jenkins项目中的Performance Trend图表不显示

    权限问题:chmod 777 /.../*.jtl 其中上述目录为jmeter生成jtl格式的结果报告的路径,也就是ant对应build.xml里配置好的路径.

  4. Error running 'tm8': Cannot load C:\Users\Administrator\.IntelliJIdea2019.3\system\tomcat\Unnamed_jymes_3\conf\server.xml (系统找不到指定的文件。)

    救命救命,由于脑壳被门夹了去更改了idea的配置,导致重启项目报错!又是给自己挖坑的一天,唉!!! 主要是看报错信息还一直以为是tomcat的问题,然后试了很多方法,比如查看配置的tomcat路径.重 ...

  5. 安装navicat,解决No All Pattern Found! File Already Patched?

    话不多说,直接上步骤和截图! 第一步:安装包和破解工具我存到了自己的网盘中,下面是地址和提取码 链接: https://pan.baidu.com/s/1KTTV3__51kKxL3jkzW5O5A ...

  6. Jetpack compose学习笔记之列表(布局)

    一,简介 Jetpack compose中的布局主要分为Column,Row,Box. 二,Column创建的列表 Column创建list时,不管内容是在屏幕内还是屏幕外,都会将list的内容全部创 ...

  7. spring security添加接口白名单

    在项目中遇到的问题是要将某个接口设为白名单,无需验证即可被用户使用. 解决方法: 在nacos配置文件中ignore whites(不校验白名单)中添加对应接口,无gateway前缀即可,添加立即生效 ...

  8. Spring Cloud学习记录

    Eureka和zookeeper都是注册中心为什么zookeeper不适合? 1.CAP原则.一致性,可用性,分区容错性,最多满足两种.zookeeper遵循CP原则,实际项目中不应该为了一致性失去可 ...

  9. 使用navicat连接本地数据库时,出现错误1251错误

    在安装完MySQL的时候,我们现在一般都使用Navicat来连接数据库,可惜出现下面的错误:1251-Client does not support authentication protocol r ...

  10. 【转】Thunderbird 设置转移

    此文章可能已经过时. 此文章的原文版本已经做出了重大更动.在此页面更新前,您可能也会觉得这个有用:Profiles - Where Thunderbird stores your messages a ...