java - JPA 两个事务更新相同的行

标签 java mysql jpa concurrency transactions

我在 SpringBoot 应用程序中使用 JPA 存储库,我有一个后台任务,定期将数据库中的某些元素设置为“就绪” 我还有一个端点,用户可以调用该端点,并且可以修改同一表的行之一。

有没有办法避免一个又一个取消对方的写入?以这个场景为例

Table: 
Key
id     name      is_ready

0) 初始数据有一个键 (1 no_name false)

1)后台任务启动,即将通过设置修改表Key

is_ready to true
Key key = repo.findKeyByIsReady(false)
key.setIsReady(true)
repo.save(key) <--- does NOT yet execute this

2) 用户调用 api 端点将 key 名称更改为“new_name”并完成

3)现在后台服务执行repo.save(key),最终数据为

1    no_name   true 

而不是

1    new_name   true

基本上后台任务已经覆盖了用户设置的键名

有没有办法避免这种情况发生?交易在这里有何帮助?

最佳答案

这通常可以通过额外的锁来解决:

乐观锁

您在第二个事务中检测到该行已被其他人更改。然后,您要么告诉用户并要求手动修复,要么尝试自动合并更改。

要实现它,您必须向表中添加附加列 - 版本。然后,当更新行时,查询将如下所示:

UPDATE ..., version=old_version+1 WHERE id=old_id and version=old_version

如果 WHERE close 找不到该行(因为其他人增加了版本),则更改的行数将为 0(JDBC 从数据库获取此信息)并且 JPA 将抛出错误在这种情况下。

附加字段必须在 JPA 中映射为 @Version

悲观锁

每次更新实体时,您都会使用构造:

select ... for update

当第二个事务发出此类语句时,数据库会锁定该请求,直到第一个事务完成。如果在特定时间段内没有发生这种情况,您会收到 JPA 的异常。请参阅 EntityManager#lock() 方法了解更多信息。

关于java - JPA 两个事务更新相同的行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45544248/

相关文章:

java - 如何在 liquibase 变更集中设置多个外键?

JPA/Hibernate 和复合键

java - Spring Boot 测试数据库初始化运行两次

java - 关于如何在 java 中为任何通用对象实现自定义哈希函数有什么想法吗?

java - 如何去除字符串中除第一个字符以外的所有非数字?

java - 添加 keyListener 来模拟鼠标单击链接,页面是使用 Javax jspx servlet 制作的。 getElementById 返回 null

mysql - 显示列数相等的两个表中的记录

php - 单击按钮删除 sql 表中的行时出错

java - 我对 Web 应用程序架构有正确的理解吗? HTML5 前端、Java 后端和 JSON 绑定(bind)

c# - 发生异常 .. 关键字 'Table' 附近的语法不正确