hibernate - 一对多和删除级联表约束
问题描述
我在帐户和交易之间有一个双向的一对多:
@Entity
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy = "account", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private List<Transaction> transactions = new ArrayList<>();
...
}
@Entity
public class Transaction {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull
@ManyToOne
@JoinColumn(name = "ACCOUNT_ID")
private Account account;
...
}
外键定义了 ON DELETE CASCADE 约束:
alter table transaction
add constraint FK6
foreign key (account_id)
references account(id) on delete cascade;
但是,当删除“帐户”记录时,为什么休眠会一一删除相关的“交易”记录:
acidTest(entityManager -> {
Account _account = entityManager.find(Account.class, pk);
assertThat(_account.getTransactions().size(), is(2));
});
acidTest(entityManager -> {
Account account = entityManager.find(Account.class, 1L);
entityManager.remove(account);
});
日志:
09:17:56.216 [main] DEBUG c.l.hibernate.JPATxBoundedTest - [TX: begin -->
Hibernate:
select
account0_.id as id1_0_0_,
...
from
account account0_
where
account0_.id=?
09:17:56.223 [main] TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [1] as [BIGINT] - [5]
Hibernate:
select
transactio0_.account_id as account_4_14_0_,
transactio0_.id as id1_14_0_,
...
from
transaction transactio0_
where
transactio0_.account_id=?
09:17:56.230 [main] TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [1] as [BIGINT] - [5]
Hibernate:
delete from transaction where id=?
09:17:56.241 [main] TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [1] as [BIGINT] - [14]
Hibernate:
delete from transaction where id=?
09:17:56.245 [main] TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [1] as [BIGINT] - [16]
Hibernate:
delete from account where id=?
09:17:56.249 [main] TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [1] as [BIGINT] - [5]
09:17:56.260 [main] DEBUG c.l.hibernate.JPATxBoundedTest - <-- end: TX]
我希望休眠跳过删除“事务”,因为我没有在帐户-> 事务关系上指定 CascadeType.REMOVE。是什么赋予了?
(添加 CascadeType.REMOVE 也触发了同一组 SQL)
解决方案
- 在关系上启用休眠特定的@OnDelete
@OneToMany(mappedBy = "account", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@org.hibernate.annotations.OnDelete(
action = org.hibernate.annotations.OnDeleteAction.CASCADE)
private List<Transaction> transactions = new ArrayList<>();
- 即使 hibernate 没有管理我的 DDL,仍然需要 @OnDelete:
spring.jpa.hibernate.ddl-auto=none
- 如果您使用的是 MySQL(我愿意!),请确保您的存储引擎是 InnoDB,它支持外键上的 ON DELETE CASCADE。
推荐阅读
- sql - SQL - 返回不同的行,其中 1 列值用作不同的标识符
- c++ - 在 VC++ 中对 C++ 字符串对象使用 malloc() 时出现问题,但 new 没有问题
- css - css - flexbox 继承父宽度,尽管 align-items: flex-start, justify-content: flex-start
- outlook - 将 Outlook 365 与 VB6 一起使用
- linux - Vim 的行为在保存文件时有所不同
- linux - 更改 Linux 帧缓冲区的分辨率
- xml - 用python解析xml(查找带有特定文本的标签)
- javascript - 从s3获取后如何在浏览器中播放视频文件?
- triggers - H2 - 无法在“插入后”触发器中写入数据库
- android - 使用 Firebase 函数将实时数据库中的数据发送到电子邮件