首页 > 热点 > > 正文

环球速讯:当transcational遇上synchronized

时间:2023-03-24 09:48:24 来源:博客园

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

@Transactionalpublic synchronized void test(){    // }

不知道大家有没有这样写过?这样写会有问题吗?

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


(资料图)

void begin();@Transactionalpublic synchronized void test(){    // }void commit();// void rollback();

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

再看同步这一块,这里很明显就有点问题了。synchronized 至少无法作用于事务开启提交这一步骤。假设一个线程先在此方法做了update,在return之后commit之前,另一个线程进入了此方法,进行了select,除非事务隔离级别为读未提交(READ_UNCOMMITTED)(话说回来谁会在生产环境用这种隔离级别呢),不然第二个线程读到的是未修改的值。而这肯定并未与使用synchronized 的初衷相符。

口说无凭,show you me code。

@Transactionalpublic 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,不要搞在一起,会出事。如果要用最好是分开。

关键词:
x 广告
共同抗疫!郑州71岁党员志愿者每天爬6栋楼,提醒800多户居民做核酸

1月4日,郑州市新冠肺炎疫情防控指挥部办公室发布通告对部分区域实施管控措施。这是近半年来,新冠疫情第3次造访郑州。截止至1月10日24时,

安阳疫情最新消息|1月11日8时至12日8时安阳市新增本土确诊病例39例,累计123例

安阳疫情最新消息2022年1月11日8时至12日8时安阳市新型冠状病毒肺炎疫情最新情况1月11日8时至12日8时,全市新增本土确诊病例39例(汤阴县38

迅速高效!“河南抗疫互助通道”网上网下联动 获群众点赞

核酸检测24小时了还没查到结果,怎么办?现在高速下站口的管控政策到底是什么样子的?从洛阳老城区自驾走高速回郑州,收费站还劝返吗?苏八

信阳市疫情防控工作视频调度会召开 陈志伟出席会议

1月11日,市疫情防控工作视频调度会召开。代市长陈志伟出席会议并讲话。听取有关疫情防控重点工作和各县区(管理区、开发区)疫情防控工作

全国最新疫情消息:11日新增本土确诊病例166例 天津市今日启动第二轮全员核酸检测

11日0—24时,31个省(自治区、直辖市)和新疆生产建设兵团报告新增新冠肺炎本土确诊病例166例(河南118例,其中安阳市65例、许昌市41例、

1月12日天津市放假半天 开启第二轮全员核酸检测

1月12日,天津市人民政府发布重要通告,为做好天津市第二轮全员核酸检测工作,全市机关和企事业单位于1月12日(星期三)下午放假半天。广大

x 广告

Copyright ©  2015-2022 华东评测网版权所有  备案号:京ICP备2022016840号-41   联系邮箱:2 913 236 @qq.com