jpa vue管理系统
从JPA 2.0版开始, EntityManager
提供了getCriteriaBuilder()
方法来动态构建选择查询,而无需使用Java Persistence Query Languge(JPQL)进行字符串连接。 在2.1版中,此CriteriaBuilder
提供了两个新方法createCriteriaDelete()
和createCriteriaUpdate()
,使我们可以使用条件API制定删除和更新查询的方法。
出于说明目的,让我们对两个实体Person
和Geek
使用简单的继承用例:
@Entity
@Table(name = "T_PERSON")
@Inheritance(strategy = InheritanceType.JOINED)
public class Person {
@Id
@GeneratedValue
private Long id;
@Column(name = "FIRST_NAME")
private String firstName;
@Column(name = "LAST_NAME")
private String lastName;
...
}
@Entity
@Table(name = "T_GEEK")
@Access(AccessType.PROPERTY)
public class Geek extends Person {
private String favouriteProgrammingLanguage;
...
}
要从我们的数据库中删除所有喜欢Java作为其编程语言的怪胎,我们可以使用EntityManager的新createCriteriaDelete()
方法利用以下代码:
EntityTransaction transaction = null;
try {
transaction = entityManager.getTransaction();
transaction.begin();
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaDelete<Geek> delete = builder.createCriteriaDelete(Geek.class);
Root<Geek> geekRoot = delete.from(Geek.class);
delete.where(builder.equal(geekRoot.get("favouriteProgrammingLanguage"), "Java"));
int numberOfRowsUpdated = entityManager.createQuery(delete).executeUpdate();
LOGGER.info("Deleted " + numberOfRowsUpdated + " rows.");
transaction.commit();
} catch (Exception e) {
if (transaction != null && transaction.isActive()) {
transaction.rollback();
}
}
与纯SQL一样,我们可以使用from()
方法来指定要针对其发出删除查询的表,并可以使用where()
来声明谓词。 通过这种方式,标准API允许以动态方式定义批量删除操作,而无需使用过多的字符串连接。
但是,SQL是如何创建的呢? 首先,ORM提供程序必须注意,我们正在使用策略JOINED
从继承层次结构中删除,这意味着我们有两个表T_PERSON
和T_GEEK
,其中第二个表存储对父表的引用。 Hibernate版本4.3.8.Final
创建以下SQL语句:
insert
into
HT_T_GEEK
select
geek0_.id as id
from
T_GEEK geek0_
inner join
T_PERSON geek0_1_
on geek0_.id=geek0_1_.id
where
geek0_.FAV_PROG_LANG=?;
delete
from
T_GEEK
where
(
id
) IN (
select
id
from
HT_T_GEEK
);
delete
from
T_PERSON
where
(
id
) IN (
select
id
from
HT_T_GEEK
)
delete
from
HT_T_GEEK;
如我们所见,Hibernate使用与我们的搜索条件匹配的极客/人员的ID填充了一个临时表。 然后,它从极客表中删除所有行,然后从人员表中删除所有行。 最后,临时表被清除。
删除语句的顺序很明确,因为表T_GEEK
在T_PERSON
表的id列上具有外键约束。 因此,子表中的行必须在父表中的行之前删除。 本文介绍了Hibernate创建临时表的原因。 概括起来,潜在的问题是查询限制了仅在子表中存在的列上要删除的行。 但是子表中的行必须在父表中的相应行之前删除。 删除了子表中的行(即,所有具有FAV_PROG_LANG='Java'
的怪胎)之后,由于已经删除了怪胎行,因此无法随后删除所有对应的人员。 解决该问题的方法是临时表,该临时表首先收集应删除的所有行ID。 知道所有ID后,可以使用此信息先从怪胎表中删除行,然后再从人员表中删除行。
上面生成SQL语句当然与标准API的用法无关。 使用JPQL方法会导致生成相同SQL:
EntityTransaction transaction = null;
try {
transaction = entityManager.getTransaction();
transaction.begin();
int update = entityManager.createQuery("delete from Geek g where g.favouriteProgrammingLanguage = :lang").setParameter("lang", "Java").executeUpdate();
LOGGER.info("Deleted " + update + " rows.");
transaction.commit();
} catch (Exception e) {
if (transaction != null && transaction.isActive()) {
transaction.rollback();
}
}
当我们将继承策略从JOINED
更改为SINGLE_TABLE
,生成SQL语句也更改为单个(此处的鉴别DTYPE
列为DTYPE
):
delete
from
T_PERSON
where
DTYPE='Geek'
and FAV_PROG_LANG=?
结论
用于删除和更新的标准API的新增功能使您可以构造SQL语句,而无需任何字符串连接。 但是请注意,从继承层次结构中进行批量删除可能会强制基础ORM使用临时表,以便组装必须事先删除的行列表。
翻译自: https://www.javacodegeeks.com/2015/02/jpa-2-1-criteria-deleteupdate-temporary-tables-hibernate.html
jpa vue管理系统