2019-12-04 关于事务与锁的一次尝试

2019-12-04  本文已影响0人  江江江123

事务:原子性,一致性,隔离性,持久性
锁:多线程下,资源不会共享

        Transaction transaction = database.beginTransaction();
        checkName(request.name);
        database.execute("UPDATE categories SET has_children = ? WHERE id = ?", Boolean.TRUE, category.parentId);
        category.id = categoryRepository.insert(category).getAsLong();
        transaction.commit();

上面这个事务保证我们在插入一个分类的同时,保证他父类的has_children为true,并在插入之前验证了name不重复

但是在调试时,我尝试添加断点,postman发送请求的结果为服务器未响应,所以会重复发请求尝试

结果就是我在同一个分类下创建了多个名字相同的类型;

根据以上结论,我可以得出如果在并发环境下,有2个人同时是创建同名分类,我的校验是失效的

解决方法:1.对该表的name添加唯一索引,这样第二个同名插入自然报错
2.使用synchronized包含该方法

进一步的思考:
1.很多时候为了支持并发量,我们会将该工程多节点启动,通过负载均衡来访问,这样mysql上添加索引依然生效,但是添加synchronized则因为只能锁住当前工程中的线程而失效,可以通过redis实现锁来解决这个问题

2.如何解决分布式下多个接口调用的事务

目前最简单,有效的方法,通过记录日志,手动处理。。

不过也可以考虑下复杂的方法。
2.1什么时候发生?
同时调用api1,api2,api3,如果1执行成功2执行不成功,但是1已经无法回滚
2.2如果希望1回滚,需要什么
2.2.1 1成功后返回一个取反的接口及参数,如果2,3失败则调用回滚接口
2.2.1.1 存在问题:一定要保证回滚接口的正确,但是回滚这个事件要保证锁,不然可能导致回滚操作将另一个线程已提交的事务修改。
那岂不是在调用1时加锁,一直要等到确定用户不回滚再解锁,所以该方案否决!当然在一些简单的新增,删除业务上还是能用用的。

2.2.2 创建一个中间表,1,2,3执行前先创建一个待确认的数据,如果返回结果正确,将待确认改为正确,如果返回失败则继续向下执行。
之后在创建一个job重复执行待确认的数据,当操作成功时修改待确认的数据

上一篇下一篇

猜你喜欢

热点阅读