JPQL语言,即 Java Persistence Query Language 的简称。JPQL 是一种和 SQL 非常类似的中间性和对象化查询语言,它最终会被编译成针对不同底层数据库的 SQL 查询,从而屏蔽不同数据库的差异。 JPQL语言的语句可以是 select 语句、update 语句或delete语句,它们都通过 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 异常基础语法结构
select_clause form_clause [where_clause] [group by_clause] [having_clause] [order by_clause] 复制代码
如果不希望返回重复实体,可使用关键字 distinct 修饰。
select、from 都是 JPQL 的关键字,通常全大写或全小写,建议不要大小写混用
public class Test01 { private EntityManagerFactory factory ; private EntityManager entityManager ; private EntityTransaction tx; @Before public void init(){ factory = Persistence.createEntityManagerFactory("jpa04"); entityManager = factory.createEntityManager(); tx = entityManager.getTransaction(); tx.begin(); } @After public void close(){ tx.commit(); entityManager.close(); factory.close(); } } 复制代码
查询所有实体的 JPQL 查询字串很简单,例如:select b from Book b
或 select b from Book as b
,关键字 as 可以省去。
标识符变量的命名规范与 Java 标识符相同,且区分大小写。
@Test public void test01(){ String jpql = "FROM Book";//Book为持久化类 Query query = entityManager.createQuery(jpql); List<Book> bookList = query.getResultList(); for (Book book : bookList) { System.out.println(book); } } @Test public void test02(){ String jpql = "SELECT b FROM Book b";//Book为持久化类 Query query = entityManager.createQuery(jpql); List<Book> bookList = query.getResultList(); for (Book book : bookList) { System.out.println(book); } } 复制代码
@Test public void test03(){ String jpql = "SELECT b.bookName FROM Book b";//Book为持久化类 Query query = entityManager.createQuery(jpql); List<String> bookNameList = query.getResultList(); for (String bookName : bookNameList) { System.out.println(bookName); } } 复制代码
a.默认的处理方式:每条记录封装成一个Object数组
@Test public void test04(){ String jpql = "SELECT b.bookName,b.price FROM Book b";//Book为持久化类 Query query = entityManager.createQuery(jpql); //默认的处理方式:每条记录封装成一个Object数组 List<Object[]> bookList = query.getResultList(); for (Object[] array : bookList) { System.out.println(Arrays.toString(array)); } } 复制代码
b.将其处理成Map对象,并且通过别名设置KEY值
@Test public void test05(){ String jpql = "SELECT new Map(b.bookName as book_name,b.price as book_price) FROM Book b";//Book为持久化类 Query query = entityManager.createQuery(jpql); List<Map<String,Object>> bookList = query.getResultList(); for (Map<String,Object> map : bookList) { System.out.println(map); } } 复制代码
关键代码:new Map(b.bookName as book_name,b.price as book_price)
c.通过构造方法将其处理成Book对象
public Book(String bookName, Double price) { this.bookName = bookName; this.price = price; } 复制代码
@Test public void test06(){ String jpql = "SELECT new Book(b.bookName,b.price) FROM Book b";//Book为持久化类 Query query = entityManager.createQuery(jpql); List<Book> bookList = query.getResultList(); for (Book book : bookList) { System.out.println(book); } } 复制代码
关键代码:new Book(b.bookName,b.price)
@Test public void test07(){ String jpql = "SELECT COUNT(*) FROM Book b";//Book为持久化类 Query query = entityManager.createQuery(jpql); long count = (long) query.getSingleResult(); System.out.println("count = " + count); } 复制代码
(1)传递方式绑定方式(不推荐)
private String getJPQL01(String bookName){ String jpql = "FROM Book b WHERE b.bookName like '%"+bookName+"%'"; return jpql; } @Test public void test08(){ String jpql = getJPQL01("记"); Query query = entityManager.createQuery(jpql); List<Book> bookList = query.getResultList(); for (Book book : bookList) { System.out.println(book); } } 复制代码
(2)占位符参数表示法
@Test public void test09(){ String jpql = "FROM Book b WHERE b.bookName like CONCAT('%',?1,'%')"; Query query = entityManager.createQuery(jpql); query.setParameter(1,"记"); List<Book> bookList = query.getResultList(); for (Book book : bookList) { System.out.println(book); } } 复制代码
示例:select o from Order o where o.id = ?1 and o.customer = ?2
:请注意写法
其中?1
代表第一个参数,?2
代表第一个参数
(3)命名参数表示法
@Test public void test10(){ String jpql = "FROM Book b WHERE b.bookName like CONCAT('%',:book_name,'%')"; Query query = entityManager.createQuery(jpql); query.setParameter("book_name","记"); List<Book> bookList = query.getResultList(); for (Book book : bookList) { System.out.println(book); } } 复制代码
命名查询是一个强大的工具。使用@NamedQuery注解定义一个命名查询,可以把它放在任何实体的类定义之上。该注解定义了查询的名称,及其查询的文本。
@Entity @Table(name = "jpa_book") @NamedQuery(name = "load",query = "FROM Book WHERE bookId=?1") public class Book { //省略代码... ... } 复制代码
@Test public void test11(){ Query query = entityManager.createNamedQuery("load"); query.setParameter(1,4); Book book = (Book)query.getSingleResult(); System.out.println("book = " + book); } 复制代码
(1) 查询全部语句返回对象
@Test public void test12(){ String sql = "SELECT * FROM jpa_book WHERE book_id=?";//请注意占位符的写法 Query query = entityManager.createNativeQuery(sql,Book.class); query.setParameter(1,5); Book book = (Book)query.getSingleResult(); System.out.println("book = " + book); } 复制代码
(2)查询部分属性返回Map对象
@Test public void test14(){ String sql = "SELECT book_name,author FROM jpa_book WHERE book_id=?";//请注意占位符的写法 Query query = entityManager.createNativeQuery(sql); //关键代码 query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP); query.setParameter(1,5); Map<String,Object> map = (Map<String,Object> )query.getSingleResult(); System.out.println("map = " + map); } 复制代码