阅读 87

【JPA专题】12.JPQL:基础操作

JPQL的基本操作

JPQL语言,即 Java Persistence Query Language 的简称。JPQL 是一种和 SQL 非常类似的中间性和对象化查询语言,它最终会被编译成针对不同底层数据库的 SQL 查询,从而屏蔽不同数据库的差异。 JPQL语言的语句可以是 select 语句、update 语句或delete语句,它们都通过 Query 接口封装执行。

Query接口封装了执行数据库查询的相关方法。调用 EntityManager 的 createQuerycreate NamedQuerycreateNativeQuery 方法可以获得查询对象,进而可调用 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 异常

Java持久化查询:属性

基础语法结构

select_clause
form_clause
[where_clause]
[group by_clause]
[having_clause]
[order by_clause]
复制代码
  • FROM 子句是查询语句的必选子句
  • SELECT 用来指定查询返回的结果实体或实体的某些属性
  • FROM 子句声明查询源实体类,并指定标识符变量(相当于SQL表的别名)

如果不希望返回重复实体,可使用关键字 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();
    }
}
复制代码

(1)查询所有实体的全部属性操作

查询所有实体的 JPQL 查询字串很简单,例如:select b from Book bselect 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);
    }
}
复制代码

(2)查询所有实体的单个属性操作

@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);
    }
}
复制代码

(3)查询所有实体的多个属性操作

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)

(4)单个值查询[聚合查询]

@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);
}
复制代码

Java持久化操作:查询定义

A.动态查询定义(JPQL)

(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);
    }
}
复制代码

B.命名查询定义(JPQL)

命名查询是一个强大的工具。使用@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);
}
复制代码

C.执行SQL语句

(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);
}
复制代码
关注下面的标签,发现更多相似文章
评论