JPA 2.1支持分别使用CriteriaDelete
和CriteriaUpdate
通过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)
(或其他内容)以将数据库中当前保存的状态反映到实体?
答案 0 :(得分:1)
DML操作直接针对数据库执行,因此绕过了第一级缓存dirty checking emchanism。
不会触发拦截器,事件监听器和JPA PostUpdate挂钩,因为Hibernate操作队列机制不会生成更新。
The AUTO flush is only triggered for HQL/Criteria查询而非本地查询,因此您最好在此类查询之前手动刷新会话,以确保挂起的更改与数据库同步。
更新后,您需要刷新所有当前加载的实体,或者逐出所有实体并重新加载它们。