JPQL就是一种查询语言,具有与SQL 相类似的特征,JPQL是完全面向对象的,具备继承、多态和关联等特性,和hibernate HQL很相似。
 
查询语句的参数
JPQL语句支持两种方式的参数定义方式: 命名参数和位置参数。。在同一个查询语句中只允许使用一种参数定义方式。
 
命令参数的格式为:“: +参数名”
例:
Query query = em.createQuery("select p from Person p where p.personid=:Id");
query.setParameter("Id",new Integer(1));
 
位置参数的格式为“?+位置编号”
例:
Query query = em.createQuery("select p from Person p where p.personid=?1");
query.setParameter(1,new Integer(1));
 
 
如果你需要传递java.util.Date或java.util.Calendar参数进一个参数查询,你需要使用一个特殊的setParameter()方法,相关的setParameter方法定义如下:
 
public interface Query
{
//命名参数查询时使用,参数类型为java.util.Date
Query setParameter(String name, java.util.Date value, TemporalType temporalType);
//命名参数查询时使用,参数类型为java.util.Calendar
Query setParameter(String name, Calendar value, TemporalType temporalType);
//位置参数查询时使用,参数类型为java.util.Date
Query setParameter(int position, Date value, TemporalType temporalType);
//位置参数查询时使用,参数类型为java.util.Calendar
Query setParameter(int position, Calendar value, TemporalType temporalType);
}
 
因为一个Date或Calendar对象能够描述一个真实的日期、时间或时间戳.所以我们需要告诉Query对象怎么使用这些参数,我们把javax.persistence.TemporalType作为参数传递进setParameter方法,告诉查询接口在转换java.util.Date或java.util.Calendar参数到本地SQL时使用什么数据库类型。
 
下面通过实例来学习JPQL语句,例子的entity Bean有Person, Order, OrderItem,他们之间的关系是:一个Person有多个Order,一个Order有多个OrderItem。
 
JPQL语句的大小写敏感性:除了Java 类和属性名称外,查询都是大小写不敏感的。所以,SeLeCT和sELEct以及SELECT相同的,但是com.foshanshop.ejb3.bean.Person和com.foshanshop.ejb3.bean.PERSon是不同的,person.name和person.NAME也是不同的。
 
 
命名查询
可以在实体bean上通过@NamedQuery or @NamedQueries预先定义一个或多个查询语句,减少每次因书写错误而引起的BUG。通常把经常使用的查询语句定义成命名查询。
 
定义单个命名查询:
@NamedQuery(name="getPerson", query= "FROM Person WHERE personid=?1")
@Entity
public class Person implements Serializable{
 
如果要定义多个命名查询,应在@javax.persistence.NamedQueries里定义@NamedQuery:
@NamedQueries({
@NamedQuery(name="getPerson", query= "FROM Person WHERE personid=?1"),
@NamedQuery(name="getPersonList", query= "FROM Person WHERE age>?1")
})
@Entity
public class Person implements Serializable{
 
当命名查询定义好了之后,我们就可以通过名称执行其查询。代码如下:
Query query = em.createNamedQuery("getPerson");
query.setParameter(1, 1);
 
 
排序(order by)
"ASC"和"DESC"分别为升序和降序,JPQL中默认为asc升序
例:
//先按年龄降序排序,然后按出生日期升序排序
Query query = em.createQuery("select p from Person p order by p.age desc, p.birthday asc");
 
查询部分属性
通常来说,都是针对Entity类的查询,返回的也是被查询的Entity类的实体。JPQL也允许我们直接查询返回我们需要的属性,而不是返回整个Entity。在一些Entity中属性特别多的情况,这样的查询可以提高性能
例:
//只查询我们感兴趣的属性(列)
Query query=em.createQuery("select p.personid, p.name from Person p order by p.personid desc ");
//集合中的元素不再是Person,而是一个Object[]对象数组
List result = query.getResultList();
if (result!=null){
Iterator iterator = result.iterator();
while( iterator.hasNext() ){
Object[] row = ( Object[]) iterator.next();
int personid = Integer.parseInt(row[0].toString());
String PersonName = row[1].toString();
。。。。
}
}
 
查询中使用构造器(Constructor)
JPQL支持将查询的属性结果直接作为一个java class的构造器参数,并产生实体作为结果返回。例如上面的例子只获取person entity bean的name and personid属性,我们不希望返回的集合的元素是object[],而希望用一个类来包装它。就要用到使用构造器
例:
public class SimplePerson {
 private Integer personid;
private String name;
   。。。。
public SimplePerson() {
}
public SimplePerson(Integer personid, String name) {
this.name = name;
this. personid = personid;
}
}
 
查询代码为:
//我们把需要的两个属性作为SimplePerson的构造器参数,并使用new 函数。
Query query = em.createQuery("select new com.foshanshop.ejb3.bean.SimplePerson(p. personid, p.name) from Person p order by p.personid desc");
//集合中的元素是SimplePerson 对象
List result = query.getResultList();
if (result!=null){
Iterator iterator = result.iterator();
while( iterator.hasNext() ){
SimplePerson simpleperson = (SimplePerson) iterator.next();
。。。。
}
}
 
聚合查询(Aggregation)
JPQL支持的聚合函数包括:
1. AVG()
2. SUM()
3. COUNT(),返回类型为Long,注意count(*)语法在hibernate中可用,但在toplink 其它产品中并不可用
4. MAX()
5. MIN()
 
例:
//获取最大年龄
Query query = em.createQuery("select max(p.age) from Person p");
Object result = query.getSingleResult();
String maxAge = result.toString();
//获取平均年龄
query = em.createQuery("select avg(p.age) from Person p");
//获取最小年龄
query = em.createQuery("select min(p.age) from Person p");
//获取总人数
query = em.createQuery("select count(p) from Person p");
//获取年龄总和
query = em.createQuery("select sum(p.age) from Person p");
 
如果聚合函数不是select...from的唯一一个返回列,需要使用"GROUP BY"语句。"GROUP BY"应该包含select 语句中除了聚合函数外的所有属性。
例:
//返回男女生各自的总人数
Query query = em.createQuery("select p.sex, count(p) from Person p group by p.sex");
//集合中的元素不再是Person,而是一个Object[]对象数组
List result = query.getResultList();
 
如果还需要加上查询条件,需要使用"HAVING"条件语句而不是"WHERE"语句
例:
//返回人数超过1人的性别
Query query = em.createQuery("select p.sex, count(p) from Person p group by p.sex having count(*)>?1");
//设置查询中的参数
query.setParameter(1, new Long(1));
//集合中的元素不再是Person,而是一个Object[]对象数组
List result = query.getResultList();
关联(join)
JPQL仍然支持和SQL中类似的关联语法:
left out join/left join
inner join
left join fetch/inner join fetch
 
 
left out join/left join等,都是允许符合条件的右边表达式中的Entiies 为空(需要显式使用left join/left outer join 的情况会比较少。
例:
//获取26岁人的订单,不管Order中是否有OrderItem
select o from Order o left join o.orderItems where o.ower.age=26 order by o.orderid
 
 
inner join 要求右边的表达式必须返回Entities
例:
//获取26 岁人的订单,Order 中必须要有OrderItem
select o from Order o inner join o.orderItems where o.ower.age=26 order by o.orderid
 
 
!!重要知识点在默认的查询中,Entity中的集合属性默认不会被关联,集合属性默认是延迟加载( lazy-load )。那么,left fetch/left out fetch/inner join fetch提供了一种灵活的查询加载方式来提高查询的性能。
例:
private String QueryInnerJoinLazyLoad(){
// 默认不关联集合属性变量(orderItems)对应的表
Query query = em.createQuery("select o from Order o inner join o.orderItems where o.ower.age=26 order by o.orderid");
List result = query.getResultList();
if (result!=null && result.size()>0){
//这时获得Order 实体中orderItems( 集合属性变量)为空
Order order = (Order) result.get(0);
//当需要时,EJB3 Runtime才会执行一条SQL语句来加载属于当前Order
//OrderItems
Set<OrderItem> list = order.getOrderItems();
Iterator<OrderItem> iterator = list.iterator();
if (iterator.hasNext()){
OrderItem orderItem =iterator.next();
System.out.println ("订购产品名:"+ orderItem.getProductname());
}
}
 
上面代码在执行"select o from Order o inner join o.orderItems where o.ower.age=26 order by o.orderid"时编译成的SQL如下(他不包含集合属性变量(orderItems)对应表的字段):
select order0_.orderid as orderid6_, order0_.amount as amount6_, order0_.person_id as
person4_6_, order0_.createdate as createdate6_ from Orders order0_ inner join OrderItems
orderitems1_ on order0_.orderid=orderitems1_.order_id, Person person2_ where
order0_.person_id=person2_.personid and person2_.age=26 order by order0_.orderid
 
 
上面代码当执行到Set<OrderItem> list = order.getOrderItems();时才会执行一条SQL语句来加载属于当前Order的OrderItems,编译成的SQL 如下:
select orderitems0_.order_id as order4_1_, orderitems0_.id as id1_, orderitems0_.id as id7_0_,
orderitems0_.order_id as order4_7_0_, orderitems0_.productname as productn2_7_0_,
orderitems0_.price as price7_0_ from OrderItems orderitems0_ where orderitems0_.order_id=?
order by orderitems0_.id ASC
 
这样的查询性能上有不足的地方。为了查询N个Order,我们需要一条SQL语句获得所有的Order的原始对象属性,但需要另外N 条语句获得每个Order的orderItems集合属性。为了避免N+1的性能问题,我们可以利用join fetch一次过用一条SQL语句把Order的所有信息查询出来
 
例子
//获取26 岁人的订单,Order 中必须要有OrderItem
Query query = em.createQuery("select o from Order o inner join fetch o.orderItems where
o.ower.age=26 order by o.orderid");
 
上面这句HPQL编译成以下的SQL:
select order0_.orderid as orderid18_0_, orderitems1_.id as id19_1_, order0_.amount as
amount18_0_,order0_.person_id as person4_18_0_, order0_.createdate as createdate18_0_,
orderitems1_.order_id as order4_19_1_, orderitems1_.productname as productn2_19_1_,
orderitems1_.price as price19_1_, orderitems1_.order_id as order4_0__, orderitems1_.id as id0__
from Orders order0_ inner join OrderItems orderitems1_ on
order0_.orderid=orderitems1_.order_id, Person person2_ where
order0_.person_id=person2_.personid and person2_.age=26 order by order0_.orderid,
orderitems1_.id ASC
 
上面由于使用了fetch,这个查询只会产生一条SQL语句,比原来需要N+1 条SQL语句在性能上有了极大的提升
 
 
排除相同的记录DISTINCT
使用关联查询,我们很经常得到重复的对象,如下面语句:
"select o from Order o inner join fetch o.orderItems order by o.orderid "
当有N 个orderItem 时就会产生N个Order,而有些Order对象往往是相同的,这时我们需要使用DISTINCT关键字来排除掉相同的对象。
例:
select DISTINCT o from Order o inner join fetch o.orderItems order by o.orderid
 
 
 
比较Entity
在查询中使用参数查询时,参数类型除了String, 原始数据类型( int, double等)和它们的对象类型( Integer, Double等),也可以是Entity的实例。
例:
//查询某人的所有订单
Query query = em.createQuery("select o from Order o where o.ower =?1 order by o.orderid");
Person person = new Person();
person.setPersonid(new Integer(1));
//设置查询中的参数
query.setParameter(1,person);
 
 
批量更新(Batch Update)
HPQL支持批量更新
例:
//把所有订单的金额加10
Query query = em.createQuery("update Order as o set o.amount=o.amount+10");
//update 的记录数
int result = query.executeUpdate();
 
 
批量删除(Batch Remove)
例:
//把金额小于100的订单删除,先删除订单子项,再删除订单
Query query = em.createQuery("delete from OrderItem item where item.order in(from Order as o where o.amount<100)");
query.executeUpdate();
query = em.createQuery("delete from Order as o where o.amount<100");
query.executeUpdate();//delete的记录数
 
 
使用操作符NOT
//查询除了指定人之外的所有订单
Query query = em.createQuery("select o from Order o where not(o.ower =?1) order by o.orderid");
Person person = new Person();
person.setPersonid(new Integer(2));
//设置查询中的参数
query.setParameter(1,person);
 
 
使用操作符BETWEEN
select o from Order as o where o.amount between 300 and 1000
 
使用操作符IN
//查找年龄为26,21 的Person
select p from Person as p where p.age in(26,21)
 
使用操作符LIKE
//查找以字符串"li"开头的Person
select p from Person as p where p.name like 'li%'
 
使用操作符IS NULL
//查询含有购买者的所有Order
select o from Order as o where o.ower is [not] null
 
使用操作符IS EMPTY
IS EMPTY是针对集合属性(Collection)的操作符。可以和NOT 一起使用。注:低版权的Mysql 不支持IS EMPTY
//查询含有订单项的所有Order
select o from Order as o where o.orderItems is [not] empty
 
使用操作符EXISTS
[NOT]EXISTS 需要和子查询配合使用。注:低版权的Mysql 不支持EXISTS
//如果存在订单号为1 的订单,就获取所有OrderItem
select oi from OrderItem as oi where exists (select o from Order o where o.orderid=1)
//如果不存在订单号为10 的订单,就获取id 为1 的OrderItem
select oi from OrderItem as oi where oi.id=1 and not exists (select o from Order o where o.orderid=10)
 
 
字符串函数
JPQL定义了内置函数方便使用。这些函数的使用方法和SQL中相应的函数方法类似。包括:
1. CONCAT 字符串拼接
2. SUBSTRING 字符串截取
3. TRIM 去掉空格
4. LOWER 转换成小写
5. UPPER 装换成大写
6. LENGTH 字符串长度
7. LOCATE 字符串定位
 
例:
//查询所有人员,并在姓名后面加上字符串"_foshan"
select p.personid, concat(p.name, '_foshan') from Person as p
//查询所有人员,只取姓名的前三个字符
select p.personid, substring(p.name,1,3) from Person as p
 
计算函数
HPQL定义的计算函数包括:
ABS 绝对值
SQRT 平方根
MOD 取余数
SIZE 取集合的数量
 
例:
//查询所有Order 的订单号及其订单项的数量
select o.orderid, size(o.orderItems) from Order as o group by o.orderid
//查询所有Order 的订单号及其总金额/10 的余数
select o.orderid, mod(o.amount, 10) from Order as o
 
 
子查询
子查询可以用于WHERE HAVING 条件语句中
例:
//查询年龄为26 岁的购买者的所有Order
select o from Order as o where o.ower in(select p from Person as p where p.age =26)
 
 
结果集分页
有些时候当执行一个查询会返回成千上万条记录,事实上我们只需要显示一部分数据。这时我们需要对结果集进行分页,QueryAPI有两个接口方法可以解决这个问题:setMaxResults( ) setFirstResult( )
 
setMaxResults方法设置获取多少条记录
setFirstResult方法设置从结果集中的那个索引开始获取(假如返回的记录有3条,容器会自动为记录编上索引,索引从0开始,依次为0,1,2)
 
例:
public List getPersonList(int max,int whichpage) {
try {
int index = (whichpage-1) * max;
Query query = em.createQuery("from Person p order by personid asc");
List list = query.setMaxResults(max).
setFirstResult(index).
getResultList();
em.clear();//分离内存中受EntityManager管理的实体bean,让VM进行垃圾回收
return list;
} catch (Exception e) {
e.printStackTrace();
return null;
}
 
createNativeQuery查询
package com.test.jpa.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table; @Entity
@Table(name="t_user")
public class User {
/**
* 主键
*/
@Id
@GeneratedValue
private Long id; /**
* 名字
*/
@Column(name="name",length=50)
private String name; /**
* 密码
*/
@Column(name="password",length=20)
private String password;
/**
* 邮箱
*/
@Column(name="email",length=50)
private String email; /**
* 年龄
*/
@Column(name="age",length=3)
private int age;
public User() { }
//以下省略getter/setter方法
//......
}
package com.cndatacom.jpa.test;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query; import org.junit.After;
import org.junit.Before;
import org.junit.Test; import com.cndatacom.jpa.entity.User; /**
* 测试JPA原生SQL查询
* @author Luxh
*/
public class TestNativeQuery {
EntityManagerFactory emf = null; @Before
public void before() {
//根据在persistence.xml中配置的persistence-unit name 创建EntityManagerFactory
emf = Persistence.createEntityManagerFactory("myJPA");
} @After
public void after() {
//关闭EntityManagerFactory
if(null != emf) {
emf.close();
}
} /**
* 查询的结果是对象数组的集合
*/
@Test
public void testNativeQuery1() {
EntityManager em = emf.createEntityManager();
//定义SQL
String sql = "SELECT * FROM t_user";
//创建原生SQL查询QUERY实例
Query query = em.createNativeQuery(sql);
//执行查询,返回的是对象数组(Object[])列表,
//每一个对象数组存的是相应的实体属性
List objecArraytList = query.getResultList();
for(int i=0;i<objecArraytList.size();i++) {
Object[] obj = (Object[]) objecArraytList.get(i);
//使用obj[0],obj[1],obj[2]...取出属性    
}
em.close();
} /**
* 查询的结果是实体的集合
*/
@Test
public void testNativeQuery2() {
EntityManager em = emf.createEntityManager();
//定义SQL
String sql = "SELECT * FROM t_user";
//创建原生SQL查询QUERY实例,指定了返回的实体类型
Query query = em.createNativeQuery(sql,User.class);
//执行查询,返回的是实体列表,
List<User> userList = query.getResultList(); em.close();
} /**
* 查询单个属性
* 返回的是这个属性值的集合
*/
@Test
public void testNativeQuery3() {
EntityManager em = emf.createEntityManager();
//定义SQL
String sql = "SELECT t.name FROM t_user t";
//创建原生SQL查询QUERY实例
Query query = em.createNativeQuery(sql);
//执行查询,返回的是String类型的集合,因为name这个属性是String类型
List<String> resultList = query.getResultList();
em.close();
} /**
     * 查询多个属性
     * 返回的是这些属性值的数组的集合
    */
@Test
public void testNativeQuery4() {
EntityManager em = emf.createEntityManager();
//定义SQL
String sql = "SELECT t.name,t.age,t.email FROM t_user t";
//创建原生SQL查询QUERY实例
Query query = em.createNativeQuery(sql);
//执行查询,返回的是查询属性值数组的集合
List objecArraytList = query.getResultList();
for(int i=0;i<objecArraytList.size();i++) {
Object[] obj = (Object[]) objecArraytList.get(i);
//使用obj[0],obj[1],obj[2]取出属性
}
em.close(); } }

EJB JPQL语句查询的更多相关文章

  1. JPA学习---第八节:使用JPQL语句进行查询

    1.JPQL 语句查询,代码如下: @Test public void query(){ EntityManagerFactory factory = Persistence.createEntity ...

  2. SpringData JPA使用JPQL的方式查询和使用SQL语句查询

    使用Spring Data JPA提供的查询方法已经可以解决大部分的应用场景,但是对于某些业务来说,我们还需要灵活的构造查询条件, 这时就可以使用@Query注解,结合JPQL的语句方式完成查询 持久 ...

  3. 通过sql语句查询出来的结果字段没有到对应实体类时的处理方法

    通过sql语句查询出来的结果字段没有到对应实体类时的处理方法,对于Person类获取用户第一个名字和年龄两个字段,常见的有两种方式: 1.在创建一个与查询结果字段对应的类,然后通过构造函数实现: Qu ...

  4. IDEA 增加对JPA的支持 执行JPQL语句

    IDEA 可以在控制台console中执行JPQL语句: 1. 在已存在的项目中选择项目结构: 2. 选择模块-指定实体所在的模块-选择上面的号 2. 选择要添加的模块:我们使用的是JPA,也可能有的 ...

  5. sql语句查询

    1. sql语句查询某位数字或者某几位数字开头的数据,字段类型为数字类: %’: 2. sql搜索以4开头和含有李字的数据: select * from wlzbpre_user where real ...

  6. phpcmsv9自定义sql语句查询模型实现

    在phpcmsv9中,自定义sql语句查询可不太好实现,传入sql语句查询很容易被内部转入生成一系列莫名其妙的sql语句,比如最佳前缀等等,直接造成sql语句查询错误,在此也提供两种解决办法,1修改底 ...

  7. 怎样用SQL语句查询一个数据库中的所有表?

    怎样用SQL语句查询一个数据库中的所有表?  --读取库中的所有表名 select name from sysobjects where xtype='u'--读取指定表的所有列名select nam ...

  8. SQL语句查询某表的所有字段及数据类型

    SQL语句查询某表的所有字段及数据类型 SELECT name AS column_name , TYPE_NAME(system_type_id) AS column_type , max_leng ...

  9. sql语句查询数据库表结构信息

    开发中经常用到查询指定表及其字段的信息,以下是我整理的SQL语句查询方法,供自己平时使用也提供给大家参考! 1.适用MS SQL SERVER: SELECT 表名 = then d.name els ...

随机推荐

  1. TOJ 2888 Pearls

    Description In Pearlania everybody is fond of pearls. One company, called The Royal Pearl, produces ...

  2. nyoj 983 ——首尾相连数组的最大子数组和——————【最大子串和变形】

    首尾相连数组的最大子数组和 时间限制:1000 ms  |  内存限制:65535 KB 难度:4   描述 给定一个由N个整数元素组成的数组arr,数组中有正数也有负数,这个数组不是一般的数组,其首 ...

  3. 小程序中搜索文件,阅览pdf,分享文件链接,评论表情符号

    小程序中搜索文件,阅览pdf,分享文件链接,评论表情符号 https://blog.csdn.net/hotqin888/article/details/84111389 小程序中打开网页和pdf h ...

  4. mysql多表条件更新

    有两张表bas_student.bas_householder, 去除学生表中与家长表重复的手机号 UPDATE bas_student a,bas_householder b SET a.mobil ...

  5. web.config节点

    1.clientCache 源码: <system.webServer> <staticContent> <clientCache cacheControlMode=&q ...

  6. div居中方法总结

    在日常开发过程中,我们会经常使用到div居中来处理布局,今天我就把我在开发过程中,遇到的div居中处理方法总结一下,方便日后查看!        1. 水平居中:给div设置一个宽度,然后添加marg ...

  7. 对 Vue 的理解(一)

    一.什么是 Vue ? 首先,Vue 是一个 MVVM 框架,M -- 模型,就是用来定义驱动的数据,V -- 视图,是经过数据改变后的 html,VM -- 框架视图,就是用来实现双向绑定的中间桥梁 ...

  8. linux服务器上创建svn版本库

    1. 创建存放各个svn版本库的目录svnrepos(自己定义路径) -bash: cd /usr/local/apache/htdocs/ -bash: mkdir svnrepos 2. 假设我要 ...

  9. freebsd mount linprocfs

    mount用来做什么? to prepare and graft a special device or the remote node(rhost:path) on to the file syst ...

  10. Enumeration 接口的使用

          Enumeration是一个接口,定义了两个规则,可以获取连续的数据,对数据结构非常重要.       接口源码: publicinterfaceEnumeration<E>{ ...