hibernate级联删除问题
有用户和用户组两个表,需要使用hibernate做级联删除。映射文件如下:
Groups.hbm.xml
<class name="com.cms.entity.Groups" table="groups" catalog="cms"> <id name="id" type="java.lang.Integer"> <column name="id" /> <generator class="native"></generator> </id> <property name="name" type="java.lang.String"> <column name="name" length="100" not-null="true" /> </property> <property name="description" type="java.lang.String"> <column name="description" length="500" /> </property> <property name="authority" type="java.lang.String"> <column name="authority" length="200" /> </property> <set name="users" inverse="true" lazy="false" cascade="all-delete-orphan"> <key> <column name="group_id" not-null="true" /> </key> <one-to-many class="com.cms.entity.User" /> </set> </class>
User.hbm.xml
<hibernate-mapping> <class name="com.cms.entity.User" table="user" catalog="cms"> <id name="id" type="java.lang.Integer"> <column name="id" /> <generator class="native"></generator> </id> <many-to-one name="groups" class="com.cms.entity.Groups" fetch="select"> <column name="group_id" not-null="true" /> </many-to-one> <property name="name" type="java.lang.String"> <column name="name" length="50" not-null="true" /> </property> <property name="password" type="java.lang.String"> <column name="password" length="200" not-null="true" /> </property> <property name="qq" type="java.lang.String"> <column name="qq" length="50" /> </property> <property name="phone" type="java.lang.String"> <column name="phone" length="50" /> </property> <property name="postDate" type="java.util.Date"> <column name="post_date" length="0" not-null="true" /> </property> <set name="articles" inverse="true" cascade="all-delete-orphan"> <key> <column name="user_id" not-null="true" /> </key> <one-to-many class="com.cms.entity.Article" /> </set> </class> </hibernate-mapping>
原本要做的是,删除用户组时将其下所属的用户全部删除;删除用户时,不对用户组进行更改。
结果过执行报错:deleted object would be re-saved by cascade (removedeleted object from associations)
感觉可能是cascade的配置问题,修改了下发现还是报错。后来我将Groups映射文件中<set>元素的lazy属性设置为true。删除成功!但是这样由于是延迟加载,就没法在页面中通过groups来获取User集合中的对象了(本来是想统计用户组中用户成员的个数)。于是还得修改。
查了文档弄明白了怎么回事。
原来cascade属性在lazy=true的时候不起作用(集合中对象还没初始化)。所以在删除User的时候,就不会触发对关联关系的维护。
而当lazy=false的时候,由于我们设置了cascade,那么删除User的时候会触发关系维护,此时虽然在user中已经将对应的Groups属性设置为null(删除前会先将外键设置为null)。但是由于Groups中的Set中仍然还保持着我们删除的User对象,所以触发关系维护的时候,这个User对象又会被重新保存到数据库中。造成了前面出现的异常。
当然,如果我们删除Groups的时候,如果没有将Set的cascade设置为all或delete,那么就会报错: Cannot delete or update a parent row:a foreign key constraint fails,因为groups删除了,User中对groups的外键引用怎么办?
解决的办法就是,如果不需要在groups中直接获取Set中的User对象,那么就把lazy设置为true就可以了。不设置cascade也可以,不过删除groups的时候就可能有问题了。或者通过代码,在删除之前将关联关系解除。
public void delete(User entity) { entity.getGroups().getUsers().remove(entity); entity.setGroups(null); userDao.delete(entity); }