hibernate为我们提供了删除直接根据实体参数删除数据的方法:
HibernateTemplate().delete(entity);
public void delete(final Object entity, final LockMode lockMode) throws DataAccessException { executeWithNativeSession(new HibernateCallback<Object>() { public Object doInHibernate(Session session) throws HibernateException { checkWriteOperationAllowed(session); if (lockMode != null) { session.lock(entity, lockMode); } session.delete(entity); return null; } }); }
这是实现的源码,此处只是把实体从session中删掉,等待事务提交时统一生成sql语句。
所以这种方式不能保证在同一个事务中的sql执行顺序,假设有这样的代码在程序中:
需要在事务中先执行删除,再执行插入。在提交事务时,就发生主键冲突的错误。
经查,hibernate在向db提交缓存的sql时,是按insert、update、delete的顺序提交。这就导致在提交insert语句时出错。
rentDeliveryChargeDao.delete(rentDeliveryCharge);
rentDeliveryKeyDao.delete(rentDeliveryKey);
rentDeliveryChargeDao.save(deliveryCharge);
rentDeliveryKeyDao.save(rentDeliveryKey);
如果此时有数据库唯一性限制的话,程序可能会报错,主要是由于在同一个事务中不保证sql执行顺序。
遇到此类问题应改为以下:
rentDeliveryChargeDao.deleteByRentContractId(rentContractId);
rentDeliveryKeyDao.delDeliveryKeyByContractId(rentContractId);
后者是底层调用:
public int bulkUpdate(final String queryString, final Object... values) throws DataAccessException { return executeWithNativeSession(new HibernateCallback<Integer>() { public Integer doInHibernate(Session session) throws HibernateException { Query queryObject = session.createQuery(queryString); prepareQuery(queryObject); if (values != null) { for (int i = 0; i < values.length; i++) { queryObject.setParameter(i, values[i]); } } return queryObject.executeUpdate(); } }); }
这样就能保证事务中sql的执行顺序。