【问题标题】:JPA: manually increment, avoid race condition (MySQL)JPA:手动递增,避免竞争条件(MySQL)
【发布时间】:2013-05-16 15:57:54
【问题描述】:

我认为我有一个相当简单的任务,即在根据某些条件向表中添加新记录时手动递增 ID。

假设我有表 Book 和 Chapter。 Chapter 具有自动递增的 ChapterId、BookId 的外键和 ChapterNo。每次我向书中添加章节时,我都希望 ChapterNo 为该章节所属的特定书籍增加一。

可以通过简单的SQL语句来完成:插入章节(BookId, ChapterNo)值(XXX, select max(ChapterNo) + 1 from chapter where BookId = XXX)。但是有没有办法在 JPA 中做到这一点并避免竞争条件(如果我先阅读 max ChapterNo 然后插入,就会发生这种情况)

更新:到目前为止我想出的唯一合理的解决方案:实现负责递增 ChapterNo 的 DB 触发器。那么至少我在 JPA 端不需要任何本机查询

【问题讨论】:

  • 我认为您应该能够通过使用事务和悲观锁定来防止其他人同时插入一章来做到这一点。我知道 JPA 支持悲观锁定,但我不知道细节。

标签: mysql jpa race-condition


【解决方案1】:

也许它不是完整的解决方案,但有一个带有 @OrderColumn 注释的 JPA 功能。

本质上,您使用列表实现@OneToMany 关系,JPA 会将列表中元素的顺序保存在数据库的列中。应用于本书和章节,它会是这样的:

@Entity
public class Book
{
    ...
    @OneToMany(mappedBy="book")
    @OrderColumn(name="chapterNo")
    private List<Chapter> chapters;
    ...
}

但请注意,如果列表中的某些元素发生更改,这可能会导致订单列的许多更新。例如,如果您删除第一章然后持久化该书,则所有其他章节都将更新以反映它们在列表中的新位置。此外,您无法直接访问 chapterNo 在查询中使用的列,只能通过列表索引进行隐式访问。

【讨论】:

  • 这很有趣,谢谢!使用这种方法,是否可以重新排序列表?即如果我希望第 1 章变成第 2 章,反之亦然?
  • 是的,如果你在内存中重新排序列表,在事务提交的那一刻,它会使用新值更新 order 列
猜你喜欢
  • 1970-01-01
  • 2015-01-30
  • 2010-09-25
  • 1970-01-01
  • 2019-05-03
  • 1970-01-01
  • 1970-01-01
  • 2010-09-25
  • 2019-06-12
相关资源
最近更新 更多