前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >你的锁为什么会失效?

你的锁为什么会失效?

作者头像
Java深度编程
发布2023-10-08 20:17:35
1240
发布2023-10-08 20:17:35
举报
文章被收录于专栏:Java深度编程Java深度编程

前言:

我们在开发过程中,为了解决高并发的问题,通常会选择加锁,以此来让程序排队执行,这样避免出现数据查询后判断的错乱,导致判断失效,数据重复,重复执行某些程序的目的。

那么,你可曾想过有一天你的锁会失效?

我们先来看一下啊以下的代码:

代码语言:javascript
复制
synchronized (Api.class) {
            resultVo = service.relationDept(data);
}
代码语言:javascript
复制
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
public ResultVo<String> relationDept(String data) {
    //校验是否已经绑定此部门
    int row = dataSubscribeDao.selectCountRDepartmentWorker(deptFkCode, workerFkCode);
    if (row == 0) {
        RDepartmentWorker rDepartmentWorker = new RDepartmentWorker();
        rDepartmentWorker.setDepartmentFkCode(deptFkCode);
        // …… 省略其它赋值代码
       dao.insertRDepartmentWorker(rDepartmentWorker);
       //加入正常部门后,要删除加入的本校区默认部门
        Long defaultDepFkCode = dao.getDefaultDepBySchool(schoolFkCode);
        if (defaultDepFkCode != null) {
            dao.deleteWorkerDefaultDepartment(workerFkCode, defaultDepFkCode);
        }
    }

如上代码,在绑定部门的时候,要先查询用户是否已经绑定了部门,从而做出判断,没有判定就判定,同时删除已绑定的默认部门。为了防止并发问题,所以在把整个方式加上同步锁。

实际上,当你运行这段代码以后,会有一定的概率出现判断失效,给人“锁失效”的感觉,其实并不是锁失效了,而是锁功能和事务维度的问题;锁限定的是线程,也叫线程锁,而事务的提交和回滚是在数据库那一套系统中完成的,因此锁并不能锁住数据库的事务,所以才会导致查询时事务可能还没有提交,从而出现判断失效的现象。

那么应该如何修正呢?

最优的方案是使用数据库自带的事务锁!

代码语言:javascript
复制
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)

上述代码中所使用的是事务注解参数,是新开事务,当查询,变更数据同时存在时,会放入不同的事务组,因此事务不同步,要改成只使用@Transactional,并且可以去掉外层的syn同步锁。

完整代码如下:

代码语言:javascript
复制
@Transactional
public ResultVo<String> relationDept(String data) {
    //校验是否已经绑定此部门
    int row = dataSubscribeDao.selectCountRDepartmentWorker(deptFkCode, workerFkCode);
    if (row == 0) {
        RDepartmentWorker rDepartmentWorker = new RDepartmentWorker();
        rDepartmentWorker.setDepartmentFkCode(deptFkCode);
        // …… 省略其它赋值代码
       dao.insertRDepartmentWorker(rDepartmentWorker);
       //加入正常部门后,要删除加入的本校区默认部门
        Long defaultDepFkCode = dao.getDefaultDepBySchool(schoolFkCode);
        if (defaultDepFkCode != null) {
            dao.deleteWorkerDefaultDepartment(workerFkCode, defaultDepFkCode);
        }
    }

原理就是让代码中的查询,插入数据放入同一组事务中,它们会一同提交。当并发请求来临的时候,由于查询和插入数据在同一个事务组,所以事务没提交的时候,再次查询的话,数据库就会让它等待,直到事务提交,这个时候就能查出新的数据了,于是就完成了并发锁的功能。

本文参与?腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-10-08,如有侵权请联系?cloudcommunity@tencent.com 删除

本文分享自 Java深度编程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com