赞
踩
起因,前端新增时,新增按钮没有加load,导致可以在弹框没有消失时可以点击很多次新增按钮
从而出现很多重复数据,一开始数据表这个订单号没有加唯一索引,也才会出现这种情况
我一开始开发时给我service的方法加了事务和同步锁,以为没问题,后面发现并发测试时出现了重复数据,然后我才注意有问题,才深究
首先这种情况 同步锁也许都不能生效。因为针对@Transactional标注的方法,Spring在AOP中实现,它会生成一个临时类,并用一个实现了开启和关闭事务的同名方法来覆写原本这个被标注的方法。大概类似这样
- public void test() {
- System.out.println("开启事务操作");
- //--------------------------------------
- //调用原本的test同步方法
- a.test();
- //--------------------------------------
- System.out.println("提交事务操作");
- }
即spring利用aop自动帮我们的业务代码做了开启事务和提交事务的操作。而中间的代码,才真正执行我们的业务代码。 如此,在这段代码里里面,是先开启事务,才进入同步锁的。 下面看这个类:
- @Service
- public class TestService{
- @Transactional
- public synchronized void test() {
- //代码1
- System.out.println("数据库操作1");
- //代码2
- System.out.println("数据库操作2");
- }
- }
这段代码中Test类被声明为bean,那么synchronized锁住的其实是整个类,在执行方法中的代码1和2时,是保证能够线程同步的,但是,假设线程A和B同时访问这个方法,如果A先执行完了代码1、2,释放了同步锁,正准备提交事务的时候,B随即进入同步代码执行完了代码1、2,并与A同时提交了事务。那就会出现问题了,同步性不能被保证了,因为我们锁的的是方法,不用管事务提没提交
解决办法有很多种 , 前端新增时加load 后端数据库加唯一约束
代码解决办法是 ,在调用事务方法test就跟他提前加上锁,这样子可以解决synchronized失效
- @Service
- public class TestService{
- @Transactional
- public void test() {
- //代码1
- System.out.println("数据库操作1");
- //代码2
- System.out.println("数据库操作2");
- }
- }
-
- @RestController
- public class Test{
- @Autowired
- private TestService testService;
-
- public void test1(){
- synchronized(this) {
- testService.test();
- }
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。