【问题标题】:Using PostgreSQL, why doesn't Hibernate/JPA create cascade constraints?使用 PostgreSQL,为什么 Hibernate/JPA 不创建级联约束?
【发布时间】:2012-04-10 20:22:22
【问题描述】:

我有一个实体Bar

@OneToMany(cascade = CascadeType.ALL, mappedBy = "bar")
private Set<Foo> fooSet;

还有一个实体Foo

@ManyToOne(optional = false)
@JoinColumn(name = "bar_id")
private Bar bar;

Hibernate 在 foo.bar -> bar.id 上创建外键约束,但它没有指定 ON DELETE CASCADE。为什么不?有什么方法可以实现吗?

或者,我可以在数据库中手动添加ON DELETE CASCADE(并禁用 DDL 生成),这是一个好习惯吗?而且,我是否必须以某种方式修改我的代码才能让Hibernate知道相关记录会被数据库自动删除吗?

谢谢。

更新 - 这是我的 JPA/Hibernate/PostgreSQL 配置:

<bean id="dataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
    <constructor-arg>
        <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="org.postgresql.Driver" />
            <property name="url" value="jdbc:postgresql://localhost:5432/my_db" />
            <property name="username" value="my_username" />
            <property name="password" value="my_password" />
        </bean>
    </constructor-arg>
</bean>
<bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    <property name="databasePlatform" value="org.hibernate.dialect.PostgreSQLDialect" />
    <property name="showSql" value="true" />
    <property name="generateDdl" value="true" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="jpaVendorAdapter" ref="jpaAdapter" />
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.format_sql">true</prop>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
        </props>
    </property>
    <property name="dataSource" ref="dataSource" />
</bean>

更新 2 - 澄清了我的意思:创建了外键约束,但我想知道为什么它没有指定 ON DELETE CASCADE(相应地更改了原始问题)

【问题讨论】:

  • 您是否告诉 Hibernate 为您创建/更新数据库架构?
  • 你好@Thomas,是的,我做到了。请查看更新后的问题以查看 JPA/Hibernate/PostgreSQL 配置。谢谢!

标签: java hibernate postgresql jpa foreign-keys


【解决方案1】:

Hibernate 自己手动管理级联操作。更重要的是,如果您在数据库上进行级联,而不是在 Hibernate 中声明它们(出于性能问题),在某些情况下您可能会出错。这是因为 Hibernate 将实体存储在其会话缓存中,因此它不会知道数据库在级联中删除某些内容。

当你使用二级缓存时,你的情况会更糟,因为这个缓存的寿命比 session 长,而且只要旧值存储在这个缓存中,db-side 上的这种变化对其他 session 是不可见的。

我已经阅读了一些 Hibernate 资料(真的很不愉快),我怀疑在任何情况下都可以在数据库端管理级联 - Hibernate 设计做出了太多与 DB 现实不兼容的假设。

【讨论】:

  • 谢谢@lechlukasz,我会让 Hibernate 管理级联!
  • 很公平。问题是,如果我在两边都设置了级联并删除了一些实体,会发生什么。 JPA/Hibernate 是否检测到 DB 端的级联并清理他的对象?还是使用多个 DELETE 语句继续执行,这会成功(删除 0 行)但会浪费一些时间?我对性能方面特别感兴趣。
【解决方案2】:

使用

 cascade = CascadeType.ALL

如果你执行任何操作,会导致hibernate遍历这个关系。它不会影响生成的 DLL。

如果要删除 fooSet 中的所有实体,请添加 orphanRemoval 属性。

@OneToMany(cascade = CascadeType.ALL, mappedBy = "bar", orphanRemoval=true)

也使用

<property name="generateDdl" value="true" />

仅适用于开发环境。不要将其用于生产。 (例如,如果您重命名一个属性/列将创建另一列,甚至可能删除前一列,那么休眠不知道如何更改表架构。

【讨论】:

  • 谢谢@franthartm。是的,我知道这一点。我想知道为什么 Hibernate 默认情况下不允许 PostgreSQL 管理级联(当然它的性能要高得多)。或者有没有办法实现?
  • 4 年后,我遇到了这个问题,并通过让 Postgres 处理级联将 CASCADE 子句添加到 FK 来解决它。
猜你喜欢
  • 2012-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-16
  • 1970-01-01
相关资源
最近更新 更多