@OnDelete Hibernate 注解不会为 MySql 生成 ON DELETE CASCADE

Posted

技术标签:

【中文标题】@OnDelete Hibernate 注解不会为 MySql 生成 ON DELETE CASCADE【英文标题】:@OnDelete Hibernate annotation does not generate ON DELETE CASCADE for MySql 【发布时间】:2017-05-18 20:44:13 【问题描述】:

我有两个具有单向关系的父子实体

class Parent 
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private Long id;

class Child 
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private Long id;

    @ManyToOne(optional = false)
    @JoinColumn(name = "parent_id")
    @OnDelete(action = OnDeleteAction.CASCADE)
    private Parent parent;

在我配置的application.properties文件中

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.mysql5InnoDBDialect
spring.jpa.database-platform = org.hibernate.dialect.MySQL5InnoDBDialect

但是当我运行应用程序时,会创建以下语句

...
alter table child add constraint FKi62eg01ijyk2kya7eil2gafmx foreign key (parent_id) references parent (id)
...

所以没有应该有的 ON CASCADE DELETE。每次我运行应用程序时都会创建表,并检查方法是否

org.hibernate.dialect.MySQL5InnoDBDialect#supportsCascadeDelete()

真的被称为(它是)。我正在使用 spring-boot-parent 版本 1.4.3,它使用 Hibernate 5.11。有任何想法吗?顺便说一句,我不想​​使用双向关系。

编辑 感谢@AlanHay,我发现我遗漏了一个重要部分。实际上涉及到第三类

class Kindergarten 

    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private Long id;

    @OneToMany(mappedBy = "kindergarten", fetch = FetchType.EAGER)
    @MapKeyJoinColumn(name = "parent_id") // parent_id causes the problem!
    private Map<Parent, Child> children;

和幼儿园的孩子其实是这样的

class Child 

    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private Long id;

    @ManyToOne(optional = false)
    @JoinColumn(name = "parent_id")
    @OnDelete(action = OnDeleteAction.CASCADE)
    private Parent parent;

    @ManyToOne
    @JoinColumn(name = "kindergarten_id")
    private Kindergarten kindergarten;

这就是问题发生的原因。如果您将 MapKeyJoinColumn 注释中的“parent_id”更改为 Child 中不存在的列,例如"map_id" 将 ON DELETE CASCADE 添加到 Child 中的外键 parent_id。如果参数是 Child 的列“parent_id”,则不会附加 ON DELETE CASCADE 部分。不幸的是,我还不清楚其中的原因。更改参数不是选项,因为我想使用指向子对象父级的现有链接。

【问题讨论】:

你不能使用 JPA Cascade.DELETE ***.com/questions/19626535/… 我认为您的意思是 CascadeType.REMOVE。如果您删除父级,这将不起作用。我想要的是,当您删除父级时,所有子级也会被删除。 刚刚检查了来源。 MySQLDialect 覆盖 supportCascadeDelete 以返回 false,这告诉生成器不要将其添加到约束中。您可以向 Hibernate 团队提出拉​​取请求,但他们添加它可能是有原因的。有时语法被列为受支持,然后您会收到“尚未实现”错误。它发生在我试图在 Oracle 11g 数据库中使用数组时。谁知道从哪个版本开始它实际工作。 除了检查方言属性外,org.hibernate.tool.schema.internal.StandardForeignKeyExporter.getSqlCreateStrings(ForeignKey, Metadata) 中还有一个额外的检查,如果第二个条件为真,它只会附加“删除级联”。您可以在此处设置断点并回溯以查看未附加的原因。查看源代码应该是正确的,但是如果 @OnDelete(action = OnDeleteAction.CASCADE) 设置为您所拥有的。见org.hibernate.cfg.AnnotationBinder.processElementAnnotations(...) 我已经针对 MySQL5 进行了测试,当且仅当它是单向的 @ManyToOne 关系时,它才能正常工作,而你说你有。 MySQL5InnoDBDialect 肯定会被选中吗?您设置的属性是 Spring Boot 特定的。这是一个 Spring Boot 项目,因为您的问题没有用 Spring Boot 标记? 【参考方案1】:

可能有点晚了,但因为它是搜索“休眠 ondelete 生成级联”时的热门帖子之一:

由于某种原因,将 @OnDelete 放在 Mysql 的 ManyToOne 端对我不起作用,但它在 OneToMany 端起作用。所以如果你运气不好,就换另一边试试吧。

【讨论】:

哇,好神奇。谢谢。要么是错误,要么文档有误:docs.jboss.org/hibernate/orm/current/userguide/html_single/…【参考方案2】:

就我而言,我还必须将@OnDelete 放在OneToMany 一侧,旁边我还必须更改JpaVendorAdapter bean 方法。它返回的适配器必须设置为org.hibernate.dialect.MySQL5InnoDBDialect,如下所示:

adapter.setDatabasePlatform("org.hibernate.dialect.MySQL5InnoDBDialect");

【讨论】:

以上是关于@OnDelete Hibernate 注解不会为 MySql 生成 ON DELETE CASCADE的主要内容,如果未能解决你的问题,请参考以下文章

onDelete 附加到 ForEach 但没有滑动手势

java hibernate注解映射类的字段可以和数据库中的字段不一致吗

Hibernate学习 —— 抓取策略(注解方式)

Hibernate注解开发(未完待续)

hibernate validation内置注解及自定义注解

如何在一对一关系中使用 onDelete: 'CASCADE'