zoukankan      html  css  js  c++  java
  • hibernate 级联删除报更新失败的问题(org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update)

    首先hibernate级联删除的前提是,首先需要在映射文件中配置,配置多表之间的关联关系:

    下面以部门表(Dept)和员工表(Emp)为例:

    1.在Emp.hbm.xml映射文件中配置many-to-one关系

     1 <?xml version="1.0"?>
     2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
     3                                    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
     4 <hibernate-mapping>
     5  <class dynamic-update="true" name="entity.Emp" schema="ACCP" table="EMP">
     6   <id column="EMPNO" name="empNo" type="java.lang.String" length="20">
     7    <generator class="assigned"></generator>
     8   </id>
     9   <property name="empName" column="EMPNAME" type="java.lang.String" not-null="true"/>
    10   <many-to-one name="dept" class="entity.Dept">
    11       <column name="DEPTNO" />
    12   </many-to-one>
    13  </class>
    14 </hibernate-mapping>

    2.在Dept.hbm.xml映射文件中配置one-to-many关系

     1 <?xml version="1.0"?>
     2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
     3                                    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
     4 <hibernate-mapping>
     5  <class dynamic-update="true" name="entity.Dept" schema="ACCP" table="DEPT">
     6   <id column="DEPTNO" name="deptNo" type="java.lang.String" length="20">
     7    <generator class="assigned"></generator>
     8   </id>
     9   <property name="deptName" column="DEPTNAME" type="java.lang.String" />
    10   <property name="location" column="LOCATION" type="java.lang.String"  />
    11   <set name="emps" cascade="all">
    12       <key column="DEPTNO" />
    13       <one-to-many class="entity.Emp"/>
    14   </set>
    15  </class>
    16 </hibernate-mapping>

    3.编写部门和员工的实体类

     1 package entity;
     2 
     3 import java.io.Serializable;
     4 
     5 public class Emp implements Serializable{
     6     /**
     7      * 
     8      */
     9     private static final long serialVersionUID = 1L;
    10     private String empNo;
    11     private String empName;
    12     private Dept dept;
    13     
    14     public Emp(){}
    15     
    16     public Emp(String empNo,String empName){
    17         this.empNo = empNo;
    18         this.empName = empName;
    19     }
    20     public String getEmpNo() {
    21         return empNo;
    22     }
    23     public void setEmpNo(String empNo) {
    24         this.empNo = empNo;
    25     }
    26     public String getEmpName() {
    27         return empName;
    28     }
    29     public void setEmpName(String empName) {
    30         this.empName = empName;
    31     }
    32 
    33     public Dept getDept() {
    34         return dept;
    35     }
    36 
    37     public void setDept(Dept dept) {
    38         this.dept = dept;
    39     }
    40     
    41 }
     1 package entity;
     2 
     3 import java.io.Serializable;
     4 import java.util.HashSet;
     5 import java.util.Set;
     6 
     7 public class Dept implements Serializable{
     8     /**
     9      * 
    10      */
    11     private static final long serialVersionUID = 1L;
    12     
    13     private String deptNo;
    14     private String deptName;
    15     private String location;
    16     
    17     private Set<Emp> emps = new HashSet<Emp>();
    18     
    19     public Dept(){}
    20     public Dept(String deptNo,String deptName,String location){
    21         this.deptNo = deptNo;
    22         this.deptName = deptName;
    23         this.location = location;
    24     }
    25     public String getDeptNo() {
    26         return deptNo;
    27     }
    28     public void setDeptNo(String deptNo) {
    29         this.deptNo = deptNo;
    30     }
    31     public String getDeptName() {
    32         return deptName;
    33     }
    34     public void setDeptName(String deptName) {
    35         this.deptName = deptName;
    36     }
    37     public String getLocation() {
    38         return location;
    39     }
    40     public void setLocation(String location) {
    41         this.location = location;
    42     }
    43     public Set<Emp> getEmps() {
    44         return emps;
    45     }
    46     public void setEmps(Set<Emp> emps) {
    47         this.emps = emps;
    48     }
    49     
    50     
    51 }

    4.测试类

    下面只写出测试的方法,

    1 public void deleteDeptAndEmps(){
    2         currentSession();
    3         beginTransaction();
    4         Dept dept = (Dept)session.load(Dept.class, "1001");
    5         session.delete(dept);
    6         commitTransaction();
    7         closeSession();
    8 }

    5.进行测试

    package test.dao;
    
    import static org.junit.Assert.*;
    
    import org.junit.Ignore;
    import org.junit.Test;
    
    import dao.impl.EmpDaoImpl;
    
    public class EmpDaoImplTest extends EmpDaoImpl{
        @Test
        public void testDeleteDeptAndEmps(){
            deleteDeptAndEmps();
        }
    }

    运行的结果会出现下面错误:

     1 org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update
     2     at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:126)
     3     at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:114)
     4     at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
     5     at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
     6     at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:266)
     7     at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:169)
     8     at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
     9     at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
    10     at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1028)
    11     at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:366)
    12     at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:137)
    13     at util.HibernateUtil.commitTransaction(HibernateUtil.java:44)
    14     at dao.impl.EmpDaoImpl.deleteDeptAndEmps(EmpDaoImpl.java:49)
    15     at test.dao.EmpDaoImplTest.testDeleteDeptAndEmps(EmpDaoImplTest.java:21)
    16     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    17     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    18     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    19     at java.lang.reflect.Method.invoke(Method.java:597)
    20     at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    21     at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    22     at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    23     at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    24     at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
    25     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
    26     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
    27     at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    28     at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    29     at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    30     at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    31     at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    32     at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    33     at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    34     at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    35     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    36     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    37     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    38     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
    39 Caused by: java.sql.BatchUpdateException: ORA-01407: 无法更新 ("ACCP"."EMP"."DEPTNO") 为 NULL
    40 
    41     at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:343)
    42     at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10720)
    43     at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
    44     at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
    45     ... 33 more

    重点关注这一条错误:无法更新 ("ACCP"."EMP"."DEPTNO") 为 NULL

    这时为什么呢,我们先看看执行hibernate删除时的sql语句:

    Hibernate: 
        select
            dept0_.DEPTNO as DEPTNO4_0_,
            dept0_.DEPTNAME as DEPTNAME4_0_,
            dept0_.LOCATION as LOCATION4_0_ 
        from
            ACCP.DEPT dept0_ 
        where
            dept0_.DEPTNO=?
    Hibernate: 
        select
            emps0_.DEPTNO as DEPTNO1_,
            emps0_.EMPNO as EMPNO1_,
            emps0_.EMPNO as EMPNO5_0_,
            emps0_.EMPNAME as EMPNAME5_0_,
            emps0_.DEPTNO as DEPTNO5_0_ 
        from
            ACCP.EMP emps0_ 
        where
            emps0_.DEPTNO=?
    Hibernate: 
        update
            ACCP.EMP 
        set
            DEPTNO=null 
        where
            DEPTNO=?

    从上面我们可以看出,要执行级联删除,要删除Dept表中部门的同时删除Emp表对于部门下的所有员工信息,hibernate是这么干的:

    (1)hibernate首先会查询出对应要删除的部门信息

    (2)然后级联查询出对于的部门下的所有员工信息

    (3)接着更新对于部门下的所有员工,将其部门更新为null

    好,问题出现了,报错就在这一个步骤,既然要更新为null,那么Emp表在设计时就要能够让Emp表中的deptNo这个字段能够为null,也就是可以为空,下面就将正确的表

    设计显示如下:

    好了,上面的勾打上了,那么问题就解决了。

    下面我们再执行一次级联删除的方法,看看最终效果:

    对于的sql语句情况如下:

    Hibernate: 
        select
            dept0_.DEPTNO as DEPTNO4_0_,
            dept0_.DEPTNAME as DEPTNAME4_0_,
            dept0_.LOCATION as LOCATION4_0_ 
        from
            ACCP.DEPT dept0_ 
        where
            dept0_.DEPTNO=?
    Hibernate: 
        select
            emps0_.DEPTNO as DEPTNO1_,
            emps0_.EMPNO as EMPNO1_,
            emps0_.EMPNO as EMPNO5_0_,
            emps0_.EMPNAME as EMPNAME5_0_,
            emps0_.DEPTNO as DEPTNO5_0_ 
        from
            ACCP.EMP emps0_ 
        where
            emps0_.DEPTNO=?
    Hibernate:  ---------------------------------------------〈〈〈〈看该句下面的变化
        update
            ACCP.EMP 
        set
            DEPTNO=null 
        where
            DEPTNO=?
    Hibernate:        
        delete 
        from
            ACCP.EMP 
        where
            EMPNO=?
    Hibernate: 
        delete 
        from
            ACCP.DEPT 
        where
            DEPTNO=?

    从上面可以得出hibernate执行级联删除的步骤分为5步:

    (1)同上

    (2)同上

    (3)同上

    (4)删除Emp表中对应部门的所有信息记录

    (5)最后删除Dept表中对应得部门信息

    OK,问题解决,通过这个级联删除,使我们能够更加充分的认识hibernate作为持久化工具在处理持久化删除时它的操作方式,是不是很有意思。有问题的话大家可以一起交流。

  • 相关阅读:
    Linux内核中的红黑树
    研究UEVENT相关东西,看到2篇优秀的博文,转载与此
    Nor Nand OneNand
    Linux设备模型(总线、设备、驱动程序和类)
    linux驱动的入口函数module_init的加载和释放(转)
    hwclock(Linux)
    Linux块设备驱动
    pdflush内核线程池及其中隐含的竞争
    Nand Flash与Nor Flash
    linux内核I2C体系结构(注意结构体原型)
  • 原文地址:https://www.cnblogs.com/IT-Monkey/p/4110169.html
Copyright © 2011-2022 走看看