通常情况下,我们都是直接将 JPQL 查询语句写到 createNamedQuery("JPQL 语句") 方法中,例如:
EntityManager em = factory.createEntityManager(); Query query = em.createQuery("select t from User t where t.id=?1"); query.setParameter(1, 1);
JPQL 命名查询指将上面示例中的 JPQL 通过 @NamedQuery 注解配置在实体类或映射的超类上。给该 JPQL 指定一个唯一名称,然后通过 createNamedQuery("JPQL 命名名称") 方法进行调用。
以下是 JPQL 中命名查询的定义示例:
@NamedQuery( name="findAllCustomersWithName", query="SELECT c FROM Customer c WHERE c.name LIKE :custName" )
上面定义了一个名为 findAllCustomersWithName 的 JPQL 查询语句。以下是使用命名查询的示例:
@PersistenceContext public EntityManager em; ... customers = em.createNamedQuery("findAllCustomersWithName") .setParameter("custName", "Smith") .getResultList();
本示例还是以用户和用户的图书为例,演示 JPQL 命名查询的用法。详细步骤如下:
(1)配置 persistence.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0"> <persistence-unit name="openJPA" transaction-type="RESOURCE_LOCAL"> <!-- JPA提供者 --> <provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider> <!-- 声明实体类 --> <class>com.hxstrive.openjpa.entity.User</class> <class>com.hxstrive.openjpa.entity.Book</class> <!-- 配置JPA数据库属性 --> <properties> <property name="openjpa.ConnectionURL" value="jdbc:mysql://localhost:3306/openjpa_learn?useSSL=false& serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8"/> <property name="openjpa.ConnectionDriverName" value="com.mysql.jdbc.Driver"/> <property name="openjpa.ConnectionUserName" value="root"/> <property name="openjpa.ConnectionPassword" value="aaaaaa"/> <property name="openjpa.Log" value="SQL=TRACE"/> <!-- 自动生成表 --> <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/> <!-- 不使用加载时强化和编译时强化,使用运行时Unenhanced(不能发挥OpenJPA的最大效能,所以也不推荐) --> <property name="openjpa.ClassLoadEnhancement" value="false"/> <property name="openjpa.DynamicEnhancementAgent" value="false"/> <property name="openjpa.RuntimeUnenhancedClasses" value="supported"/> </properties> </persistence-unit> </persistence>
(2)用户表实体映射,其中使用 @OneToMany 指定一对多映射,一个用户拥有多本图书。代码如下:
@Data @Entity @Table @NamedQueries({ @NamedQuery(name = "find_users", query = "Select u from User u"), @NamedQuery(name = "find_byId", query = "Select u from User u where u.id=:id") }) public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @Column private String name; @Column private Integer age; @Column private Float salary; @OneToMany(cascade = CascadeType.ALL) private List<Book> bookList; }
上面代码中,通过 @NamedQueries 或者 @NamedQuery 注解定义了两个命名 JPQL 查询。
(3)图书表实体映射,代码如下:
@Data @Entity @Table public class Book { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @Column private String name; @Column private float price; }
(4)客户端代码
import com.hxstrive.openjpa.entity.User; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import javax.persistence.Query; import java.util.List; public class JPQLDemo2 { /** 持久化单元名称 */ private static final String PERSISTENCE_NAME = "openJPA"; public static void main(String[] args) { EntityManagerFactory factory = Persistence.createEntityManagerFactory( PERSISTENCE_NAME, System.getProperties()); EntityManager em = factory.createEntityManager(); Query query = em.createNamedQuery("find_byId"); query.setParameter("id", 1); List<User> userList = query.getResultList(); for (User user : userList) { System.out.println(user); } em.close(); factory.close(); System.out.println("finished."); } }
运行客户端输出的 SQL 日志如下:
SELECT t0.id, t0.age, t0.name, t0.salary FROM User t0 WHERE (t0.id = ?) [params=?] SELECT t1.id, t1.name, t1.price FROM User_Book t0 INNER JOIN Book t1 ON t0.BOOKLIST_ID = t1.id WHERE t0.USER_ID = ? [params=?] User{id=1, name='用户-0', age=56, salary=7251.132, bookList=[{"id":1,"name":"图书-用户-0-0","price":40.912487},{"id":2,"name":"图书-用户-0-1","price":25.45687},{"id":3,"name":"图书-用户-0-2","price":87.681984},{"id":4,"name":"图书-用户-0-3","price":94.50937}]} finished.