JPQL查询实例

来源:互联网 发布:艾克里里淘宝店铺号 编辑:程序博客网 时间:2024/06/15 03:32

前面学习了JPQL语言和Query接口。这里学习一下如果通过JPQL和Query接口进行数据的查询、更新和删除。

【1】普通查询

首先说明一下FROM子句和Select-FROM。

from 子句是查询语句的必选子句。

Select 用来指定查询返回的结果实体或实体的某些属性。

From 子句声明查询源实体类,并指定标识符变量(相当于SQL表的别名)。

如果不希望返回重复实体,可使用关键字 distinct 修饰。select、from 都是 JPQL 的关键字,通常全大写或全小写,建议不要大小写混用。

代码实例如下:

        @Test        public void testHelloJPQL(){            String jpql = "select c FROM Customer c WHERE c.age > ?";            Query query = (Query) entityManager.createQuery(jpql);            //占位符的索引是从 1 开始            query.setParameter(1, 1);            List<Customer> customers = query.getResultList();            System.out.println(customers.size());        }

控制台输出如下:

这里写图片描述


可以看到就是一条普通的查询语句。

但是在写JPQL时,需要注意,这一切面向对象。即对象+属性相当于表+列。

如果不写 select 而是直接使用from子句,表明获取对象的全部属性。

Stringjpql = FROM Customer c WHERE c.age > ?;

查询一个对象的所有属性时,并不能像MySQL那样使用 * 号标志。

下面语句是错误的,不符合JPQL的规范。

select * FROM Customer c WHERE c.age > ?

当然,你可以查询部分属性。

代码实例如下:

        @Test        public void testPartlyProperties(){            String jpql = "SELECT c.lastName, c.age FROM Customer c WHERE c.id > ?";            List result = entityManager.createQuery(jpql).setParameter(1, 1).getResultList();            System.out.println(result);            Object[] objects = (Object[]) result.get(0);            System.out.println(objects[0]);        }

控制台输出如下:

这里写图片描述


可以看到,获取到的list是一个list<object[]>,解析起来是比较麻烦的。

故而,我们更希望使用如下方式:

@Test        public void testPartlyProperties(){            String jpql = "SELECT new Customer(c.lastName, c.age) FROM Customer c WHERE c.id > ?";            List result = entityManager.createQuery(jpql).setParameter(1, 1).getResultList();            System.out.println(result);        }

控制台输出如下:

这里写图片描述

这样获取到的是list<Customer>,这样解析起来就很友好了。


【2】createNamedQuery和createNativeQuery

createNamedQuery 适用于在实体类前使用 @NamedQuery 标记的查询语句。

如下:

@NamedQuery(name="testNamedQuery", query="FROM Customer c WHERE c.id = ?")@Cacheable(true)@Table(name="jpa_cutomers")@Entitypublic class Customer {    private Integer id;    private String lastName;    private String email;    private int age;    private Date createdTime;    private Date birth;    public Customer() {    }//...}

代码实例如下:

        @Test        public void testNamedQuery(){            Query query = entityManager.createNamedQuery("testNamedQuery").setParameter(1, 3);            Customer customer = (Customer) query.getSingleResult();            System.out.println(customer);        }

控制台输出如下:

这里写图片描述


createNativeQuery 适用于本地 SQL。

即,你可以像MySQL那样写sql语句进行查询。

代码实例如下:

        @Test        public void testNativeQuery(){            String sql = "SELECT age FROM jpa_cutomers WHERE id = ?";            Query query = entityManager.createNativeQuery(sql).setParameter(1, 3);            Object result = query.getSingleResult();            System.out.println(result);        }

控制台输出如下:

这里写图片描述


【3】查询缓存

多次查询同条语句,代码实例如下:

        @Test        public void testQueryCache(){            String jpql = "FROM Customer c WHERE c.age > ?";            Query query = entityManager.createQuery(jpql);            //占位符的索引是从 1 开始            query.setParameter(1, 1);            List<Customer> customers = query.getResultList();            System.out.println(customers.size());            //占位符的索引是从 1 开始            query.setParameter(1, 1);            customers = query.getResultList();            System.out.println(customers.size());        }

控制台输出如下:

这里写图片描述


使用查询缓存。

persistence.xml配置如下:

            <!-- 二级缓存相关 -->            <property name="hibernate.cache.use_second_level_cache" value="true"/>            <property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory"/>            <!--  这里表明使用查询缓存 -->            <property name="hibernate.cache.use_query_cache" value="true"/>

代码实例如下:

        @Test        public void testQueryCache(){            String jpql = "FROM Customer c WHERE c.age > ?";            Query query = entityManager.createQuery(jpql).setHint(QueryHints.HINT_CACHEABLE, true);            //占位符的索引是从 1 开始            query.setParameter(1, 1);            List<Customer> customers = query.getResultList();            System.out.println(customers.size());            query = entityManager.createQuery(jpql).setHint(QueryHints.HINT_CACHEABLE, true);            //占位符的索引是从 1 开始            query.setParameter(1, 1);            customers = query.getResultList();            System.out.println(customers.size());        }

控制台输出入下:

这里写图片描述


【4】更新和删除

JPQL的更新和删除主要 用的是query.executeUpdate()方法;

代码实例如下:

        @Test        public void testExecuteUpdate(){            String jpql = "UPDATE Customer c SET c.lastName = ? WHERE c.id = ?";            Query query = entityManager.createQuery(jpql).setParameter(1, "YYY").setParameter(2, 12);            query.executeUpdate();        }

控制台输出如下:

这里写图片描述

删除同上。


【5】order by,group by 和having子句

JPQL是面向对象的,和hibernate一致。此外,像排序、分组等和普通MySQL并无差异。

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;

group by实例:

        //查询 order 数量大于 2 的那些 Customer        @Test        public void testGroupBy(){            String jpql = "SELECT o.customer FROM Order o "                    + "GROUP BY o.customer "                    + "HAVING count(o.id) >= 2";            List<Customer> customers = entityManager.createQuery(jpql).getResultList();            System.out.println(customers);        }

Having 子句用于对 group by 分组设置约束条件,用法与where 子句基本相同。

不同是 where 子句作用于基表或视图,以便从中选择满足条件的记录;having 子句则作用于分组,用于选择满足条件的组,其条件表达式中通常会使用聚合函数。


order by 实例:

        @Test        public void testOrderBy(){            String jpql = "FROM Customer c WHERE c.age > ? ORDER BY c.age DESC";            Query query = entityManager.createQuery(jpql).setHint(QueryHints.HINT_CACHEABLE, true);            //占位符的索引是从 1 开始            query.setParameter(1, 1);            List<Customer> customers = query.getResultList();            System.out.println(customers.size());        }

order by子句用于对查询结果集进行排序。和SQL的用法类似,可以用 “asc“ 和 “desc“ 指定升降序。

如果不显式注明,默认为升序。


【6】关联查询

在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等义,都是允许符合条件的右边表达式中的实体为空。

左外连接实例如下:

        @Test        public void testLeftOuterJoinFetch(){            String jpql = "FROM Customer c LEFT OUTER JOIN FETCH c.orders WHERE c.id = ?";            Customer customer =                     (Customer) entityManager.createQuery(jpql).setParameter(1, 7).getSingleResult();            System.out.println(customer.getLastName());            System.out.println(customer.getOrders().size());        }

控制台输出如下:

这里写图片描述


需要注意的是,这里jpql用到了FETCH。

如果不加FETCH呢?

代码实例如下:

@Test        public void testLeftOuterJoinFetch(){            String jpql = "FROM Customer c LEFT OUTER JOIN  c.orders WHERE c.id = ?";            List<Object[]> result = entityManager.createQuery(jpql).setParameter(1, 7).getResultList();            System.out.println(result);        }

控制台输出如下:

这里写图片描述

result为数组集合,解析比较麻烦啊!

综上,在使用JPQL语言时 ,需要时刻记得和hibernate一致–面向对象。如果你使用的Query为createNativeQuery,才可以像使用普通MySQL一样进行数据操作。


【7】子查询

JPQL也支持子查询,在 where 或 having 子句中可以包含另一个查询。

当子查询返回多于 1 个结果集时,它常出现在 any、all、exist s表达式中用于集合匹配查询。

它们的用法与SQL语句基本相同。

子查询实例如下:

        @Test        public void testSubQuery(){            //查询所有 Customer 的 lastName 为 YY 的 Order            String jpql = "SELECT o FROM Order o "                    + "WHERE o.customer = (SELECT c FROM Customer c WHERE c.lastName = ?)";            Query query = entityManager.createQuery(jpql).setParameter(1, "YY");            List<Order> orders = query.getResultList();            System.out.println(orders.size());        }

控制台输出如下:

这里写图片描述