我有一个实体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上创建外键约束 - &gt; 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
(相应地更改了原始问题)
答案 0 :(得分:5)
Hibernate手动管理级联操作。更重要的是,如果你要在数据库上进行级联,而不是在Hibernate中声明它们(对于性能问题),在某些情况下你可能会遇到错误。这是因为Hibernate将实体存储在其会话缓存中,因此它不会知道数据库是否会级联删除。
当您使用二级缓存时,您的情况会更糟,因为此缓存的持续时间比会话长,并且db-side上的此类更改对于其他会话将是不可见的,因为旧的值存储在此缓存中。
我已经阅读了一些Hibernate资源(非常不愉快的经历),我怀疑在任何情况下都可以在数据库端管理级联 - Hibernate设计做出的太多假设与数据库现实不兼容。
答案 1 :(得分:1)
使用
cascade = CascadeType.ALL
如果执行任何操作,会导致hibernate遍历此关系。它不会影响生成的DLL。
如果要删除fooSet中的所有实体,请添加orphanRemoval属性。
@OneToMany(cascade = CascadeType.ALL, mappedBy = "bar", orphanRemoval=true)
也使用
<property name="generateDdl" value="true" />
仅适用于开发环境。不要将它用于生产。 (例如,如果你重命名一个属性/列,那么hibernate就不知道如何更改表模式,而是创建另一个列,甚至可能删除前一个列。)