为了账号安全,请及时绑定邮箱和手机立即绑定

在 MySQL 休眠 JPA 事务期间未检测到死锁

在 MySQL 休眠 JPA 事务期间未检测到死锁

绝地无双 2022-08-17 12:25:42
警告!!!TL;DRMySQL 5.6.39  mysql:mysql-connector-java:5.1.27org.hibernate.common:hibernate-commons-annotations:4.0.5.Final  org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final  org.hibernate:hibernate-core:4.3.6.Finalorg.hibernate:hibernate-entitymanager:4.3.6.Final  org.hibernate:hibernate-validator:5.0.3.FinalHTTP 方法: POST, API 路径: /reader实体“阅读器”引擎:innoDBidnametotal_pages_read类映射:@Entity@Table(name = "reader")public class Reader{    @Column(name = "id")    private Long id;    @Column(name = "name")    private String name;    @Column(name = "total_pages_read")    private Long total_pages_read;        @OneToMany(fetch = FetchType.LAZY, mappedBy = "reader", orphanRemoval = true)    private Set<Book_read> book_reads;    ...}我使用方法 createEntity() 并在 Reader write service 类中重新计算 TotaltalPageRead():@Servicepublic class ReaderWritePlatformServiceJpaRepositoryImpl{    private final ReaderRepositoryWrapper readerRepositoryWrapper;       ...    @Transactional    public Long createEntity(final Long id, final String name, final Long total_pages_read){        try {            final Reader reader = new Reader(id, name, total_pages_read);            this.readerRepositoryWrapper.saveAndFlush(reader);            return 1l;        } catch (final Exception e) {            return 0l;        }    }        ...}HTTP 方法: POST, API 路径: /bookread实体“book_read”引擎:innoDBid  reader_id  book_title  number_of_pages 类映射:@Entity@Table(name = "book_read")public class Book_read{    @Column(name = "id")    private Long id;    @ManyToOne(fetch = FetchType.LAZY)    @JoinColumn(name = "reader_id")    private Reader reader;    @Column(name = "book_title")    private String book_title;    @Column(name = "number_of_pages")    private Long number_of_pages;        ...}
查看完整描述

2 回答

?
ITMISS

TA贡献1871条经验 获得超8个赞

您遇到的更新被称为丢失更新,这真的不是JPA级的问题,您可以在MySQL shell中轻松重现此问题。我假设您没有在数据库本身中进行任何更改,因此您的默认事务隔离级别是 。REPEATABLE READ

在MySQL中,不会检测到可能的丢失更新(即使这是此隔离级别的常见理解)。您可以在SO和评论线程上查看此答案以了解更多信息。REPEATABLE READ

基本上,通过使用MVCC,MySQL试图避免争用和死锁。在你的情况下,你将不得不做出权衡,并选择为了一致性而牺牲一些速度。

您可以选择使用语句或设置更严格的隔离级别,即(您可以对单个事务执行此操作)。这两个选项都将阻止读取,直到并发事务提交/回滚。因此,您将在稍晚一点(或更晚,具体取决于应用程序的要求)看到数据的一致视图。SELECT ... FOR UPDATESERIALIZABLE

你也可以在这里,这里这里阅读这个

并发性很难。:)

更新:在考虑了下面的评论之后,您实际上还有另一种选择:为数据模型实现乐观锁定。JPA对此有支持,请看这里这里。您实现的目标基本上是相同的,但是使用稍微不同的方法(您将不得不重新启动未能不匹配版本的事务),并且由于锁定较少,因此争用较少。


查看完整回答
反对 回复 2022-08-17
?
qq_笑_17

TA贡献1818条经验 获得超7个赞

我认为您面临的问题是,FK 关系的属性锁定由关系的拥有方控制。

由于集合是用它注释的,因此它不会控制锁,因此另一端会这样做,这意味着在更新集合时,您将获得两个单独的锁,它们实际上并不能相互识别。book_reads@OneToMany(mappedBy = "reader")

删除和注释应该可以解决这个问题。Book_read.readermappedBy

所有这些实际上都适用于具有版本属性的乐观锁定,这是无论如何都要执行操作的推荐方法。

另请参阅Vlad Mihalcea关于该主题的文章:https://vladmihalcea.com/hibernate-collections-optimistic-locking/


查看完整回答
反对 回复 2022-08-17
  • 2 回答
  • 0 关注
  • 323 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号