首页 > 解决方案 > Spring JDBC 应用程序中的 SELECT FOR UPDATE 问题

问题描述

我正在使用SELECT ... FOR UPDATE语句在我的 SpringBoot 应用程序中实现行级锁定。数据库:MySQL 5.7.28,连接器 - MariaDb java 客户端 2.5.2,连接池 HikariCP 2.7.9,spring boot 版本 - 2.0.3 Release。

持久性是由 Spring JDBC Template 完成的,而不是由 JPA 完成的。我正在使用 Spring Transaction 管理,通过@Transactional在我的 DAO 方法上添加注释来进行注释。事务代理是通过 AspectJ 编译时编织 ( @EnableTransactionManagement(mode = AdviceMode.ASPECTJ)) 生成的。我确信事务管理器配置正确。

我已经编写了几个集成测试,这些测试将验证当多个线程竞争更新同一行时出现竞争条件的可能性,该行应该被锁定SELECT ... FOR UPDATE

现在,测试在 95% 的情况下都有效,但是,当执行特定的 IT 序列时,有一个测试会失败。

我确信当测试失败时,不会强加行锁。

我已在服务器上启用 MySql 查询日志以帮助进行故障排除。

这是我在第一个线程执行SELECT ... FOR UPDATE语句时看到的:

2020-01-26T12:54:06.681319Z  1219 Query set autocommit=0
2020-01-26T12:54:36.616097Z  1209 Query SELECT _listed_fields_ FROM _my_table_ WHERE id IN ('19qix6lvsfx') FOR UPDATE

似乎自动提交设置在错误的连接对象上。我读对了吗?这些数字1219和是1209什么?

当一切正常时,日志如下所示:

2020-01-26T13:24:22.940787Z  1243 Query set autocommit=0
2020-01-26T13:24:36.515016Z  1243 Query SELECT _listed_fields_ FROM _my_table_ WHERE id IN ('19xbs7vv53r') FOR UPDATE

任何帮助将不胜感激。

标签: mysqlspring-bootmariadbspring-jdbcspring-transactions

解决方案


我不喜欢autocommit=0,因为我COMMIT最终可能会忘记。

SELECT ... FOR UPDATE仅在您处于事务中时适用(autocommit=0 表示您始终处于事务中)。

您的一般日志片段暗示所有连接都在设置该值,也许是重复的。不,每个连接不受其他连接设置的影响。

您在日志中看到任何 COMMIT 吗?你曾经发出 ROLLBACK 吗?


推荐阅读