ReentrantLock锁不起作用

发布于 2022-09-01 17:15:29 字数 9983 浏览 83 评论 0

插入数据之前需要先检查数据库中没有了才插入,没加锁之前发现如果两次添加请求很接近会出现重复插入情况,所以添加了一个ReentrantLock锁,但是实际使用发现还是会出现重复插入。
锁添加在Spring 的 Controller 里:

@RestController
@RequestMapping("/user")
public class UserAction {
    Lock lock = new ReentrantLock();
    
    @RequestMapping(value = "add", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    @ResponseBody
    public ResponseEntity addUser(User user) {
        lock.lock();
        try {
            //检查数据库是否已有用户 没有的话才加入
            //代码略
        } finally {
            lock.unlock();
        }
    }

问题补充:

根据回答又本地做了实验:

Lock lock = new ReentrantLock();
public Integer insertLock(String code) {
        lock.lock();
        try {
            System.out.println("get lock: " + lock.hashCode());
            //检查数据库是否已经有此code数据
            if (lockCheck(code)) return 0;

            QSCategory qsCategory = new QSCategory();

            qsCategory.setCode(code);
            
            qsCategory.setAdvice("1");
            qsCategory.setCreationDate(DateUtil.nowDatetime());
            qsCategory.setParentCode("1");
            qsCategory.setCreationUser("1");
            qsCategory.setStatus(0);
            qsCategory.setTitle("1");
            qsCategoryMapper.insert(qsCategory);
            return qsCategory.getId();
        } finally {
            System.out.println("release lock: " + lock.hashCode());
            lock.unlock();
        }
    }

输出日志:

get lock: 1031529608
16:18:00.585 [btpool0-4] DEBUG c.b.j.c.d.m.Q.selectByExample - ==>  Preparing: select Id, ParentCode, Code, Title, Status, CreationDate, CreationUser, ModificationDate, ModificaitonUser from TB_QS_Category WHERE ( Code = ? ) 
16:18:00.585 [btpool0-4] DEBUG c.b.j.c.d.m.Q.selectByExample - ==>  Preparing: select Id, ParentCode, Code, Title, Status, CreationDate, CreationUser, ModificationDate, ModificaitonUser from TB_QS_Category WHERE ( Code = ? ) 
16:18:00.603 [btpool0-4] DEBUG c.b.j.c.d.m.Q.selectByExample - ==> Parameters: cyh(String)
16:18:00.603 [btpool0-4] DEBUG c.b.j.c.d.m.Q.selectByExample - ==> Parameters: cyh(String)
16:18:00.624 [btpool0-4] DEBUG c.b.j.c.d.m.Q.selectByExample - <==      Total: 0
16:18:00.624 [btpool0-4] DEBUG c.b.j.c.d.m.Q.selectByExample - <==      Total: 0
16:18:00.630 [btpool0-4] DEBUG c.b.j.c.d.m.QSCategoryMapper.insert - ==>  Preparing: insert into TB_QS_Category (Id, ParentCode, Code, Title, Status, CreationDate, CreationUser, ModificationDate, ModificaitonUser, Advice) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 
16:18:00.630 [btpool0-4] DEBUG c.b.j.c.d.m.QSCategoryMapper.insert - ==>  Preparing: insert into TB_QS_Category (Id, ParentCode, Code, Title, Status, CreationDate, CreationUser, ModificationDate, ModificaitonUser, Advice) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 
16:18:00.636 [btpool0-4] DEBUG c.b.j.c.d.m.QSCategoryMapper.insert - ==> Parameters: null, 1(String), cyh(String), 1(String), 0(Integer), 2015-09-02 16:18:00.0(Timestamp), 1(String), null, null, java.io.StringReader@1caa2881(StringReader)
16:18:00.636 [btpool0-4] DEBUG c.b.j.c.d.m.QSCategoryMapper.insert - ==> Parameters: null, 1(String), cyh(String), 1(String), 0(Integer), 2015-09-02 16:18:00.0(Timestamp), 1(String), null, null, java.io.StringReader@1caa2881(StringReader)
16:18:00.637 [btpool0-4] DEBUG c.b.j.c.d.m.QSCategoryMapper.insert - <==    Updates: 1
16:18:00.637 [btpool0-4] DEBUG c.b.j.c.d.m.QSCategoryMapper.insert - <==    Updates: 1
16:18:00.637 [btpool0-4] DEBUG c.b.j.c.d.m.Q.insert!selectKey - ==>  Preparing: SELECT LAST_INSERT_ID(); 
16:18:00.637 [btpool0-4] DEBUG c.b.j.c.d.m.Q.insert!selectKey - ==>  Preparing: SELECT LAST_INSERT_ID(); 
16:18:00.637 [btpool0-4] DEBUG c.b.j.c.d.m.Q.insert!selectKey - ==> Parameters: 
16:18:00.637 [btpool0-4] DEBUG c.b.j.c.d.m.Q.insert!selectKey - ==> Parameters: 
16:18:00.640 [btpool0-4] DEBUG c.b.j.c.d.m.Q.insert!selectKey - <==      Total: 1
16:18:00.640 [btpool0-4] DEBUG c.b.j.c.d.m.Q.insert!selectKey - <==      Total: 1
release lock: 1031529608
get lock: 1031529608
16:18:00.644 [btpool0-3] DEBUG c.b.j.c.d.m.Q.selectByExample - ==>  Preparing: select Id, ParentCode, Code, Title, Status, CreationDate, CreationUser, ModificationDate, ModificaitonUser from TB_QS_Category WHERE ( Code = ? ) 
16:18:00.644 [btpool0-3] DEBUG c.b.j.c.d.m.Q.selectByExample - ==>  Preparing: select Id, ParentCode, Code, Title, Status, CreationDate, CreationUser, ModificationDate, ModificaitonUser from TB_QS_Category WHERE ( Code = ? ) 
16:18:00.645 [btpool0-3] DEBUG c.b.j.c.d.m.Q.selectByExample - ==> Parameters: cyh(String)
16:18:00.645 [btpool0-3] DEBUG c.b.j.c.d.m.Q.selectByExample - ==> Parameters: cyh(String)
16:18:00.647 [btpool0-3] DEBUG c.b.j.c.d.m.Q.selectByExample - <==      Total: 0
16:18:00.647 [btpool0-3] DEBUG c.b.j.c.d.m.Q.selectByExample - <==      Total: 0
16:18:00.647 [btpool0-3] DEBUG c.b.j.c.d.m.QSCategoryMapper.insert - ==>  Preparing: insert into TB_QS_Category (Id, ParentCode, Code, Title, Status, CreationDate, CreationUser, ModificationDate, ModificaitonUser, Advice) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 
16:18:00.647 [btpool0-3] DEBUG c.b.j.c.d.m.QSCategoryMapper.insert - ==>  Preparing: insert into TB_QS_Category (Id, ParentCode, Code, Title, Status, CreationDate, CreationUser, ModificationDate, ModificaitonUser, Advice) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 
16:18:00.648 [btpool0-3] DEBUG c.b.j.c.d.m.QSCategoryMapper.insert - ==> Parameters: null, 1(String), cyh(String), 1(String), 0(Integer), 2015-09-02 16:18:00.0(Timestamp), 1(String), null, null, java.io.StringReader@36386935(StringReader)
16:18:00.648 [btpool0-3] DEBUG c.b.j.c.d.m.QSCategoryMapper.insert - ==> Parameters: null, 1(String), cyh(String), 1(String), 0(Integer), 2015-09-02 16:18:00.0(Timestamp), 1(String), null, null, java.io.StringReader@36386935(StringReader)
16:18:00.855 [btpool0-3] INFO  o.s.b.f.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
16:18:00.895 [btpool0-3] INFO  o.s.j.support.SQLErrorCodesFactory - SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase]
release lock: 1031529608
get lock: 1031529608
16:18:00.898 [btpool0-5] DEBUG c.b.j.c.d.m.Q.selectByExample - ==>  Preparing: select Id, ParentCode, Code, Title, Status, CreationDate, CreationUser, ModificationDate, ModificaitonUser from TB_QS_Category WHERE ( Code = ? ) 
16:18:00.898 [btpool0-5] DEBUG c.b.j.c.d.m.Q.selectByExample - ==>  Preparing: select Id, ParentCode, Code, Title, Status, CreationDate, CreationUser, ModificationDate, ModificaitonUser from TB_QS_Category WHERE ( Code = ? ) 
16:18:00.903 [btpool0-5] DEBUG c.b.j.c.d.m.Q.selectByExample - ==> Parameters: cyh(String)
16:18:00.903 [btpool0-5] DEBUG c.b.j.c.d.m.Q.selectByExample - ==> Parameters: cyh(String)
16:18:00.906 [btpool0-5] DEBUG c.b.j.c.d.m.Q.selectByExample - <==      Total: 1
16:18:00.906 [btpool0-5] DEBUG c.b.j.c.d.m.Q.selectByExample - <==      Total: 1
release lock: 1031529608
get lock: 1031529608
16:18:00.907 [btpool0-0] DEBUG c.b.j.c.d.m.Q.selectByExample - ==>  Preparing: select Id, ParentCode, Code, Title, Status, CreationDate, CreationUser, ModificationDate, ModificaitonUser from TB_QS_Category WHERE ( Code = ? ) 
16:18:00.907 [btpool0-0] DEBUG c.b.j.c.d.m.Q.selectByExample - ==>  Preparing: select Id, ParentCode, Code, Title, Status, CreationDate, CreationUser, ModificationDate, ModificaitonUser from TB_QS_Category WHERE ( Code = ? ) 
16:18:00.909 [btpool0-0] DEBUG c.b.j.c.d.m.Q.selectByExample - ==> Parameters: cyh(String)
16:18:00.909 [btpool0-0] DEBUG c.b.j.c.d.m.Q.selectByExample - ==> Parameters: cyh(String)
16:18:00.911 [btpool0-0] DEBUG c.b.j.c.d.m.Q.selectByExample - <==      Total: 1
16:18:00.911 [btpool0-0] DEBUG c.b.j.c.d.m.Q.selectByExample - <==      Total: 1
release lock: 1031529608
get lock: 1031529608
16:18:00.913 [btpool0-2] DEBUG c.b.j.c.d.m.Q.selectByExample - ==>  Preparing: select Id, ParentCode, Code, Title, Status, CreationDate, CreationUser, ModificationDate, ModificaitonUser from TB_QS_Category WHERE ( Code = ? ) 
16:18:00.913 [btpool0-2] DEBUG c.b.j.c.d.m.Q.selectByExample - ==>  Preparing: select Id, ParentCode, Code, Title, Status, CreationDate, CreationUser, ModificationDate, ModificaitonUser from TB_QS_Category WHERE ( Code = ? ) 
16:18:00.913 [btpool0-2] DEBUG c.b.j.c.d.m.Q.selectByExample - ==> Parameters: cyh(String)
16:18:00.913 [btpool0-2] DEBUG c.b.j.c.d.m.Q.selectByExample - ==> Parameters: cyh(String)
16:18:00.916 [btpool0-2] DEBUG c.b.j.c.d.m.Q.selectByExample - <==      Total: 1
16:18:00.916 [btpool0-2] DEBUG c.b.j.c.d.m.Q.selectByExample - <==      Total: 1
release lock: 1031529608
16:18:00.991 [btpool0-3] INFO  c.b.j.c.s.e.RestExceptionHandler - 
### Error updating database.  Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'cyh' for key 'Code'
### The error may involve com.bocean.jkyzx.common.dao.mapper.QSCategoryMapper.insert-Inline
### The error occurred while setting parameters
### SQL: insert into TB_QS_Category (Id, ParentCode, Code,        Title, Status, CreationDate,        CreationUser, ModificationDate, ModificaitonUser,        Advice)     values (?, ?, ?,        ?, ?, ?,        ?, ?, ?,        ?)
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'cyh' for key 'Code'
; SQL []; Duplicate entry 'cyh' for key 'Code'; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'cyh' for key 'Code'
org.springframework.dao.DuplicateKeyException: 

同时5个http请求会产生5个线程,发现ReentrantLock其实是有效的,每个线程在加锁区域是同步的,但是第一个线程释放锁时候,数据还是没有完全插入进去,之后的线程查询不到就重复插入,出现这个的原因是什么?如何解决?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

忆依然 2022-09-08 17:15:29

是不是集群部署?两次请求落在了不同的机器上?
java程序级别的锁是没办法约束集群的情况的;
最终的可靠方案还是需要唯一性主键约束以及设置数据库的事务隔离级别

update:
也有可能是UserAction这个类不是单例,你看看spring mvc是否每次请求都会重新创建一个UserAction实例,这样会导致Lock也被重新创建,那么多个请求使用的其实不是同一个lock,这样就看上去没用了;

可以考虑把这个Lock放在一个更全局的地方

笑饮青盏花 2022-09-08 17:15:29

没用过spring mvc,不过你的action每次是不是一个新的实例?如果是的话那每个请求的lock是不同的,有怎会生效,所以每次打印下lock的hashcode看看是不是同一个对象,不是的话加个static吧

update

恩,第二次的cyh查询是0,看起来像事务问题,但没道理0_0,你的插入用delayed了吗,myisam还是innodb?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文