• 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作为持久化工具在处理持久化删除时它的操作方式,是不是很有意思。有问题的话大家可以一起交流。

  • 相关阅读:
    windows中dos命令指南
    HDU 2084 数塔 (dp)
    HDU 1176 免费馅饼 (dp)
    HDU 1004 Let the Balloon Rise (map)
    变态杀人狂 (数学)
    HDU 2717 Catch That Cow (深搜)
    HDU 1234 开门人和关门人 (模拟)
    HDU 1070 Milk (模拟)
    HDU 1175 连连看 (深搜+剪枝)
    HDU 1159 Common Subsequence (dp)
  • 原文地址:https://www.cnblogs.com/IT-Monkey/p/4110169.html
Copyright © 2020-2023  润新知