高尔基曾经说过——"要想用好Spring Data Jpa,必须学会JPQL"。
嘿嘿嘿。学过Hibernate的同学可能知道,hibernate中有一个hql,它跟数据库无关,可以自动翻译成对应数据库的sql,
JPQL也是如此,它是一个可移植的面向对象的语言。直接开始吧,我等不及了!
要从 Java 代码内发出 JPQL 查询,您需要利用 EntityManager API 和 Query API 的相应方法,执行以下一般步骤:
1. 使用注入或通过 EntityManagerFactory 实例获取一个 EntityManager 实例。
2. 通过调用相应 EntityManager 的方法(如 createQuery),创建一个 Query 实例。
3. 如果有查询参数,使用相应 Query 的 setParameter 方法进行设置。
4. 如果需要,使用 setMaxResults 和/或 setFirstResult Query 的方法设置要检索的实例的最大数量和/或指定检索的起始实例位置。
5. 如果需要,使用 setHint Query 的方法设置供应商特定的提示。
6. 如果需要,使用 setFlushMode Query 的方法设置查询执行的刷新模式,覆盖实体管理器的刷新模式。
7. 使用相应 Query 的方法 getSingleResult 或 getResultList 执行查询。如果进行更新或删除操作,您必须使用 executeUpdate 方法,它返回已更新或删除的实体实例的数量。
@PersistenceContext
private EntityManager em; // 注入实体管理器
@SuppressWarnings("unchecked")
public Page search(User user) {
String dataSql = "select t from User t where 1 = 1";
String countSql = "select count(t) from User t where 1 = 1";
if(null != user && !StringUtils.isEmpty(user.getName())) {
dataSql += " and t.name = ?1";
countSql += " and t.name = ?1";
}
Query dataQuery = em.createQuery(dataSql);
Query countQuery = em.createQuery(countSql);
if(null != user && !StringUtils.isEmpty(user.getName())) {
dataQuery.setParameter(1, user.getName());
countQuery.setParameter(1, user.getName());
}long totalSize = (long) countQuery.getSingleResult();
Page page = new Page();
page.setTotalSize(totalSize);
List data = dataQuery.getResultList();
page.setData(data);
return page;
}
JPQL详细介绍
User -------------->interests 多对多关系,
JPQL :
select u from User u
select u.name u.income from User u
貌似和sql没啥区别对吧, 好到这里先做个简单实例,我们现说下概念:
算术运算符:
+ - * /
select u from User u where (u.income + 2000) = 5000
关系运算符:
= > < >= <=
逻辑运算符:
between,like,in,is null,is empty,member of ,not,and ,or
is null 用来判断普通属性,
is empty用来判断集合属性,
member of的话,emmm.。。。。举个栗子:
查出所有喜欢体育的User:select u from User u where :interest member of u.interests
(冒号加一个名字是JPQL的一种传参方式见下面的JPQL动态查询)这里的:interests是传入的体育这个兴趣实体对象,没错就是Java对象!
JPQL函数
字符串函数:
concat,substring,trim,upper,lower,length,locate
concat拼接字符串,
trim(leading,'小', from u.name)表示去掉左边的'小'字符串
trailing表示右边,both表示两边, 而去掉空格能直接trim(u.name)
locate是定位函数,locate('小',u.name,1)表示'小'出现的位置,开始找的位置最小从1开始。
时间函数:
CURRENT_DATE 日期,CURRENT_TIME 时间, CURRENT_TIMESTAMP日期时间
算术函数:
ABS绝对值
SQRT平方根
MOD取模
SIZE集合数量(只用在where 中)
例如:select u.name from User u where size(u.interests)=2 查出有2个兴趣的人。
JPQL分页:
和Hibernate差不多,用Query的setFirstResult和setMaxResult设置开始位置和个数
JPQL分组查询:
group by ..... having
聚合函数:avg(distinct),sum(distinct),count(distinct),min(distinct),max(distinct)
JPQL连接查询:
左连接:
selecy a.id,a.name,b.id,b.name from A a left join a.b b
关联查询:
select u from User u (left) join fetch u.interests i
JPQL动态查询:
基于位置参数 : 用?接数字表示参数位置,如?1,?2,设置参数就query.setparameter(1,name);
基于名称绑定: 用:id 冒号加上一个参数名字,query.setparameter("id",name);
查询中使用构造器(Constructor)
可以在SELECT子句中使用构造器返回一个或多个java实例。如下所示:
Query query = em.createQuery("select new com.demo.bean.Person(p.id, p.name) from Person p order by p.id desc");
JPQL本地化查询,即直接使用sql查询,移植到其他数据库需要修改代码,并且需要手动做结果映射:
Query query = entityManager.createNativeQuery("");
命名查询
可以在实体bean上通过@NamedQuery or @NamedQueries预先定义一个或多个查询语句,减少每次因书写错误而引起的BUG。通常把使用频率高的查询语句定义成命名查询。
定义单个命名查询:
@NamedQuery(name="getPerson", query= "select p from Person p where p.id=?1")
@Entity
public class Person implements Serializable{
如果要定义多个命名查询,应在@javax.persistence.NamedQueries里定义@NamedQuery:
@NamedQueries({
@NamedQuery(name="getPerson", query= "select p from Person p where p.id=?1"),
@NamedQuery(name="getPersonList", query= "select p from Person as p where p.age>?1")
})
@Entity
public class Person implements Serializable{
当命名查询定义好了之后,我们就可以通过名称执行其查询。代码如下:
Query query = em.createNamedQuery("getPerson");
query.setParameter(1, 1);
就到这里吧,下一张讲高级查询,博客写的不好,有什么问题直接家QQ问我,或者留言都行。。