Hibernate的SQL执行顺序引起的血案

问题起源于代码中对某个对象的处理逻辑,当发现该对象的某些属性变化时,先将原数据删除,再插入一个新对象,因为使用了Spring+Hibernate的组合,很容易写出以下代码: java

//从数据库中读取原数据
Role entity = hibernateTemplate.load(ID);
//将数据复制到新对象上
Role newEntity = new Role();
BeanCopier.copy(entity, newEntity);
//删除原数据
hibernateTemplate.delete(entity);
//保存新数据
hibernateTemplate.save(entity);
然而这段代码在执行时却失败了,程序抛出:DataIntegrityViolationException异常,日志显示以下错误:
SQL Error: 1062, SQLState: 23000
Duplicate entry 'demo' for key 'IDX_ROLE_NAME'
即数据插入数据库时失败了,缘由是触发了惟一性约束。经反复核实,数据库中数据没有问题,不是其余数据致使的,从代码逻辑上讲,这段代码先删后插也没有任何问题,在一个事务当中也没有什么脏读的问题, 这就搞笑了,问题到底出在哪呢???
打开Hibernate的SQL输出,还原最真实的SQL语句,终于找到了答案,输入日志以下:
Hibernate: 
    /* insert com.litt.cidp.system.po.Role
        */ insert 
        into
            role
            (ROLE_NAME, STATUS, REMARK) 
        values
            (?, ?, ?)
Hibernate: 
    /* update
        com.litt.cidp.system.po.Role */ update
            role 
        set
            ROLE_NAME=?,
            STATUS=?,
            REMARK=? 
        where
            ROLE_ID=?
Hibernate: 
    /* delete com.litt.cidp.system.po.Role */ delete 
        from
            role 
        where
            ROLE_ID=?

Hibernate在最终执行SQL语句时,竟然是按INSERT, UPDATE, DELETE的顺序执行的,而非按照代码顺序执行!What the F!查阅了相关资料,说是Hibernate为了性能优化,对象操做都是放在缓存里而没有当即执行数据库操做直到commit操做,为的是利用batch操做提升数据库操做性能;老天,那业务逻辑怎么办?同理,在一个事务中混用Hibernate和JDBC操做,将致使数据不一致问题sql

解决方案:在须要同步的地方(即按照INSERT, UPDATE, DELETE顺序有可能产生问题的时候;混用JDBC操做的时候),执行session.flush()方案,该方法将缓存中的数据请求当即转换为数据库操做并执行。 数据库

相关文章
相关标签/搜索