使用 JPQL 和原生 SQL 查询 JPA 实体

JPQL 和 SQL 的主要区别在于,前者处理 JPA 实体,后者直接处理关系数据。作为 Java 开发人员,您可能还有兴趣了解使用 JPQL 与 SQL/JDBC 的不同,无需在 Java 代码中使用 JDBC API — 容器在幕后为您完成了所有这些工作。

通过 JPQL,您可以使用 SELECT、UPDATE 或 DELETE 这三条语句之一来定义查询。值得注意的是,EntityManager API 接口提供的方法也可用于对实体执行检索、更新和删除操作。具体来说,是 find、merge 和 remove 方法。然而,这些方法的使用通常限于单个实体实例,当然,级联生效时除外。而 JPQL 语句则没有这样的限制 — 您可以定义对若干组实体进行批量更新和删除操作,并定义查询返回若干组实体实例。

要从 Java 代码内发出 JPQL 查询,您需要利用 EntityManager API 和 Query API 的相应方法,执行以下一般步骤:

  1. 使用注入或通过 EntityManagerFactory 实例显式获取一个 EntityManager 实例。
  2. 通过调用相应 EntityManager 的方法(如 createQuery),创建一个 Query 实例。
  3. 如果有查询参数,使用相应 Query 的 setParameter 方法进行设置。
  4. 如果需要,使用 setMaxResults 和/或 setFirstResult Query 的方法设置要检索的实例的最大数量和/或指定检索的起始实例位置。
  5. 如果需要,使用 setHint Query 的方法设置供应商特定的提示。
  6. 如果需要,使用 setFlushMode Query 的方法设置查询执行的刷新模式,覆盖实体管理器的刷新模式。
  7. 使用相应 Query 的方法 getSingleResult 或 getResultList 执行查询。可是,如果进行更新或删除操作,您必须使用 executeUpdate 方法,它返回已更新或删除的实体实例的数量。
EntityManager 接口方法以及 Query API 接口方法的完整列表可以在以下 Enterprise JavaBeans 3.0 规范中找到:Java 持久性 API 文档( JSR-220  的一部分)。

既然您已经对如何创建以及发出 JPQL 查询有了大致了解,您可能希望看一些实际的示例。以下代码片段摘自一个 servlet 的 doGet 方法,该方法使用 JPQL 查询获取有关与查询中指定的 Customer 实体相关的底层关系表中存储的所有客户的信息。

...
    @PersistenceUnit
    private EntityManagerFactory emf;
    public void doGet(
...
        EntityManager em = emf.createEntityManager();
        PrintWriter out = response.getWriter();
        List<Customer> arr_cust = (List<Customer>)em.createQuery("SELECT c FROM Customer c")
                              .getResultList(); 
        out.println("List of all customers: "+"<br/>");
Iterator i = arr_cust.iterator();
Customer cust;
while (i.hasNext()) {
cust = (Customer) i.next();
out.println(cust.getCust_id()+"<br/>");
out.println(cust.getCust_name()+"<br/>");
out.println(cust.getEmail()+"<br/>");
out.println(cust.getPhone()+"<br/>");
out.println("----------------" + "<br/>");
        }
...
当然,这里让人关注的是 EntityManager 实例的 createQuery 方法和 Query 实例的 getResultList 方法。EntityManager 的 createQuery 用于创建 Query 实例,然后该实例的 getResultList 方法用于执行作为参数传递给 createQuery 的 JPQL 查询。正如您可能已经猜到的那样,Query 的 getResultList 方法以 List 形式返回查询的结果,在这个特定示例中,将 List 的元素转换为 Customer 类型。

如果您需要检索单个结果,Query API 接口提供了 getSingleResult 方法,如以下示例所示。然而,请注意,如果您返回多个结果,使用 getSingleResult 将引发异常。

该示例还说明了如何使用 Query 的 setParameter 方法,通过该方法,您可以将参数值绑定到某个查询参数。使用 setParameter,您既可以绑定命名参数也可以绑定位置参数。但是,您在此处绑定的是一个命名参数。

...
        Integer cust_id =2;
        Customer cust = (Customer)em.createQuery("SELECT c FROM Customer c WHERE c.cust_id=:cust_id")
                              .setParameter("cust_id", cust_id)
                              .getSingleResult(); 
        out.println("Customer with id "+cust.getCust_id()+" is: "+ cust.getCust_name()+"<br/>");
...
值得注意的是,如果检索单个实体实例,SELECT JPQL 语句并不是唯一的选择。您还可以使用 EntityManager 的 find 方法,通过该方法,您可以根据实体的 ID(作为参数传入)检索单个实体实例。

在某些情况下,您可能只需检索目标实体实例中的某些信息,针对特定的实体字段定义 JPQL 查询。如果您只需检索此处查询的 Customer 实体实例的 cust_name 字段的值,上面的代码片段应改为:

...
        Integer cust_id =2;
        String cust_name = (String)em.createQuery("SELECT c.cust_name FROM Customer c WHERE c.cust_id=:cust_id")
                              .setParameter("cust_id", cust_id)
                              .getSingleResult(); 
        out.println("Customer with id "+cust_id+" is: "+cust_name+"<br/>");
...
同样,要获取客户名称的完整列表,可以使用以下代码:
...
        List<String> arr_cust_name = (List<String>)em.createQuery("SELECT c.cust_name FROM Customer c")
                              .getResultList(); 
        out.println("List of all customers: "+"<br/>");
Iterator i = arr_cust_name.iterator();
String cust_name;
while (i.hasNext()) {
cust_name = (String) i.next();
out.println(cust_name+"<br/>");
        }
...
重新再看 SQL,您可能想起 SQL 查询的选择列表可以由 FROM 子句中指定的表中的若干个字段组成。在 JPQL 中,您还可以使用组成的选择列表,仅从感兴趣的实体字段中选择数据。但是,在这种情况下,您需要创建一个类,将查询结果赋予该类。在下一小节中,您将看到一个 JPQL 联接查询的示例,该查询的选择列表由源自多个实体的字段组成。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值