本人初学hibernate,今天做级联删除,遇到两个问题。虽然第一个问题已经解决了,但是第二个问题让我调了一晚上。
我从第一个问题开始讲起:
一开始我是用主键做删除,结果总是删除了主表的记录,关联关系的表中只是改了外键值为null;
两张表是Dept和Emp,one-to-many关系
代码和配置大致是这样的:
@Test
public void deleteDept(){
Session session = null;
try {
session = HibernateUtil.getSession();
session.setFlushMode(FlushMode.AUTO);
session.beginTransaction().begin();
Dept dept = new Dept();
dept.setId(1);
session.delete(dept);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtil.close(session);
}
}<set cascade="all" lazy="extra" name="emps" inverse="false">
   <key  column="did"/>
    <one-to-many class="entity.Emp"/>
  </set>这样只能删除一条dept的记录,跟他关联的emp中的外键只是被update成null而已。
后来查到,这是因为session删除时,必须删除一个从数据库中查询返回的Dept对象,不能new一个然后setId。于是我改成
Dept dept = (Dept) session.load(Dept.class, 5);
session.delete(dept);
这样,的确是没问题了。但是,我就是想要只通过一个主键值来做删除操作,要怎么办?我还是在网上搜寻到,说只要增加配置属性on-delete="cascade"就可以了。于是我配置文件改成:
<set cascade="all" lazy="extra" name="emps" inverse="false">
   <key  column="did" on-delete="cascade"/>
    <one-to-many class="entity.Emp"/>
  </set>
结果就报出一个异常,org.hibernate.MappingException: only inverse one-to-many associations may use on-delete="cascade"
具体控制台打印如下:
org.hibernate.MappingException: only inverse one-to-many associations may use on-delete="cascade": entity.Dept.emps
at org.hibernate.mapping.Collection.validate(Collection.java:267)
at org.hibernate.mapping.Set.validate(Set.java:19)
at org.hibernate.cfg.Configuration.validate(Configuration.java:1112)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1293)
at util.HibernateUtil.<clinit>(HibernateUtil.java:14)
at test.testEmp.deleteDept(testEmp.java:102)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:59)
at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:98)
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:79)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:87)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42)
at org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:88)
at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
java.lang.NullPointerException
at util.HibernateUtil.getSession(HibernateUtil.java:22)
at test.testEmp.deleteDept(testEmp.java:102)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:59)
at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:98)
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:79)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:87)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42)
at org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:88)
at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)这个异常让我很不能明白, only inverse one-to-many associations may use on-delete="cascade"
我明明已经配置<one-to-many>啦?!后来我又找到一份org.hibernate.mapping.Collection的源代码,找到了这段抛异常的代码:
public void validate(Mapping mapping) throws MappingException {
 237:           if ( getKey().isCascadeDeleteEnabled() && ( !isInverse() || !isOneToMany() ) ) {
 238:            throw new MappingException(
 239:                "only inverse one-to-many associations may use on-delete=\"cascade\": " 
 240:                + getRole() );
 241:        }
 242:           if ( !getKey().isValid( mapping ) ) {
 243:            throw new MappingException(
 244:                "collection foreign key mapping has wrong number of columns: "
 245:                + getRole()
 246:                + " type: "
 247:                + getKey().getType().getName() );
 248:        }
 249:           if ( !getElement().isValid( mapping ) ) {
 250:            throw new MappingException( 
 251:                "collection element mapping has wrong number of columns: "
 252:                + getRole()
 253:                + " type: "
 254:                + getElement().getType().getName() );
 255:        }我看他的判断语句,if ( getKey().isCascadeDeleteEnabled() && ( !isInverse() || !isOneToMany() ) )
从我的配置来看,on-delete="cascade"-->getKey().isCascadeDeleteEnabled()是ture
                inverse="false" -->  !isInverse() 是true 
好了,这个if语句已经返回true了。于是就throw了这个异常了!我尝试改了 inverse为true,那就等于弃权维护关联关系,那这个时候删除会报异常说是违反外键约束了:
Hibernate: delete from t_dept where d_id=?
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:253)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:266)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:172)
......................
Caused by: java.sql.BatchUpdateException: Cannot delete or update a parent row: a foreign key constraint fails (`tarena/emp_t`, CONSTRAINT `FK5C282BD499E420F` FOREIGN KEY (`did`) REFERENCES `t_dept` (`d_id`))
at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2016)
at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1452)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:246)
... 30 more
如果尝试改掉on-delete,这不就又绕回来了么!请哪位大神帮我看看,到底该怎么配置?!先谢谢了!!hibernate级联