使用多个 ID 时在 JPQL 中执行 CRUD 操作的正确方法是啥

Posted

技术标签:

【中文标题】使用多个 ID 时在 JPQL 中执行 CRUD 操作的正确方法是啥【英文标题】:What is correct way to do CRUD operation in JPQL when working with multiple IDs使用多个 ID 时在 JPQL 中执行 CRUD 操作的正确方法是什么 【发布时间】:2015-03-03 15:09:48 【问题描述】:

我想知道执行涉及获取和删除多个实体对象的操作的首选/正确方法是什么?

这是一个例子:

这里是使用IN操作符的方式:

@Override
public void delete(Iterable<Long> ids) 
    startTransaction();

    Query query = getEntityManager().createNamedQuery(Entity.DELETE_ALL_BY_IDS_NQ);
    query.setParameter(Entity.DELETE_ALL_BY_IDS_PARAMS[0], ids);
    query.executeUpdate();

    endTransaction();
    closeTransaction();

命名查询如下所示:

@NamedQuery(
        name = "Entity.deleteAllByIds",
        query = "DELETE from Entity e WHERE e.id IN :ids"
)

这就是通过EntityManager#remove实现它的方式

public void delete(Iterable<Long> ids) 
    int count = 0;

    startTransaction();

    for (Long id : ids) 
        count++;

        Query query = getEntityManager().createNamedQuery(ImeiTacEntity.IMEITAC_READ_BY_ID_NQ);
        query.setParameter(ImeiTacEntity.IMEITAC_READ_BY_ID_PARAMS[0], id);

        ImeiTacEntity entity = (ImeiTacEntity) query.getSingleResult();
        getEntityManager().remove(entity);

        if ((count % BATCH_THRESHOLD) == 0) 
            endTransaction();
            clearTransaction();
            startTransaction();
        
    

    endTransaction();
    closeTransaction();

读取查询是这样的:

@NamedQuery(
    name = "Entity.readById", 
    query = "SELECT e from Entity e WHERE e.id = :id"
)

【问题讨论】:

【参考方案1】:

第一个操作是 JPQL“批量”操作的示例,虽然在执行的 SQL 语句数量方面效率更高,但您应该注意以下要点:

https://docs.oracle.com/html/E24396_01/ejb3_langref.html#ejb3_langref_bulk_ops

10.2.9。 JPQL 批量更新和删除

操作批量更新和删除操作适用于一个实体 单个实体类(连同它的子类,如果有的话)。

删除操作仅适用于指定类的实体,并且 它的子类。 它不会级联到相关实体。这 为更新操作指定的新值必须在类型上兼容 与分配给它的状态字段。 批量更新地图 直接到数据库更新操作,绕过乐观锁定 检查。便携式应用程序必须手动更新 版本列,如果需要,和/或手动验证 版本列。 持久化上下文不同步 批量更新或删除的结果。应谨慎使用时 执行批量更新或删除操作,因为 它们可能会导致 数据库和活动中的实体之间的不一致 持久化上下文。一般来说,批量更新和删除操作 只能在单独的事务中或在 事务的开始(在访问其实体之前 状态可能会受到此类操作的影响)。

因此,在决定采用一种或其他方法时,您需要考虑上述因素。

【讨论】:

【参考方案2】:

在这种情况下,第一个选项肯定有其优势。最大的一个是它转换为单个 delete SQL 查询,而在第二个选项中,您在将每个实体传递给 em.remove() 之前加载它。

【讨论】:

以上是关于使用多个 ID 时在 JPQL 中执行 CRUD 操作的正确方法是啥的主要内容,如果未能解决你的问题,请参考以下文章

在 JPQL 查询中执行更新/删除查询

如何使用 JPA 1.0 构建一个 JPQL 查询,从多个表中获取数据以克服延迟初始化?

JPA JPQL高级操作

JPQL 右连接

SOUNDEX 不能使用 JPQL 与 JPA 一起工作

可以在一个 JPQL 查询中传递多个命名实体图?