当transcational遇上synchronized
工作当中经常会遇到既需要开启事务管理,同时也需要同步保证线程安全的场景。
比如一个方法
@Transactional
public synchronized void test(){
//
}
不知道大家有没有这样写过?
这样写会有问题吗?
众所周知,spring使用动态代理加AOP实现事务管理。那么上面的方法实际上需要简化成3个步骤:
void begin();
@Transactional
public synchronized void test(){
//
}
void commit();
// void rollback();
先看事务本身,这里简化为test()一个方法,从而忽略事务的传播来看,它是不受synchronized 影响的。因为它能正常commit或rollback不受其它线程影响。
再看同步这一块,这里很明显就有点问题了。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方法加一层调用方法
把transcational和synchronized分开,作用在两个方法。比如synchronized在上层方法。

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

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

另外,一定是synchronized在调用层,transcational在被调用层。不能弄反了,弄反了就和之前没区别了。
总结
当transcational遇上synchronized,不要搞在一起,会出事。
如果要用最好是分开。
当transcational遇上synchronized的更多相关文章
- 谁还没遇上过NoClassDefFoundError咋地——浅谈字节码生成与热部署
谁还没遇上过NoClassDefFoundError咋地--浅谈字节码生成与热部署 前言 在Java程序员的世界里,NoClassDefFoundError是一类相当令人厌恶的错误,因为这类错误通常非 ...
- MVC遇上bootstrap后的ajax表单模型验证
MVC遇上bootstrap后的ajax表单验证 使用bootstrap后他由他自带的样式has-error,想要使用它就会比较麻烦,往常使用jqueyr.validate的话只有使用他自己的样式了, ...
- 敏捷遇上UML-需求分析及软件设计最佳实践(郑州站 2014-6-7)
邀请函: 尊敬的阁下:我们将在郑州为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实 ...
- 敏捷遇上UML—软创基地马年大会(广州站 2014-4-19)
我们将在广州为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实战技巧. 时间:2 ...
- 敏捷遇上UML——软创基地马年大会(深圳站 2014-3-15)
邀请函: 尊敬的阁下: 我们将在深圳为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实战 ...
- 初识genymotion安装遇上的VirtualBox问题
想必做过Android开发的都讨厌那慢如蜗牛的 eclipse原生Android模拟器吧! 光是启动这个模拟器都得花上两三分钟,慢慢的用起来手机来调试,但那毕竟不是长久之计,也确实不方便,后来知道了g ...
- SQL SERVER 2008 R2 SP1更新时,遇上共享功能更新失败解决方案
SQL SERVER 2008 R2 SP1更新时,遇上共享功能更新失败的问题,可作如下尝试: 更新失败后,在windows的[事件查看器→应用程序]中找到来源为MsiInstaller,事件ID为1 ...
- 当创业遇上O2O,新一批死亡名单,看完震惊了!
当创业遇上O2O,故事就开始了,总投入1.6亿.半年开7家便利店.会员猛增至10万……2015半年过去后,很多故事在后面变成了一场创业“事故”,是模式错误还是烧钱过度?这些项目的失败能给国内创业者带来 ...
- LoadRunner - 当DiscuzNT遇上了Loadrunner(下) (转发)
当DiscuzNT遇上了Loadrunner(下) 在之前的两篇文章中,基本上介绍了如何录制脚本和生成并发用户,同时还对测试报告中的几个图表做了简单的说明.今天这篇文章做为这个系列的最后一篇,将会介绍 ...
- LoadRunner - 当DiscuzNT遇上了Loadrunner(中) (转发)
当DiscuzNT遇上了Loadrunner(中) 在上文中,介绍了如果录制脚本和设置脚本执行次数.如果经过调试脚本能够正常工作的话,就可以设置并发用户数并进行压力测试了. 首先我们通过脚本编辑界面上 ...
随机推荐
- docker登录mysql
一.查看mysql是否已启动 二.登录mysql 三.假如需要重启mysql 查看docker中运行的容器docker ps,再重新启动mysql,docker restart 9299415df7f ...
- Erueka注册源码分析
在com.netfix.discovery包下有一个DiscoveryClient类中包含注册方法,DiscoveryClient实现了EurekaClient接口,并且是一个单例模式,而Eureka ...
- ssh连接不上、Xshell意外关闭Socket error Event: 32 Error: 10053.
Xshell意外关闭可能会出现这种问题,如遇如下错误可解决: Connecting to 47.106.80.28:22- Connection established. To escape to l ...
- JDK1.8下载、安装和环境配置教程——
JDK1.8下载.安装和环境配置教程 1.下载安装包 - 浏览器搜索JDK8,如下图: - 点击网页打开后,下拉找到这个: - 根据自己的系统选择正确的进行下载: 例如我的是windows 64位,我 ...
- 常用的CSS效果(1)
单行省略 overflow: hidden; text-overflow: ellipsis; white-space: nowrap; 多行省略 display:-webkit-box; overf ...
- vue中关于get传参数为数组的解决方法
按理来说,get请求方式是没有数组的,get请求方式带参数都是字符串,需要和后端协商是用某个标识符分割开,例如"|" ",". 当然如果需要数组的话,也能解 ...
- ARP协议 路由器原理
ARP协议 路由器原理 1 广播与广播域 广播:将广播地址作为目的地址的数据帧 广播域:网络中能够接收到同一个广播所有节点的集合(在这里广播域越小越好) 交换机控制不了广播 路由器可以控制广播 ...
- c++官方网站汇集
c++官方网站汇集 gcc官网: https://gcc.gnu.org/ c++参考手册: https://en.cppreference.com/w/cpp c++教程网站: https://ww ...
- Python抓取数据具体流程
之前看了一段有关爬虫的网课深有启发,于是自己也尝试着如如何过去爬虫百科"python"词条等相关页面的整个过程记录下来,方便后期其他人一起来学习. 抓取策略 确定目标:重要的是先确 ...
- ping 的七种用法【搬运】
原作者:Pheenet菲尼特 原地址:https://www.toutiao.com/a6783191796659782148/?tt_from=weixin&utm_campaign=cli ...