我希望在Hibernate HQL中执行多个更新语句,像下面这样:
hql = " update Table1 set prob1=null where id=:id1; "
+ " delete from Table2 where id =:id2 ";
...
query.executeUpdate();
在同一个 executeUpdate
调用中,我想更新 Table1 中的记录并从 Table2 中删除记录。
这种操作是否可行?
executeUpdate()
执行单个更新查询。因此,不行。您必须执行与要更新/删除的表数量相同的更新查询。此外,如果将查询分开,则可以使代码更清晰:executeUpdate()
中处理查询,那么理解起来会更容易。hibernate.jdbc.batch_size
属性必须设置为适当的值。hql = "update Table1 set prob1=null where id=:id1;"
...
query.setParameter("id1",...);
query.executeUpdate();
hql = "delete from Table2 where id =:id2";
...
query.executeUpdate();
query.setParameter("id2",...);
..
tx.commit();
PreparedStatement
(这很好,因为有绑定变量),而PreparedStatement
不支持由多个不同语句组成的批处理。 PreparedStatement
只能为一个语句批量处理不同的绑定变量组合,当在持久化上下文(会话)中刷新更改时,Hibernate用于批量插入/更新。List<Order> orders = findOrderByUserId(userName);
for (Order order: orders) {
if (order outstanding quantity is 0) {
dbConn.addBatch("update ORDER set STATE='C' where ID=:id", order.id);
} else if (order is after expriation time) {
dbConn.addBatch("delete ORDER where ID=:id", order.id);
}
}
dbConn.executeBatch();
从JDBC逻辑到Hibernate的朴素转换可能会给您带来以下内容:
List<Order> orders = findOrderByUserId(userName);
for (Order order: orders) {
if (order outstanding quantity is 0) {
q = session.createQuery("update Order set state='C' where id=:id");
q.setParameter("id", order.id);
q.executeUpdate();
} else if (order is after expriation time) {
q = session.createQuery("delete Order where id=:id");
q.setParameter("id", order.id);
q.executeUpdate();
}
}
我猜想你认为你需要批处理功能,因为你正在做类似的事情(根据你的例子,你使用批量更新来更新单个记录)。然而,在Hibernate/JPA中,这不是应该采用的方式。
(实际上,最好通过存储库来包装持久层访问,这里我只是简化了图像)
List<Order> orders = findOrderByUserId(userName);
for (Order order: orders) {
if (order.anyOutstanding()) {
order.complete(); // which internally update the state
} else if (order.expired) {
session.delete(order);
}
}
session.flush(); // or you may simply leave it to flush automatically before txn commit
flush()
中的DB CUD操作。更重要的是,这是ORM的整个目的:我们想提供行为丰富的实体进行工作,对于这些实体的内部状态更改可以在持久存储中“透明”反映出来。q = session.createQuery("update Order set state='C' "
+ " where user.id=:user_id "
+ " and outstandingQty = 0 and state != 'C' ");
q.setParameter("user_id", userId);
q.executeUpdate();
在这种使用场景下,很少需要执行大量查询,因此,数据库往返的开销微不足道,因此,对于批处理支持和批量更新查询的好处很少显著。
我不能忽略有些情况下确实需要发出大量更新查询,这不适合通过有意义的实体行为来完成。在这种情况下,您可能需要重新考虑是否使用Hibernate是正确的工具。在这种情况下,您可以考虑使用纯JDBC,以便控制查询的发出方式。
如果允许在第2次读取之后推迟第1次executeUpdate,则会得到错误的答案(客户仍然存在)。
您需要使用JPA读取实体,更新它们,并让Hibernate生成更新SQL(它可以进行批处理),或直接调用JDBC执行批量更新。
@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
public void executeQuery(Obj1 obj1) {
String query="update table1 set actualRepaymentAmount=expectedRepaymentAmount,active='Y' where loanCaseId = '"+caseId+"'";
sessionFactory.getCurrentSession().createQuery(query).executeUpdate();
query="update table2 set loanStatus='C' where loanCaseId = '"+caseId+"'";
sessionFactory.getCurrentSession().createQuery(query).executeUpdate();
...
}
Criteria
而不是hql
语言。参考链接:https://dev59.com/-nVC5IYBdhLWcg3wvT1a?rq=1 - Jordi CastillaQuery::executeUpdate
,不能进行连接,但将在同一会话中进行事务。 - Jordi CastillaPreparedStatement
。 - Dragan Bozanovic