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的执行顺序。