框架学习之JPA(六)
JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
Sun引入新的JPA ORM规范出于两个原因:其一,简化现有Java EE和Java SE应用开发工作;其二,Sun希望整合ORM技术,实现天下归一。
学习视频:尚硅谷框架jpa学习(有兴趣的同学留言邮箱)
使用软件:eclipse
Java版本:jdk8
本节目录
六、JPA_JPQL
1.HelloWorld
2.使用Hibernate的查询缓存
3.ORDER BY 和GROUP BY
4.关联查询
5.子查询和内建函数
6.UPDATE和DELETE
六、JPA_JPQL
JPQL语言
- JPQL语言,即 Java Persistence Query Language 的简称。JPQL 是一种和 SQL 非常类似的中间性和对象化查询语言,它最终会被编译成针对不同底层数据库的 SQL 查询,从而屏蔽不同数据库的差异。
- JPQL语言的语句可以是 select 语句、update 语句或delete语句,它们都通过 Query 接口封装执行
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 异常。
1.HelloWorld
- 按照条件获取一个List列表,没有SELECT开头,占位符索引从1开始
@Test public void testHelloJPQL(){ 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()); }
- 获取部分属性,需要在对应的model中创建构造函数
//默认情况下, 若只查询部分属性, 则将返回 Object[] 类型的结果. 或者 Object[] 类型的 List. //也可以在实体类中创建对应的构造器, 然后再 JPQL 语句中利用对应的构造器返回实体类的对象. @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); }
- 在Customer类开头加入一个@NameQuery标签,然后进行测试,此时报错不用管
//createNamedQuery 适用于在实体类前使用 @NamedQuery 标记的查询语句 @Test public void testNamedQuery(){ Query query = entityManager.createNamedQuery("testNamedQuery").setParameter(1, 3); Customer customer = (Customer) query.getSingleResult(); System.out.println(customer); }
- 本地SQL语句
//createNativeQuery 适用于本地 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); }
2.使用Hibernate的查询缓存
- 查询相同的语句只需要提交一次SQL语句查询,之前已经配置过一次查询缓存配置文件,此处不用重复配置
//使用 hibernate 的查询缓存. @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()); }
3.ORDER BY 和GROUP BY
- Order by(和SQL一样正常用)
@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()); }
- Grope by(和SQL一样正常用)
//查询 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); }
4.关联查询
注:左外连接语句中的fetch,表示迫切。即迫切左外连接。
什么叫迫切左外连接?
个人理解:
若将(迫切)左外连接左边的对象称为“主对象“,右边的对象称为”附属对象“。
则使用左外连接时,查询出来的对象结构是主对象和附属对象组成的组成的一个对象数组,形如:
Object[主对象,附属对象]。
而使用迫切左外连接时,查询出来的对象结构是一个主对象,而附属对象作为住对象的一个属性值嵌在其中,形如:
主对象
其他属性……
.
.
.
对应属性名:附属对象
.
.
.
其他属性……
- 关联查询,建议加上FETCH
/** * JPQL 的关联查询同 HQL 的关联查询. */ @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, 12).getSingleResult(); System.out.println(customer.getLastName()); System.out.println(customer.getOrders().size()); // List<Object[]> result = entityManager.createQuery(jpql).setParameter(1, 12).getResultList(); // System.out.println(result); }
5.子查询和内建函数
- 子查询
@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()); }
- 内建函数
-
- 字符串处理函数主要有:
- 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。
- 字符串处理函数主要有:
- n 算术函数主要有 abs、mod、sqrt、size 等。Size 用于求集合的元素个数。
- n 日期函数主要为三个,即 current_date、current_time、current_timestamp,它们不需要参数,返回服务器上的当前日期、时间和时戳。
测试:
//使用 jpql 内建的函数 @Test public void testJpqlFunction(){ String jpql = "SELECT lower(c.email) FROM Customer c"; List<String> emails = entityManager.createQuery(jpql).getResultList(); System.out.println(emails); }
6.UPDATE和DELETE
//可以使用 JPQL 完成 UPDATE 和 DELETE 操作. @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(); }