我正在寻找一种有效的方法来删除事务中的多个实体。
给定一个id列表,如果受影响的行数与列表数不同,我想抛出异常。目前我使用下面的代码片段,但它涉及很多样板:
private int deleteMyEntities(final List<Integer> ids) {
final Session session = SomeHelper.getOpenSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
final int affectedCount = session.createQuery("delete MyEntity where id in (:ids)")
.setParameterList("ids", ids)
.executeUpdate();
if (affectedCount == ids.size()) {
tx.commit();
tx = null;
return affectedCount;
} else {
throw new HibernateException("Delete count does not match target count.");
}
} finally {
if (tx != null) {
tx.rollback();
}
}
}
一些问题:
答案 0 :(得分:1)
try
语句中启动您的事务,因为如果您无法启动它,那么您可能无法将其回滚,但即使您可能没有因为你还没有做任何事情。如果交易无法打开,则无法关闭。换句话说,连接池中不会有孤立的线程。
private int deleteMyEntities(final List<Integer> ids) {
final Session session = SomeHelper.getOpenSession();
Transaction tx = session.beginTransaction();
try {
final int affectedCount = session.createQuery("delete MyEntity where id in (:ids)")
.setParameterList("ids", ids)
.executeUpdate();
if (affectedCount == ids.size()) {
tx.commit();
return affectedCount;
} else {
throw new HibernateException("Delete count does not match target count.");
}
} catch (Exception e) {
tx.rollback();
throw e;
}
}
不幸的是,如果不编写自己的自定义框架来执行基于注释的事务之类的操作,就很难让它变得“好”。如果你有权访问AOP库,你可以使用它来隐藏很多这个,虽然你的描述看起来很可疑。
答案 1 :(得分:0)
我最终采用的解决方案包括Alex的建议。我还提出了很多逻辑来保持代码有点干。注意:hibernate会话在过滤器中打开并在请求期间保持(在视图中打开会话),因此会话重置在recoverFromFailedTransaction
public int deleteMyEntity(final List<Integer> ids) {
return deleteEntities("MyEntity", ids);
}
private int deleteEntities(final String entityName, final List<Integer> ids) {
final Session session = SomeHelper.getOpenSession();
final Query query = session.createQuery("delete " + entityName + " where id in (:ids)")
.setParameterList("ids", ids);
return performBatchOperation(query, ids.size());
}
private int performBatchOperation(final Query query, final int expectedAffectedCount) {
final Session session = SomeHelper.getOpenSession();
final Transaction tx = session.beginTransaction();
try {
final int affectedCount = query.executeUpdate();
if (affectedCount == expectedAffectedCount) {
tx.commit();
return affectedCount;
} else {
throw new HibernateException(String.format(
"Affected count [%d] does not match expected count [%d].",
affectedCount,
expectedAffectedCount));
}
} catch (RuntimeException e) {
logger.error(e);
recoverFromFailedTransaction(tx);
throw e;
}
}
private void recoverFromFailedTransaction(final Transaction tx) {
try {
if (tx != null) {
tx.rollback();
}
} catch (HibernateException e) {
logger.error("Exception when rolling back failed transaction. ", e);
}
try {
SomeHelper.getOpenSession().close();
} catch (HibernateException e) {
logger.error("Exception when closing session . ", e);
}
SomeHelper.resetOpenSession();
logger.warn("Session discarded.");
}