我想在hibernate Hql中的同一个查询中执行多个更新语句。 如下所示:
$scope.result = []
data.forEach(function(d){
$scope.result.push({"id":d.id, "text":d.text});
});
在同一个hql = " update Table1 set prob1=null where id=:id1; "
+ " delete from Table2 where id =:id2 ";
...
query.executeUpdate();
调用中我想更新Table1中的记录并从Table2中删除记录。
这可能吗?
答案 0 :(得分:4)
在同一个executeUpdate调用中我想更新Table1和中的记录 从表2中删除记录。
这可能吗?
executeUpdate()
执行单个更新查询。
所以,不,你不能这样做。您必须执行与表一样多的更新查询才能更新/删除。
此外,如果您分开查询,它会使代码更清晰:
executeUpdate()
这并不意味着必须逐个传递查询
批处理是Hibernate提供的一项功能,可在您想要执行多个查询时提高性能。您必须启用该功能才能使用它。
必须使用合适的值设置hibernate.jdbc.batch_size
属性。
如果您正在进行批处理,则需要启用批处理 使用JDBC批处理。如果你愿意,这绝对是必不可少的 实现最佳性能。将JDBC批处理大小设置为合理 数字(例如10-50):
hibernate.jdbc.batch_size 20 Hibernate禁用插入批处理 如果使用标识符生成器,则透明地使用JDBC级别。
如果,Hibernate会透明地禁用JDBC级别的插入批处理 您使用身份标识符生成器。
然而,在你的情况下,它将是无用的,因为Dragan Bozanovic解释你更新/删除查询中的不同表。因此,它将创建与查询表一样多的批处理执行 因此,您应该单独执行每个查询。当你认为应该是:(/ p>)时,只需提交()
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();
答案 1 :(得分:3)
不,这是不可能的,因为Hibernate为此使用了PreparedStatement
(由于绑定变量这很好),PreparedStatement
不支持由多个不同语句组成的批处理。
PreparedStatement
只能为一个语句批量绑定变量的不同组合,Hibernate在刷新持久化上下文(会话)中的更改时用于batch inserts/updates。
答案 2 :(得分:3)
简而言之,您所看到的就像在JDBC中批处理一样。 Hibernate没有为批量更新查询提供Thich,我怀疑它是否会被考虑用于Hibernate。
根据我过去的经验,HQL的批处理功能在现实生活中很少有用。某些东西在SQL + JDBC中有用但在HQL中却没有用,这听起来很奇怪。我会尝试解释。
通常当我们使用Hibernate(或其他类似的ORM)时,我们会对实体起作用。 Hibernate将负责将我们的实体状态与DB同步,这是JDBC批处理可以帮助提高性能的大多数情况。但是,在Hibernate中,我们不会通过批量更新查询更改单个实体的状态。
举个例子,用伪代码:
在JDBC中,您可以执行类似的操作(我试图模仿您在示例中显示的内容):
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();
}
}
我怀疑您认为您需要批处理功能,因为您正在执行类似的操作(基于您的示例,您使用批量更新进行单个记录)。但是 NOT 应该如何在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
通过这样做,Hibernate足够智能,可以检测已更改/删除/插入的实体,并利用JDBC批处理在flush()
进行DB CUD操作。更重要的是,这是ORM的全部目的:我们希望提供与行为相关的实体,实体的内部状态变化可以“透明地”反映在持久存储中。
HQL批量更新旨在用于其他用途,例如对DB进行批量更新以影响大量记录,例如:
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();
在这种使用场景中很少需要执行大量查询,因此,DB往返的开销微不足道,因此,批量更新查询的好处和批量处理支持很少发生。
我不能忽略有些情况下您确实需要发出大量更新查询,这些查询不适合由有意义的实体行为完成。在这种情况下,您可能需要重新考虑Hibernate是否是正确使用的工具。您可以考虑在此类用例中使用纯JDBC,以便您可以控制如何发出查询。
答案 3 :(得分:1)
由JPA批量更新/删除生成的SQL,即对javax.persistence.Query.executeUpdate()的调用在传递给JDBC时不能由Hibernate批处理。 @DraganBozanovic和@AdrianShum已经解释了这一点,但是要添加他们的注释:executeUpdate()返回一个int(更新或删除的实体数) - 无论刷新Hibernate会话,如何在不调用数据库的情况下返回int立即和同步?必须在客户端评估JPQL / HQL / SQL,这是不可能的,因为要批量更新/删除的实体甚至可能都没有被读入Hibernate会话。此外,如果未立即在数据库上执行更新/删除,则在JPA实体中读取的后续查询可能会获得过时数据。例如:
如果允许将1的executeUpdate推迟到读取2之后,那么你得到错误的答案(客户仍然存在)。
您需要阅读使用JPA的实体,更新它们,让Hibernate生成更新SQL(它可以批处理),或者直接调用JDBC来执行批量更新。
答案 4 :(得分:0)
为什么不在Transactional方法中单独执行两个查询
通过使用@Transactional注释方法,如果任何查询失败,则另一个不会执行。
@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();
...
}