• 记一次Hibernate错误


     错误信息如下:

    Caused by: org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1

    1、看了代码也找不到错,通常都会先搜索一番,然后发现报这个错,主要是因为如下:

    使用的是hibernate的saveOrUpdate方法保存实例。saveOrUpdate方法要求ID为null时才执行SAVE,在其它情况下执行UPDATE。在保存实例的时候是新增,但你的ID不为null,所以使用的是UPDATE,但是数据库里没有主键相关的值,所以出现异常。

    但是翻来覆去看了N遍代码也没有找到哪里有调用update之类的方法,错误现场是一个查询语句的地方。

    public DepartmentVo getDepartmentVo(String deptCode) {
            SQLQuery query = getCurrentSession().createSQLQuery("select * from department where DEPT_CODE = ?");
            query.setParameter(0, deptCode);
            query.setMaxResults(1);
            
            DepartmentVo departmentVo = (DepartmentVo) query.addEntity(DepartmentVo.class).uniqueResult(); // 断点调试时,此处报错
            return departmentVo;
        }

    2、然后就想到把Sql语句打印出来,看一下具体是执行了什么update语句导致的,于是将Hibernate打印sql的地方配置为true

    <prop key="hibernate.show_sql">${hibernate.show_sql:true}</prop>

    3、然后发现了update的语句

      update
            area 
        set
            DEPT_CODE=?,
            DEPT_NAME=?,
            PARENT_DEPT_CODE=?,
            TYPE_LEVEL=? 
        where
            DEPT_ID=?

    这里 实体类 DepartmentVo映射的就是area 表。但是Hibernate只有对对象set值操作之后才会自动执行update语句的,而代码里并没有看到有地方有赋值

    4、然后把参数值也打印出来,在logback里面添加配置

    <logger name="org.hibernate.type.descriptor.sql.BasicBinder">  
        <level value="TRACE" />
    </logger><logger name="org.hibernate.type.descriptor.sql.BasicExtractor">  
        <level value="DEBUG" />
    </logger>

    打印update语句的参数值如下:

    binding parameter [1] as [VARCHAR] - [888M]
    binding parameter [2] as [VARCHAR] - [xxxx/888M]
    binding parameter [3] as [VARCHAR] - [888M]
    binding parameter [4] as [VARCHAR] - [3]
    binding parameter [5] as [BIGINT] - [2817]

    5、然后再把刚刚查询出来的对象打印出来,跟update的值比较一下

    DepartmentVo [deptId=2817, deptCode=888M, deptName=xxxx, parentCode=888M, typeLevel=3]

    最终发现了对象前后的值果然不一样,然后deptId=2817在表area又不存在,所以报错。

    最后在DepartmentVo中发现

        public String getDeptName() {
            if (null != deptCode && null != deptName)
            {
                return deptName + "/" + deptCode;
            }
            return deptName;
        }

    所以,按照这个,addEntity方法大概是用的反射吧~~~

    解决方法的话,可以用

    getCurrentSession().evict(对象);
  • 相关阅读:
    flex 只显示年、月的日期选择控件(TimeChooser)
    SQL 实现统计业务
    SQL 时间函数详解
    我与计算机
    ISE中FPGA的实现流程
    总结Verilog中always语句的使用
    VGA 时序标准
    ChipScope软件使用
    FIFO的使用场景
    Verilog 初级入门概念
  • 原文地址:https://www.cnblogs.com/ld-swust/p/10478849.html
Copyright © 2020-2023  润新知