文章目录
查询
1.二级缓存
节点:若 JPA 实现支持二级缓存,该节点可以配置在当前的持久化单元中是否启用二级缓存,可配置如下值:
- ALL:所有的实体类都被缓存
- NONE:所有的实体类都不被缓存.
- ENABLE_SELECTIVE:标识 @Cacheable(true) 注解的实体类将被缓存
- DISABLE_SELECTIVE:缓存除标识 @Cacheable(false) 以外的所有实体类
- UNSPECIFIED:默认值,JPA 产品默认值将被使用
@Test
public void testSecondLevelCache(){
//若是同一个manager,则查询时,是相同的,则只执行一个查询
Person person3 = entityManager.find(Person.class, 27);
Person person4 = entityManager.find(Person.class, 27);
//若不是同一个manager
Person person = entityManager.find(Person.class, 27);
transaction.commit();
entityManager.close();
//当重新获取一个manager后,再执行查询,则sql会再次执行
entityManager = entityManagerFactory.createEntityManager();
transaction = entityManager.getTransaction();
transaction.begin();
Person person2 = entityManager.find(Person.class, 27);
}
参考:
JPA-二级缓存
2.JPQL
2.1 介绍
JPQL语言,即 Java Persistence Query Language 的简称。JPQL 是一种和 SQL 非常类似的中间性和对象化查询语言,它最终会被编译成针对不同底层数据库的 SQL 查询,从而屏蔽不同数据库的差异。
JPQL语言的语句可以是 select 语句、update 语句或delete语句,它们都通过 Query 接口封装执行
2.2 javax.persistence.Query
Query接口封装了执行数据库查询的相关方法。调用 EntityManager 的 createQuery、create NamedQuery 及 createNativeQuery 方法可以获得查询对象,进而可调用 Query 接口的相关方法来执行查询操作。
Query接口的主要方法:
-
int
executeUpdate
()
用于执行update或delete语句。 -
List
getResultList
()
用于执行select语句并返回结果集实体列表。 -
Object
getSingleResult
()
用于执行只返回单个结果实体的select语句。 -
Query
setFirstResult
(int startPosition)
用于设置从哪个实体记录开始返回查询结果。 -
Query setMaxResults(int maxResult)
用于设置返回结果实体的最大数。与setFirstResult结合使用可实现分页查询。 -
Query
setFlushMode
(FlushModeType flushMode)
设置查询对象的Flush模式。参数可以取2个枚举值:FlushModeType.AUTO 为自动更新数据库记录,FlushMode Type.COMMIT 为直到提交事务时才更新数据库记录。 -
setHint
(String hintName, Object value)
设置与查询对象相关的特定供应商参数或提示信息。参数名及其取值需要参考特定 JPA 实现库提供商的文档。如果第二个参数无效将抛出IllegalArgumentException异常。 -
setParameter
(int position, Object value)
为查询语句的指定位置参数赋值。Position 指定参数序号,value 为赋给参数的值。 -
setParameter
(int position, Date d, TemporalType type)
为查询语句的指定位置参数赋 Date 值。Position 指定参数序号,value 为赋给参数的值,temporalType 取 TemporalType 的枚举常量,包括 DATE、TIME 及 TIMESTAMP 三个,,用于将 Java 的 Date 型值临时转换为数据库支持的日期时间类型(java.sql.Date、java.sql.Time及java.sql.Timestamp)。 -
setParameter
(int position, Calendar c, TemporalType type)
为查询语句的指定位置参数赋 Calenda r值。position 指定参数序号,value 为赋给参数的值,temporalType 的含义及取舍同前。 -
setParameter
(String name, Object value)
为查询语句的指定名称参数赋值。 -
setParameter
(String name, Date d, TemporalType type)
为查询语句的指定名称参数赋 Date 值。用法同前。 -
setParameter
(String name, Calendar c, TemporalType type)
为查询语句的指定名称参数设置Calendar值。name为参数名,其它同前。该方法调用时如果参数位置或参数名不正确,或者所赋的参数值类型不匹配,将抛出 IllegalArgumentException 异常。
2.3 select语法
select语句用于执行查询。其语法可表示为:
select_clause
form_clause
[where_clause]
[groupby_clause]
[having_clause]
[orderby_clause]
@Test
public void testHelloJPQL(){
String jpql = "FROM Person p WHERE p.pid > ?";
Query query = entityManager.createQuery(jpql);
//占位符的索引是从 1 开始
query.setParameter(1, 27);
List<Person> personList = query.getResultList();
System.out.println(personList.size());
}
2.4查询所有实体
- from 子句是查询语句的必选子句。
- Select 用来指定查询返回的结果实体或实体的某些属性
From 子句声明查询源实体类,并指定标识符变量(相当于SQL表的别名)。
如果不希望返回重复实体,可使用关键字 distinct 修饰。select、from 都是 JPQL 的关键字,通常全大写或全小写,建议不要大小写混用。
查询所有实体的 JPQL 查询字串很简单,例如:
select o from Order o 或 select o from Order as o
关键字 as 可以省去。
标识符变量的命名规范与 Java 标识符相同,且区分大小写。
调用 EntityManager 的 createQuery() 方法可创建查询对象,接着调用 Query 接口的 getResultList() 方法就可获得查询结果集。例如:
Query query = entityManager.createQuery( "select o from Order o");
List orders = query.getResultList();
Iterator iterator = orders.iterator();
while( iterator.hasNext() ) {
// 处理Order
}
2.5 where
where子句用于指定查询条件,where跟条件表达式。例:
select o from Orders o where o.id = 1
select o from Orders o where o.id > 3 and o.confirm = 'true'
select o from Orders o where o.address.streetNumber >= 123
JPQL也支持包含参数的查询,例如:
select o from Orders o where o.id = :myId
select o from Orders o where o.id = :myId and o.customer = :customerName
注意:参数名前必须冠以冒号(:),执行查询前须使用Query.setParameter(name, value)方法给参数赋值。
也可以不使用参数名而使用参数的序号,例如:
select o from Order o where o.id = ?1 and o.customer = ?2
其中 ?1 代表第一个参数,?2 代表第一个参数。在执行查询之前需要使用重载方法Query.setParameter(pos, value) 提供参数值。
Query query = entityManager.createQuery( "select o from Orders o where o.id = ?1 and o.customer = ?2" );
query.setParameter( 1, 2 );
query.setParameter( 2, "John" );
List orders = query.getResultList();
where条件表达式中可用的运算符基本上与SQL一致,包括:
算术运算符:+ - * / +(正) -(负)
关系运算符:== <> > >= < <= between…and like in is null 等
逻辑运算符: and or not
例如:
下面是一些常见查询表达式示例:
// 以下语句查询 Id 介于 100 至 200 之间的订单。
select o from Orders o where o.id between 100 and 200
// 以下语句查询国籍为的 'US'、'CN'或'JP' 的客户。
select c from Customers c where c.county in ('US','CN','JP')
// 以下语句查询手机号以139开头的客户。%表示任意多个字符序列,包括0个。
select c from Customers c where c.phone like '139%'
// 以下语句查询名字包含4个字符,且234位为ose的客户。_表示任意单个字符。
select c from Customers c where c.lname like '_ose'
// 以下语句查询电话号码未知的客户。Nul l用于测试单值是否为空。
select c from Customers c where c.phone is null
// 以下语句查询尚未输入订单项的订单。empty用于测试集合是否为空。
select o from Orders o where o.orderItems is empty
… …
2.6 查询部分属性
如果只须查询实体的部分属性而不需要返回整个实体。例如:
select o.id, o.customerName, o.address.streetNumber from Order o order by o.id
执行该查询返回的不再是Orders实体集合,而是一个对象数组的集合(Object[]),集合的每个成员为一个对象数组,可通过数组元素访问各个属性。
2.7 order by
order by子句用于对查询结果集进行排序。和SQL的用法类似,可以用 “asc“ 和 "desc“ 指定升降序。如果不显式注明,默认为升序。
select o from Orders o order by o.id
select o from Orders o order by o.address.streetNumber desc
select o from Orders o order by o.customer asc, o.id desc
2.8 group by
group by 子句用于对查询结果分组统计,通常需要使用聚合函数。常用的聚合函数主要有 AVG、SUM、COUNT、MAX、MIN 等,它们的含义与SQL相同。例如:
select max(o.id) from Orders o
没有 group by 子句的查询是基于整个实体类的,使用聚合函数将返回单个结果值,可以使用Query.getSingleResult()得到查询结果。例如:
Query query = entityManager.createQuery(
"select max(o.id) from Orders o");
Object result = query.getSingleResult();
Long max = (Long)result;
2.9 Having
Having 子句用于对 group by 分组设置约束条件,用法与where 子句基本相同,不同是 where 子句作用于基表或视图,以便从中选择满足条件的记录;having 子句则作用于分组,用于选择满足条件的组,其条件表达式中通常会使用聚合函数。
例如,以下语句用于查询订购总数大于100的商家所售商品及数量:
select o.seller, o.goodId, sum(o.amount) from V_Orders o group by
o.seller, o.goodId having sum(o.amount) > 100
having子句与where子句一样都可以使用参数。
2.10 关联查询
在JPQL中,很多时候都是通过在实体类中配置实体关联的类属性来实现隐含的关联(join)查询。例如:
select o from Orders o where o.address.streetNumber=2000
上述JPQL语句编译成以下SQL时就会自动包含关联,默认为左关联。
在某些情况下可能仍然需要对关联做精确的控制。为此,JPQL 也支持和 SQL 中类似的关联语法。如:
left out join / left join
inner join
left join / inner join fetch
其中,left join和left out join等义,都是允许符合条件的右边表达式中的实体为空。
例如,以下外关联查询可以找出所有客户实体记录,即使它未曾订货:
select c from Customers c left join c.orders o
以下内关联查询只找出所有曾订过商品的客户实体记录:
select c from Customers c inner join c.orders o
如果001号客户下过5次订单的话,以下fetch关联查询将得到 5个客户实体的引用,并且执行了 5 个订单的查询:
select c from Customers c left join fetch c.orders o where c.id=001
2.11 子查询
JPQL也支持子查询,在 where 或 having 子句中可以包含另一个查询。当子查询返回多于 1 个结果集时,它常出现在 any、all、exist s表达式中用于集合匹配查询。它们的用法与SQL语句基本相同。
2.12 JPQL函数
JPQL提供了以下一些内建函数,包括字符串处理函数、算术函数和日期函数。
字符串处理函数主要有:
concat(String s1, String s2):字符串合并/连接函数。
substring(String s, int start, int length):取字串函数。
trim([leading|trailing|both,] [char c,] String s):从字符串中去掉首/尾指定的字符或空格。
lower(String s):将字符串转换成小写形式。
upper(String s):将字符串转换成大写形式。
length(String s):求字符串的长度。
locate(String s1, String s2[, int start]):从第一个字符串中查找第二个字符串(子串)出现的位置。若未找到则返回0。
3.与Spring整合
三种整合方式:
- LocalEntityManagerFactoryBean:适用于那些仅使用 JPA 进行数据访问的项目,该 FactoryBean 将根据JPA PersistenceProvider 自动检测配置文件进行工作,一般从“META-INF/persistence.xml”读取配置信息,这种方式最简单,但不能设置 Spring 中定义的DataSource,且不支持 Spring 管理的全局事务
- 从JNDI中获取:用于从 Java EE 服务器获取指定的EntityManagerFactory,这种方式在进行 Spring 事务管理时一般要使用 JTA 事务管理
- LocalContainerEntityManagerFactoryBean:适用于所有环境的 FactoryBean,能全面控制 EntityManagerFactory 配置,如指定 Spring 定义的 DataSource 等等。