对 - 我想从数据库中删除(例如)1,000,000 条记录。 这需要很长时间 -> 事务超时并失败。 所以 - 我分批删除它们,比如每笔交易 25000 条记录。 在 MySQL 上使用 limit 子句,在 Oracle 上使用 ROWNUM。 太棒了,这有效。
我想以独立于数据库的方式执行此操作。 以及来自使用 JPA/Hibernate 的现有 Java 代码库。
运气不好。 JPA Query.setMaxResults 和 setFirstResult 没有 写入“查询”的效果(例如删除)。选择许多实体 我想说,将它们单独删除到内存中是非常缓慢和愚蠢的。
因此,我使用本机查询并管理应用程序代码中的“限制”子句。 最好将此子句封装在 orm.xml 中,但是...... “Hibernate Annotations 3.2 不支持使用本机查询批量更新/删除。” - http://opensource.atlassian.com/projects/hibernate/browse/ANN-469。
我想这是一个常见问题。 有人有更好的独立于数据库的解决方案吗?
我不想给出非建设性的答案,但 ORM 并不是真正用于对数据库进行批量操作。因此,看起来本机查询可能是这些操作的最佳选择。
您还应该确保您的 ORM 已更新以反映数据库的新状态,否则您可能会发生一些奇怪的情况。
ORM 是将对象映射到数据库的绝佳工具,但它们通常不是通用数据库接口。
查询限制是数据库特定的功能,并且没有 SQL 标准(我同意应该有)。
适用于大多数数据库的一种解决方案是使用视图将多个表分组为一个。每个表都包含数据的子集(比如某一天)。这允许您一次删除整个子集。也就是说,许多数据库在此类视图上运行 UPDATE 和 INSERT 时都会遇到问题。
您通常可以通过为 INSERT/UPDATE 创建视图或别名(指向单个表;“当前”表)和用于搜索的分组视图来解决此问题。
一些数据库还提供分区,这基本上是相同的事情,只是您可以定义一个列来指定一行应该进入哪个基础表(在 INSERT 上)。当您需要删除子集时,您可以删除/截断其中一个基础表。
我相信您可以使用 HQL (JPA QL) 直接 DML 操作,这将绕过持久化上下文和缓存,并直接执行(生成的 SQL)语句:
Query q = session.createQuery("delete YourEntity ye where ye.something like :param");
q.setParameter("param", "anything");
int deletedEntities = q.executeUpdate();
将其插入所需的存储库。
@Modifying
@Transactional
@Query(value = "DELETE FROM myTable LIMIT 25000", nativeQuery = true)
void removeRows();
q.setMaxResults(int)
...索尼