首页 > 解决方案 > 一对多和删除级联表约束

问题描述

我在帐户和交易之间有一个双向的一对多:

@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)

标签: hibernatejpacascade

解决方案


  1. 在关系上启用休眠特定的@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<>();

  1. 即使 hibernate 没有管理我的 DDL,仍然需要 @OnDelete:
spring.jpa.hibernate.ddl-auto=none
  1. 如果您使用的是 MySQL(我愿意!),请确保您的存储引擎是 InnoDB,它支持外键上的 ON DELETE CASCADE。

推荐阅读