一对多和级联表的删除限制

问题描述 投票:0回答:1

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

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

但是,当删除一个 "账户 "记录时 为什么hibernate会逐一删除相关的 "事务 "记录呢?

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]

我以为hibernate会跳过删除 "transaction",因为我没有在account -> transactions关系上指定CascadeType.REMOVE。什么情况?

(添加CascadeType.REMOVE也触发了同一组SQL)

hibernate jpa cascade
1个回答
0
投票
  1. 在关系上启用hibernate特定的@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。
© www.soinside.com 2019 - 2024. All rights reserved.