通过JPA条件/ JPQL和JPA缓存进行DML操作

时间:2014-11-20 06:15:31

标签: hibernate caching jpa eclipselink criteria

JPA 2.1支持分别使用CriteriaDeleteCriteriaUpdate通过JPA条件API执行删除/更新DML操作。

下面是一个非常简单的示例,它使用CriteriaUpdate(由EclipseLink 2.5.2和/或Hibernate 4.3.6 final提供)对关联数据库执行更新操作。

public boolean update(byte[] file, Brand brand)
{
    CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
    CriteriaUpdate<Brand>criteriaUpdate=criteriaBuilder.createCriteriaUpdate(Brand.class);
    Root<Brand> root = criteriaUpdate.from(entityManager.getMetamodel().entity(Brand.class));

    criteriaUpdate.set(root.get(Brand_.brandName), brand.getBrandName());
    criteriaUpdate.set(root.get(Brand_.category), brand.getCategory());
    criteriaUpdate.set(root.get(Brand_.brandImage), file);

    criteriaUpdate.where(criteriaBuilder.equal(root, brand));
    return entityManager.createQuery(criteriaUpdate).executeUpdate()>0;
}

可以使用相应的JPQL重写相同的内容,如下所示。我通常习惯使用JPA标准。

public boolean update(byte[] file, Brand brand)
{
    return entityManager.createQuery("UPDATE Brand b SET b.brandName=:brandName, b.category=:category, b.brandImage=:brandImage WHERE b.brandId=:brandId")
           .setParameter("brandName", brand.getBrandName())
           .setParameter("category", brand.getCategory())
           .setParameter("brandImage", file)
           .setParameter("brandId", brand.getBrandId())
           .executeUpdate()>0;
}

我认为代码片段本身是不言自明的。因此,我对他们保持沉默。

在这种情况下,与entityManager.merge(brand)不同,DML操作直接在数据库上执行,因此,关联的被管实体brand的状态不会受到影响。不会触发相关的JPA回调,例如@PreUpdate@PostUpdate,如果有的话。

数据库状态将不会与持久性提供程序管理的实体同步,即依赖于持久性提供程序,关联实体(在这种情况下为brand)可能不会反映更新的值数据库中。

每次调用此方法时,即使实体brand未更改/更新,更新操作也会传播到数据库。

与使用entityManager.createNativeQuery("query")方法直接对基础数据库执行本机查询相同。

是否可以为此DML操作提供与entityManager.merge(brand)相同的效果,以便在执行此类操作后实体状态与数据库的当前状态同步?

完成此更新操作后是否需要执行entityManager.refresh(entity)(或其他内容)以将数据库中当前保存的状态反映到实体?

1 个答案:

答案 0 :(得分:1)

DML操作直接针对数据库执行,因此绕过了第一级缓存dirty checking emchanism

不会触发拦截器,事件监听器和JPA PostUpdate挂钩,因为Hibernate操作队列机制不会生成更新。

The AUTO flush is only triggered for HQL/Criteria查询而非本地查询,因此您最好在此类查询之前手动刷新会话,以确保挂起的更改与数据库同步。

更新后,您需要刷新所有当前加载的实体,或者逐出所有实体并重新加载它们。