当前位置:文档之家› JPA 2.0动态查询Criteria

JPA 2.0动态查询Criteria

JPA 2.0动态查询Criteria
JPA 2.0动态查询Criteria

详解JPA 2.0动态查询机制:Criteria API

自从JPA 于2006 年首次被引入之后,它就得到了Java开发社区的广泛支持。该规范的下一个主要更新—— 2.0 版本(JSR 317) ——将在2009 年年底完成。JPA 2.0 引入的关键特性之一就是Criteria API,它为Java 语言带来了一种独特的能力:开发一种Java 编译器可以在运行时验证其正确性的查询。Criteria API 还提供一个能够在运行时动态地构建查询的机制。

本文将介绍Criteria API 和与之密切相关的元模型(metamodel)概念。您将学习如何使用Criteria API 开发Java 编译器能够检查其正确性的查询,从而减少运行时错误,这种查询优于传统的基于字符串的Java Persistence Query Language (JPQL) 查询。借助使用数据库函数或匹配模板实例的样例查询,我将演示编程式查询构造机制的强大威力,并将其与使用预定义语法的JPQL 查询进行对比。本文假设您具备基础的Java 语言编程知识,并了解常见的JPA 使用,比如EntityManagerFactory 或EntityManager。

JPQL 查询有什么缺陷?

JPA 1.0 引进了JPQL,这是一种强大的查询语言,它在很大程度上导致了JPA 的流行。不过,基于字符串并使用有限语法的JPQL 存在一些限制。要理解JPQL 的主要限制之一,请查看清单1 中的简单代码片段,它通过执行JPQL 查询选择年龄大于20 岁的Person 列表:

清单 1. 一个简单(并且错误)的JPQL 查询

EntityManager em = ...;

String jpql = "select p from Person where p.age > 20";

Query query = em.createQuery(jpql);

List result = query.getResultList();

这个基础的例子显示了JPA 1.0 中的查询执行模型的以下关键方面:?JPQL 查询被指定为一个String(第2 行)。

?EntityManager 是构造一个包含给定JPQL 字符串的可执行查询实例的工厂(第 3 行)。

?查询执行的结果包含无类型的java.util.List 的元素。

但是这个简单的例子有一个验证的错误。该代码能够顺利通过编译,但将在运行时失败,因为该JPQL 查询字符串的语法有误。清单1的第2 行的正确语法为:

String jpql = "select p from Person p where p.age > 20";

不幸的是,Java 编译器不能发现此类错误。在运行时,该错误将出现在第3 或第4 行(具体行数取决于JPA 提供者是否在查询构造或执行期间根据JPQL 语法解析JPQL 字符串)。

类型安全查询如何提供帮助?

Criteria API 的最大优势之一就是禁止构造语法错误的查询。清单2 使用CriteriaQuery 接口重新编写了清单1中的JPQL 查询:

清单 2. 编写CriteriaQuery 的基本步骤

EntityManager em = ...

QueryBuilder qb = em.getQueryBuilder();

CriteriaQuery< Person> c = qb.createQuery(Person.class);

Root< Person> p = c.from(Person.class);

Predicate condition = qb.gt(p.get(Person_.age), 20);

c.where(condition);

TypedQuery< Person> q = em.createQuery(c);

List< Person> result = q.getResultList();

清单2展示了Criteria API 的核心构造及其基本使用:

?第1 行通过几种可用方法之一获取一个EntityManager 实例。

?在第2 行,EntityManager 创建QueryBuilder 的一个实例。QueryBuilder 是CriteriaQuery 的工厂。

?在第3 行,QueryBuilder 工厂构造一个CriteriaQuery 实例。CriteriaQuery 被赋予泛型类型。泛型参数声明CriteriaQuery 在执行时返回的结果的类型。在构造CriteriaQuery 时,您可以提供各种结果类型参数——从持

久化实体(比如Person.class)到形式更加灵活的Object[]。

?第4 行在CriteriaQuery 实例上设置了查询表达式。查询表达式是在一个树中组装的核心单元或节点,用于指定CriteriaQuery。图 1 显示了在

Criteria API 中定义的查询表达式的层次结构:

图 1. 查询表达式中的接口层次结构

点击查看大图

首先,将CriteriaQuery 设置为从Person.class 查询。结果返回Root< Person> 实例p。Root 是一个查询表达式,它表示持久化实体的范围。

Root< T> 实际上表示:“对所有类型为T 的实例计算这个查询。” 这类似于JPQL 或SQL 查询的FROM 子句。另外还需要注意,Root< Person> 是泛型的(实际上每个表达式都是泛型的)。类型参数就是表达式要计算的值的类型。因此Root< Person> 表示一个对Person.class 进行计算的表达式。第 5 行构造一个Predicate。Predicate 是计算结果为true 或false 的常见查询表达式形式。谓词由QueryBuilder 构造,QueryBuilder 不仅是CriteriaQuery 的工厂,同时也是查询表达式的工厂。QueryBuilder 包含构造传统JPQL 语法支持的所有查询表达式的API 方法,并且还包含额外的方法。在清单2中,QueryBuilder 用于构造一个表达式,它将计算第一个表达式参数的值是否大于第二个参数的值。方法签名为:

Predicate gt(Expression< ? extends Number> x, Number y);

这个方法签名是展示使用强类型语言(比如Java)定义能够检查正确性并阻止错误的API 的好例子。该方法签名指定,仅能将值为Number 的表达式与另一个值也为Number 的表达式进行比较(例如,不能与值为String 的表达式进行比较):

Predicate condition = qb.gt(p.get(Person_.age), 20);

第 5 行有更多学问。注意qb.gt() 方法的第一个输入参数:

p.get(Person_.age),其中p 是先前获得的Root< Person> 表达式。

p.get(Person_.age) 是一个路径表达式。路径表达式是通过一个或多个持久化属性从根表达式进行导航得到的结果。因此,表达式

p.get(Person_.age) 表示使用Person 的age 属性从根表达式p 导航。您可能不明白Person_.age 是什么。您可以将其暂时看作一种表示Person 的age 属性的方法。我将在谈论JPA 2.0 引入的新Metamodel API 时详细解释Person_.age。

如前所述,每个查询表达式都是泛型的,以表示表达式计算的值的类型。

如果Person.class 中的age 属性被声明为类型Integer (或int),则表达式p.get(Person_.age) 的计算结果的类型为Integer。由于API 中的类型安全继承,编辑器本身将对无意义的比较抛出错误,比如:

Predicate condition = qb.gt(p.get(Person_.age, "xyz"));

?第6 行在CriteriaQuery 上将谓词设置为其WHERE 子句。

?在第7 行中,EntityManager 创建一个可执行查询,其输入为CriteriaQuery。这类似于构造一个输入为JPQL 字符串的可执行查询。但是由于输入CriteriaQuery 包含更多的类型信息,所以得到的结果是

TypedQuery,它是熟悉的javax.persistence.Query 的一个扩展。如其名所示,TypedQuery 知道执行它返回的结果的类型。它是这样定义的:

public interface TypedQuery< T> extends Query {

List< T> getResultList();

}

与对应的无类型超接口相反:

public interface Query {

List getResultList();

}

很明显,TypedQuery 结果具有相同的Person.class 类型,该类型在构造输入CriteriaQuery 时由QueryBuilder 指定(第 3 行)。

?在第8 行中,当最终执行查询以获得结果列表时,携带的类型信息展示了其优势。得到的结果是带有类型的Person 列表,从而使开发人员在遍历生成的元素时省去麻烦的强制类型转换(同时减少了

ClassCastException 运行时错误)。

现在归纳清单2中的简单例子的基本方面:

?CriteriaQuery 是一个查询表达式节点树。在传统的基于字符串的查询语言中,这些表达式节点用于指定查询子句,比如FROM、WHERE 和ORDER BY。图2 显示了与查询相关的子句:

图 2. CriteriaQuery 封装了传统查询的子句

?查询表达式被赋予泛型。一些典型的表达式是:

o Root< T>,相当于一个FROM 子句。

o Predicate,其计算为布尔值true 或false(事实上,它被声明为interface Predicate extends Expression< Boolean>)。

o Path< T>,表示从Root< ?> 表达式导航到的持久化属性。Root< T> 是一个没有父类的特殊Path< T>。

?QueryBuilder 是CriteriaQuery 和各种查询表达式的工厂。

?CriteriaQuery 被传递给一个可执行查询并保留类型信息,这样可以直接访问选择列表的元素,而不需要任何运行时强制类型转换。

持久化域的元模型

讨论清单2时指出了一个不常见的构造:Person_.age,它表示Person 的持久化属性age。清单2使用Person_.age 形成一个路径表达式,它通过

p.get(Person_.age) 从Root< Person> 表达式p 导航而来。Person_.age 是Person_ 类中的公共静态字段,Person_ 是静态、已实例化的规范元模型类,对应于原来的Person 实体类。

元模型类描述持久化类的元数据。如果一个类安装JPA 2.0 规范精确地描述持久化实体的元数据,那么该元模型类就是规范的。规范的元模型类是静态的,因此它的所有成员变量都被声明为静态的(也是public 的)。Person_.age 是静态成员变量之一。您可以在开发时在源代码中生成一个具体的Person_.java 来实例化一个规范类。实例化之后,它就可以在编译期间以强类型的方式引用Person 的持久化属性。

这个Person_metamodel 类是引用Person 的元信息的一种代替方法。这种方法类似于经常使用(有人可能认为是滥用)的Java Reflection API,但概念上有很大的不同。您可以使用反射获得关于https://www.doczj.com/doc/a96048903.html,ng.Class 的实例的元信息,但是不能以编译器能够检查的方式引用关于Person.class 的元信息。例如,使用反射时,您将这样引用Person.class 中的age 字段:

Field field = Person.class.getField("age");

不过,这种方法也存在很大的限制,类似于清单1中基于字符串的JPQL 查询存在的限制。编译器能够顺利编译该代码,但不能确定它是否可以正常工作。如果该代码包含任何错误输入,它在运行时肯定会失败。反射不能实现JPA 2.0 的类型安全查询API 要实现的功能。

类型安全查询API 必须让您的代码能够引用Person 类中的持久化属性age,同时让编译器能够在编译期间检查错误。JPA 2.0 提供的解决办法通过静态地公开相同的持久化属性实例化名为Person_ 的元模型类(对应于Person)。

关于元信息的讨论通常都是令人昏昏欲睡的。所以我将为熟悉的Plain Old Java Object (POJO) 实体类展示一个具体的元模型类例子(domain.Person),如清单3 所示:

清单 3. 一个简单的持久化实体

package domain;

@Entity

public class Person {

@Id

private long ssn;

private string name;

private int age;

// public gettter/setter methods

public String getName() {...}

}

这是POJO 的典型定义,并且包含注释(比如@Entity 或@Id ),从而让JPA 提供者能够将这个类的实例作为持久化实体管理。

清单 4 显示了domain.Person 的对应静态规范元模型类:

清单 4. 一个简单实体的规范元模型

package domain;

import javax.persistence.metamodel.SingularAttribute;

@javax.persistence.metamodel.StaticMetamodel(domain.Person.class)

public class Person_ {

public static volatile SingularAttribute< Person,Long> ssn;

public static volatile SingularAttribute< Person,String> name;

public static volatile SingularAttribute< Person,Integer> age;

}

元模型类将原来的domain.Person 实体的每个持久化属性声明为类型为SingularAttribute< Person,?> 的静态公共字段。通过利用这个Person_ 元模型类,可以在编译期间引用domain.Person 的持久化属性age —不是通过Reflection API,而是直接引用静态的Person_.age 字段。然后,编译器可以根据age 属性声明的类型实施类型检查。我已经列举了一个关于此类限制的例子:QueryBuilder.gt(p.get(Person_.age), "xyz") 将导致编译器错误,因为编译器通过QueryBuilder.gt(..) 的签名和Person_.age 的类型可以确定Person 的age 属性是一个数字字段,不能与String 进行比较。

其他一些需要注意的要点包括:

元模型Person_.age 字段被声明为类型

javax.persistence.metamodel.SingularAttribute。SingularAttribute 是JPA

Metamodel API 中定义的接口之一,我将在下一小节描述它。

SingularAttribute< Person, Integer> 的泛型参数表示该类声明原来的持久

化属性和持久化属性本身的类型。

元模型类被注释为@StaticMetamodel(domain.Person.class) 以将其标记为一个与原来的持久化domain.Person 实体对应的元模型类。Metamodel API

我将一个元模型类定义为一个持久化实体类的描述。就像Reflection API 需要其他接口(比如https://www.doczj.com/doc/a96048903.html,ng.reflect.Field 或https://www.doczj.com/doc/a96048903.html,ng.reflect.Method )来描述https://www.doczj.com/doc/a96048903.html,ng.Class 的组成一样,JPA Metamodel API 也需要其他接口(比如SingularAttribute 和PluralAttribute)来描述元模型类的类型及其属性。

图3 显示了在Metamodel API 中定义用于描述类型的接口:

图 3. Metamodel API 中的持久化类型的接口的层次结构

图4 显示了在Metamodel API 中定义用于描述属性的接口:

图 4. Metamodel API 中的持久化属性的接口的层次结构

JPA 的Metamodel API 接口比Java Reflection API 更加专业化。需要更细微的差别来表达关于持久化的丰富元信息。例如,Java Reflection API 将所有Java 类型表示为https://www.doczj.com/doc/a96048903.html,ng.Class。即没有通过独立的定义对概念进行区分,比如类、抽象类和接口。当然,您可以询问Class 它是一个接口还是一个抽象类,但这与通过两个独立的定义表示接口和抽象类的差别不同。

Java Reflection API 在Java 语言诞生时就被引入(对于一种常见的多用途编程语言而言,这曾经是一个非常前沿的概念),但是经过多年的发展才认识到强类型系统的用途和强大之处。JPA Metamodel API 将强类型引入到持久化实体中。例如,持久化实体在语义上区分为MappedSuperClass、Entity 和Embeddable。在JPA 2.0 之前,这种语义区分是通过持久化类定义中的对应类级别注释来表示的。JPA Metamodel 在javax.persistence.metamodel 包中描述了3 个独立的接口(MappedSuperclassType、EntityType 和EmbeddableType ),以更加鲜明的对比它们的语义特征。类似地,可以通过接口(比如SingularAttribute、CollectionAttribute 和MapAttribute)在类型定义级别上区分持久化属性。

除了方便描述之外,这些专门化的元模型接口还有实用优势,能够帮助构建类型安全的查询从而减少运行时错误。您在前面的例子中看到了一部分优势,随着我通过CriteriaQuery 描述关于连接的例子,您将看到更多优势。

运行时作用域

一般而言,可以将Java Reflection API 的传统接口与专门用于描述持久化元数据的javax.persistence.metamodel 的接口进行比较。要进一步进行类比,则需要对元模型接口使用等效的运行时作用域概念。https://www.doczj.com/doc/a96048903.html,ng.Class 实例的作用域由https://www.doczj.com/doc/a96048903.html,ng.ClassLoader 在运行时划分。一组相互引用的Java 类实例必须在ClassLoader 作用域下定义。作用域的边界是严格或封闭的,如果在ClassLoader L 作用域下定义的类A 试图引用不在ClassLoader L 作用域之内的类B,结果将收到可怕的ClassNotFoundException 或NoClassDef FoundError(对于处理包含多个ClassLoader 的环境的开发人员或部署人员而言,问题就复杂了)。

现在将一组严格的可相互引用的类称为运行时作用域,而在JPA 1.0 中称为持久化单元。持久化单元作用域的持久化实体在META-INF/persistence.xml 文件的< class> 子句中枚举。在JPA 2.0 中,通过javax.persistence.metamodel.Metamodel 接口让开发人员可以在运行时使用作用域。Metamodel 接口是特定持久化单元知道的所有持久化实体的容器,如图5 所示:

图 5. 元模型接口是持久化单元中的类型的容器

这个接口允许通过元模型元素的对应持久化实体类访问元模型元素。例如,要获得对Person 持久化实体的持久化元数据的引用,可以编写:

EntityManagerFactory emf = ...;

Metamodel metamodel = emf.getMetamodel();

EntityType< Person> pClass = metamodel.entity(Person.class);

这是一个用类的名称通过ClassLoader 获得Class 的类比:

ClassLoader classloader = Thread.currentThread().getContextClassLoader();

Class< ?> clazz = classloader.loadClass("domain.Person");

可以在运行时浏览EntityType< Person> 获得在Person 实体中声明的持久化属性。如果应用程序在pClass(比如pClass.getSingularAttribute("age", Integer.class))

上调用一个方法,它将返回一个SingularAttribute< Person, Integer> 实例,该实例与实例化规范元模型类的静态Person_.age 成员相同。最重要的是,对于应用程序可以通过Metamodel API 在运行时引用的属性,是通过实例化静态规范元模型Person_ 类向Java 编译器提供的。

除了将持久化实体分解为对应的元模型元素之外,Metamodel API 还允许访问所有已知的元模型类(Metamodel.getManagedTypes()),或者通过类的持久化信息访问元模型类,例如embeddable(Address.class),它将返回一个EmbeddableType< Address> 实例(ManagedType< > 的子接口)。

在JPA 中,关于POJO 的元信息使用带有源代码注释(或XML 描述符)的持久化元信息进一步进行区分——比如类是否是嵌入的,或者哪个字段用作主键。持久化元信息分为两大类:持久化(比如@Entity)和映射(比如@Table)。在JPA 2.0 中,元模型仅为持久化注释(不是映射注释)捕捉元数据。因此,使用当前版本的Metamodel API 可以知道哪些字段是持久化的,但不能找到它们映射到的数据库列。

规范和非规范

尽管JPA 2.0 规范规定了规范的静态元模型类的精确样式(包括元模型类的完整限定名及其静态字段的名称),应用程序也能够编写这些元模型类。如果应用程序开发人员编写元模型类,这些类就称为非规范元模型。现在,关于非规范元模型的规范还不是很详细,因此对非规范元模型的支持不能在JPA 提供者之间移植。您可能已经注意到,公共静态字段仅在规范元模型中声明,而没有初始化。声明之后就可以在开发CriteriaQuery 时引用这些字段。但是,必须在运行时给它们赋值才有意义。尽管为规范元模型的字段赋值是JPA 提供者的责任,但非规范元模型则不存在这一要求。使用非规范元模型的应用程序必须依赖于特定供应商机制,或开发自己的机制来在运行时初始化元模型属性的字段值。

注释处理和元模型生成

如果您有许多持久化实体,您将倾向于不亲自编写元模型类,这是很自然的事情。持久化提供者应该为您生成这些元模型类。在规范中没有强制规定这种工具或生成机制,但是JPA 之间已经私下达成共识,他们将使用在Java 6 编译器中集成的Annotation Processor 工具生成规范元模型。Apache OpenJPA 提供一个工具来生成这些元模型类,其生成方式有两种,一是在您为持久化实体编译源代码时隐式地生成,二是通过显式地调用脚本生成。在Java 6 以前,有一个被广泛使用的称为apt 的Annotation Processor 工具,但在Java 6 中,编译器和Annotation Processor 的合并被定义为标准的一部分。

要像持久化提供者一样在OpenJPA 中生成这些元模型类,仅需在编译器的类路径中使用OpenJPA 类库编译POJO 实体:

$ javac domain/Person.java

将生成规范元模型Person_ 类,它将位于Person.java 所在的目录,并且作为该编译的一部分。

编写类型安全的查询

到目前为止,我已经构建了CriteriaQuery 的组件和相关的元模型类。现在,我将展示如何使用Criteria API 开发一些查询。

函数表达式

函数表达式将一个函数应用到一个或多个输入参数以创建新的表达式。函数表达式的类型取决于函数的性质及其参数的类型。输入参数本身可以是表达式或文本值。编译器的类型检查规则与API 签名结合确定什么是合法输入。

考虑一个对输入表达式应用平均值的单参数表达式。CriteriaQuery 选择所有Account 的平均余额,如清单 5 所示:

清单 5. CriteriaQuery 中的函数表达式

CriteriaQuery< Double> c = cb.createQuery(Double.class);

Root< Account> a = c.from(Account.class);

c.select(cb.avg(a.get(Account_.balance)));

等效的JPQL 查询为:

String jpql = "select avg(a.balance) from Account a";

在清单5中,QueryBuilder 工厂(由变量cb 表示)创建一个avg() 表达式,并将其用于查询的select() 子句。

该查询表达式是一个构建块,可以通过组装它为查询定义最后的选择谓词。清单6中的例子显示了通过导航到Account 的余额创建的Path 表达式,然后Path 表达式被用作两个二进制函数表达式(greaterThan() 和lessThan())的输入表达式,这两个表达式的结果都是一个布尔表达式或一个谓词。然后,通过and() 操作合并谓词以形成最终的选择谓词,查询的where() 子句将计算该谓词:

清单 6. CriteriaQuery 中的where() 谓词

CriteriaQuery< Account> c = cb.createQuery(Account.class);

Root< Account> account = c.from(Account.class);

Path< Integer> balance = account.get(Account_.balance);

c.where(cb.and

(cb.greaterThan(balance, 100),

cb.lessThan(balance), 200)));

等效的JPQL 查询为:

"select a from Account a where a.balance>100 and a.balance< 200";

符合谓词

某些表达式(比如in())可以应用到多个表达式。清单7 给出了一个例子:

清单7. CriteriaQuery 中的多值表达式

CriteriaQuery< Account> c = cb.createQuery(Account.class);

Root< Account> account = c.from(Account.class);

Path< Person> owner = account.get(Account_.owner);

Path< String> name = owner.get(Person_.name);

c.where(cb.in(name).value("X").value("Y").value("Z"));

这个例子通过两个步骤从Account 进行导航,创建一个表示帐户所有者的名称的路径。然后,它创建一个使用路径表达式作为输入的in() 表达式。in() 表达式计算它的输入表达式是否等于它的参数之一。这些参数通过value() 方法在In< T> 表达式上指定,In< T> 的签名如下所示:

In< T> value(T value);

注意如何使用Java 泛型指定仅对值的类型为T 的成员计算In< T> 表达式。因为表示Account 所有者的名称的路径表达式的类型为String,所以与值为String 类型的参数进行比较才有效,String 值参数可以是字面量或计算结果为String 的另一个表达式。

将清单7中的查询与等效(正确)的JPQL 进行比较:

"select a from Account a where https://www.doczj.com/doc/a96048903.html, in ('X','Y','Z')";

在JPQL 中的轻微疏忽不仅不会被编辑器检查到,它还可能导致意外结果。例如:

"select a from Account a where https://www.doczj.com/doc/a96048903.html, in (X, Y, Z)";

连接关系

尽管清单6和清单7中的例子将表达式用作构建块,查询都是基于一个实体及其属性之上的。但是查询通常涉及到多个实体,这就要求您将多个实体连接起来。CriteriaQuery 通过类型连接表达式连接两个实体。类型连接表达式有两个类型参数:连接源的类型和连接目标属性的可绑定类型。例如,如果您想查询有一个或多个PurchaseOrder 没有发出的Customer,则需要通过一个表达式将Customer 连接到PurchaseOrder,其中Customer 有一个名为orders 类型为java.util.Set< PurchaseOrder> 的持久化属性,如清单8 所示:

清单8. 连接多值属性

CriteriaQuery< Customer> q = cb.createQuery(Customer.class);

Root< Customer> c = q.from(Customer.class);

SetJoin< Customer, PurchaseOrder> o = c.join(Customer_.orders);

连接表达式从根表达式c 创建,持久化属性Customer.orders 由连接源(Customer)和Customer.orders 属性的可绑定类型进行参数化,可绑定类型是PurchaseOrder 而不是已声明的类型java.util.Set< PurchaseOrder>。此外还要注意,因为初始属性的类型为java.util.Set,所以生成的连接表达式为SetJoin,它是专门针对类型被声明为java.util.Set 的属性的Join。类似地,对于其他受支持的多值持久化属性类型,该API 定义CollectionJoin、ListJoin 和MapJoin。(图1显示了各种连接表达式)。在清单8的第3 行不需要进行显式的转换,因为CriteriaQuery 和Metamodel API 通过覆盖join() 的方法能够识别和区分声

明为java.util.Collection 或List 或者Set 或Map 的属性类型。

在查询中使用连接在连接实体上形成一个谓词。因此,如果您想要选择有一个或多个未发送PurchaseOrder 的Customer,可以通过状态属性从连接表达式o 进行导航,然后将其与DELIVERED 状态比较,并否定谓词:

Predicate p = cb.equal(o.get(PurchaseOrder_.status), Status.DELIVERED)

.negate();

创建连接表达式需要注意的一个地方是,每次连接一个表达式时,都会返回一个新的表达式,如清单9 所示:

清单9. 每次连接创建一个唯一的实例

SetJoin< Customer, PurchaseOrder> o1 = c.join(Customer_.orders);

SetJoin< Customer, PurchaseOrder> o2 = c.join(Customer_.orders);

assert o1 == o2;

清单9中对两个来自相同表达式c 的连接表达式的等同性断言将失败。因此,如果查询的谓词涉及到未发送并且值大于$200 的PurchaseOrder,那么正确的构造是将PurchaseOrder 与根Customer 表达式连接起来(仅一次),把生成的连接表达式分配给本地变量(等效于JPQL 中的范围变量),并在构成谓词时使用本地变量。

使用参数

回顾一下本文初始的JPQL 查询(正确那个):

String jpql = "select p from Person p where p.age > 20";

尽管编写查询时通常包含常量文本值,但这不是一个良好实践。良好实践是参数化查询,从而仅解析或准备查询一次,然后再缓存并重用它。因此,编写查询的最好方法是使用命名参数:

String jpql = "select p from Person p where p.age > :age";

参数化查询在查询执行之前绑定参数的值:

Query query = em.createQuery(jpql).setParameter("age", 20);

List result = query.getResultList();

在JPQL 查询中,查询字符串中的参数以命名方式(前面带有冒号,例如:age)或位置方式(前面带有问号,例如?3)编码。在CriteriaQuery 中,参数本身就是查询表达式。与其他表达式一样,它们是强类型的,并且由表达式工厂(即QueryBuilder)构造。然后,可以参数化清单2中的查询,如清单10 所示:

清单10. 在CriteriaQuery 中使用参数

ParameterExpression< Integer> age = qb.parameter(Integer.class);

Predicate condition = qb.gt(p.get(Person_.age), age);

c.where(condition);

TypedQuery< Person> q = em.createQuery(c);

List< Person> result = q.setParameter(age, 20).getResultList();

比较该参数使用和JPQL 中的参数使用:参数表达式被创建为带有显式类型信息Integer,并且被直接用于将值20 绑定到可执行查询。额外的类型信息对减少运行时错误十分有用,因为阻止参数与包含不兼容类型的表达式比较,或阻止参数与不兼容类型的值绑定。JPQL 查询的参数不能提供任何编译时安全。

清单10中的例子显示了一个直接用于绑定的未命名表达式。还可以在构造参数期间为参数分配第二个名称。对于这种情况,您可以使用这个名称将参数值绑定到查询。不过,您不可以使用位置参数。线性JPQL 查询字符串中的整数位置有一定的意义,但是不能在概念模型为查询表达式树的CriteriaQuery 上下文中使用整数位置。

JPA 查询参数的另一个有趣方面是它们没有内部值。值绑定到可执行查询上下文中的参数。因此,可以合法地从相同的CriteriaQuery 创建两个独立可执行的查询,并为这些可执行查询的相同参数绑定两个整数值。

预测结果

您已经看到CriteriaQuery 在执行时返回的结果已经在QueryBuilder 构造CriteriaQuery 时指定。查询的结果被指定为一个或多个预测条件。可以通过两种方式之一在CriteriaQuery 接口上指定预测条件:

CriteriaQuery< T> select(Selection< ? extends T> selection);

CriteriaQuery< T> multiselect(Selection< ?>... selections);

最简单并且最常用的预测条件是查询候选类。它可以是隐式的,如清单11 所示:清单11. CriteriaQuery 默认选择的候选区段

CriteriaQuery< Account> q = cb.createQuery(Account.class);

Root< Account> account = q.from(Account.class);

List< Account> accounts = em.createQuery(q).getResultList();

在清单11中,来自Account 的查询没有显式地指定它的选择条件,并且和显式地选择的候选类一样。清单12 显示了一个使用显式选择条件的查询:

清单12. 使用单个显式选择条件的CriteriaQuery

CriteriaQuery< Account> q = cb.createQuery(Account.class);

Root< Account> account = q.from(Account.class);

q.select(account);

List< Account> accounts = em.createQuery(q).getResultList();

如果查询的预测结果不是候选持久化实体本身,那么可以通过其他几个构造方法来生成查询的结果。这些构造方法包含在QueryBuilder 接口中,如清单13 所示:

清单13. 生成查询结果的方法

< Y> CompoundSelection< Y> construct(Class< Y> result, Selection< ?>... terms);

CompoundSelection< Object[]> array(Selection< ?>... terms);

CompoundSelection< Tuple> tuple(Selection< ?>... terms);

清单13中的方法构建了一个由其他几个可选择的表达式组成的预测条件。construct() 方法创建给定类参数的一个实例,并使用来自输入选择条件的值调用一个构造函数。例如,如果CustomerDetails —一个非持久化实体—有一个接受String 和int 参数的构造方法,那么CriteriaQuery 可以通过从选择的Customer —一个持久化实体—实例的名称和年龄创建实例,从而返回CustomerDetails 作为它的结果,如清单14 所示:

清单14. 通过construct() 将查询结果包放入类的实例

CriteriaQuery< CustomerDetails> q = cb.createQuery(CustomerDetails.class);

Root< Customer> c = q.from(Customer.class);

q.select(cb.construct(CustomerDetails.class,

c.get(Customer_.name), c.get(Customer_.age));

可以将多个预测条件合并在一起,以组成一个表示Object[] 或Tuple 的复合条件。清单15 显示了如何将结果包装到Object[] 中:

清单15. 将结果包装到Object[]

CriteriaQuery< Object[]> q = cb.createQuery(Object[].class);

Root< Customer> c = q.from(Customer.class);

q.select(cb.array(c.get(Customer_.name), c.get(Customer_.age));

List< Object[]> result = em.createQuery(q).getResultList();

这个查询返回一个结果列表,它的每个元素都是一个长度为2 的Object[],第0 个数组元素为Customer 的名称,第 1 个数组元素为Customer 的年龄。

Tuple 是一个表示一行数据的JPA 定义接口。从概念上看,Tuple 是一个TupleElement 列表—其中TupleElement 是源自单元和所有查询表达式的根。包含在Tuple 中的值可以被基于0 的整数索引访问(类似于熟悉的JDBC 结果),也可以被TupleElement 的别名访问,或直接通过TupleElement 访问。清单16 显示了如何将结果包装到Tuple 中:

清单16. 将查询结果包装到Tuple

CriteriaQuery< Tuple> q = cb.createTupleQuery();

Root< Customer> c = q.from(Customer.class);

TupleElement< String> tname = c.get(Customer_.name).alias("name");

q.select(cb.tuple(tname, c.get(Customer_.age).alias("age");

List< Tuple> result = em.createQuery(q).getResultList();

String name = result.get(0).get(name);

String age = result.get(0).get(1);

这个查询返回一个结果列表,它的每个元素都是一个Tuple。反过来,每个二元组都带有两个元素—可以被每个TupleElement 的索引或别名(如果有的话)访问,或直接被TupleElement 访问。清单16中需要注意的两点是alias() 的使用,它是将一个名称绑定到查询表达式的一种方式(创建一个新的副本),和QueryBuilder 上的createTupleQuery() 方法,它仅是createQuery(Tuple.class) 的代替物。

这些能够改变结果的方法的行为和在构造期间被指定为CriteriaQuery 的类型参数结果共同组成multiselect() 方法的语义。这个方法根据最终实现结果的CriteriaQuery 的结果类型解释它的输入条件。要像清单14一样使用multiselect() 构造CustomerDetails 实例,您需要将CriteriaQuery 的类型指定为CustomerDetails,然后使用将组成CustomerDetails 构造方法的条件调用multiselect(),如清单17 所示:

清单17. 基于结果类型的multiselect() 解释条件

CriteriaQuery< CustomerDetails> q = cb.createQuery(CustomerDetails.class);

Root< Customer> c = q.from(Customer.class);

q.multiselect(c.get(Customer_.name), c.get(Customer_.age));

因为查询结果类型为CustomerDetails,multiselect() 将其预测条件解释为CustomerDetails 构造方法参数。如将查询指定为返回Tuple,那么带有相同参数的multiselect() 方法将创建Tuple 实例,如清单18 所示:

清单18. 使用multiselect() 方法创建Tuple 实例

CriteriaQuery< Tuple> q = cb.createTupleQuery();

Root< Customer> c = q.from(Customer.class);

q.multiselect(c.get(Customer_.name), c.get(Customer_.age));

如果以Object 作为结果类型或没有指定类型参数时,multiselect() 的行为会变得更加有趣。在这些情况中,如果multiselect() 使用单个输入条件,那么返回值将为所选择的条件。但是如果multiselect() 包含多个输入条件,结果将得到一个Object[]。

高级特性

到目前为止,我主要强调了Criteria API 的强类型,以及它如何帮助减少出现在基于字符串JPQL 查询中的语义错误。Criteria API 还是以编程的方式构建查询的机制,因此通常被称为动态查询API。编程式查询构造API 的威力是无穷的,但它的利用还取决于用户的创造能力。我将展示4 个例子:

?使用弱类型的API 构建动态查询

?使用数据库支持的函数作为查询表达式来扩展语法

?编辑查询实现“在结果中搜索” 功能

?根据例子进行查询—数据库社区熟悉的模式

弱类型和动态查询构建

Criteria API 的强类型检查基于开放期间的实例化元模型类的可用性。不过,在某些情况下,选择的实体仅能够在运行时决定。为了支持这种用法,Criteria API 方法提供一个并列版本,其中持久化属性通过它们的名称进行引用(类似于Java Reflection API),而不是引用实例化静态元模型属性。该API 的这个并列版本可以通过牺牲编译时类型检查来真正地支持动态查询构造。清单19 使用弱类型API 重新编写了清单6中的代码:

清单19. 弱类型查询

Class< Account> cls =Class.forName("domain.Account");

Metamodel model = em.getMetamodel();

EntityType< Account> entity = model.entity(cls);

CriteriaQuery< Account> c = cb.createQuery(cls);

Root< Account> account = c.from(entity);

Path< Integer> balance = account.< Integer>get("balance");

c.where(cb.and

(cb.greaterThan(balance, 100),

cb.lessThan(balance), 200)));

不过,弱类型API 不能够返回正确的泛型表达式,因此生成一个编辑器来警告未检查的转换。一种消除这些烦人的警告消息的方法是使用Java 泛型不常用的工具:参数化方法调用,比如清单19中通过调用get() 方法获取路径表达式。

可扩展数据库表达式

动态查询构造机制的独特优势是它的语法是可扩展的。例如,您可以在QueryBuilder 接口中使用function() 方法创建数据库支持的表达式:

< T> Expression< T> function(String name, Class< T> type, Expression< ?>...args); function() 方法创建一个带有给定名称和0 个或多个输入表达式的表达式。function() 表达式的计算结果为给定的类型。这允许应用程序创建一个计算数据

库的查询。例如,MySQL数据库支持CURRENT_USER() 函数,它为服务器用于验证当前客户机的MySQL 帐户返回一个由用户名和主机名组成的UTF-8 字符串。应用程序可以在CriteriaQuery 中使用未带参数的CURRENT_USER() 函数,如清单20 所示:

清单20. 在CriteriaQuery 中使用特定于数据库的函数

CriteriaQuery< Tuple> q = cb.createTupleQuery();

Root< Customer> c = q.from(Customer.class);

Expression< String> currentUser =

cb.function("CURRENT_USER", String.class, (Expression< ?>[])null);

q.multiselect(currentUser, c.get(Customer_.balanceOwed));

注意,在JPQL 中不能表达等效的查询,因为它的语法仅支持固定数量的表达式。动态API 不受固定数量表达式的严格限制。

可编辑查询

可以以编程的方式编辑CriteriaQuery。可以改变查询的子句,比如它的选择条件、WHERE 子句中的选择谓词和ORDER BY 子句中的排序条件。可以在典型的“在结果中搜索” 工具中使用这个编辑功能,以添加更多限制在后续步骤中进一步细化查询谓词。

SpringBoot整合SpringDataJPA,不用写SQ语句

SpringBoot整合SpringDataJPA,今天没啥事情就看了一下springboot整合springdataJPA,实在 SpringBoot整合SpringDataJPA 1、JPA概念 JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0 注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中. JPA的总体思想和现有Hibernate、TopLink、JDO等ORM框架大体一致。总的来说,JPA包括以下3方面的技术: ORM映射元数据 JPA支持XML和JDK5.0注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中; API 用来操作实体对象,执行CRUD操作,框架在后台替代我们完成所有的事情,开发者从繁琐的JDBC和SQL代码中解脱出来。 查询语言 这是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合 创建maven工程并导入依赖:(这里用的是sprigcloud2.1.16的)

org.springframework.boot spring-boot-starter-parent 2.1.16.RELEASE org.sprin mysql mysql-connector-java org.springframework.boot spring-boot-starter-test org.projectlombok lombok 2、配置文件application.yml server: port: 9090 spring: application: name: spring-data-jpa datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql:///user_db?serverTimezone=UTC username: root password: root #jpa配置 jpa: show-sql: true hibernate: ddl-auto: update 注意: url这里的配置必须要加入serverTimezone=UTC传递时区,不然操作数据库会抛异常的,///代表的是127.0.0.1:3306 本地的可以省略

停车场管理系统要点

北京科技大学计算机科学与技术专业生产实习报告项目名称:物品租赁平台设计与开发 学生姓名:徐松松 班级:计1304 学号:41345053 企业指导老师:邬志君 校内指导老师: 成绩: 地点:大唐移动通信设备有限公司 时间:2016 年7 月20 日

一、生产实习目的与实习要求 1、实习目的 生产实习旨在培养学生的实践能力、分析问题和解决问题的能力以及综合运用所学基础知识和基本技能的能力,同时也是为了增强学生适应社会的能力和就业竞争力。通过理论联系实际,巩固所学的知识,提高处理实际问题的能力。 互联网发展到3.0时代,进入互联网+综合服务的时代。互联网巨头纷纷专注于开发一个联系卖家和买家的平台,而自身不从事这个行业。为了最贴近计算机的生产环境,本次实习目标是开发一个物品租赁平台,个人可以自由发布空余物品。具体实践中以空闲车位作为物品.可以出租空闲车位、也可以租赁别人的空闲车位。通过实际动手开发,掌握JPA、WebService等开发技术,为顺利毕业进行做好充分的准备,并为自己能顺利与社会环境接轨做准备。 2、实习要求 本次生产实习,需要满足以下几点要求: 2.1掌握常用软件开发工具(MyEclipse、TortoiseSVN、Navicat)的使用,掌握根据实际开发需要查找使用工具的能力。 2.2能将具体的计算机知识应用到实际开发工作中,能独立进行工作,将自己的所学所想所感付诸实践,了解新型的软件开发模式,开发思想,开发技术。 2.3.能体会面向对象编程思想,熟悉UML图,能独立创建WebService项目,熟悉数据库设计及JPA开发。

2.4.能够进行团队合作,在团队中承担适合自己的角色,积累沟通经验及提升协作能力。 2.5能深刻体会敏捷开发、持续集成在软件开发中的优点和作用。 二、生产实习设备(环境)及要求 开发环境:win7/Linux/Mac OS 开发工具:MyEclipse2014/Eclipse 开发语言:JA V A JDK1.7 版本库平台:SVN 数据库:MySql 5.7 测试手段:Google Chrom/客户端测试工具 三、实习内容与步骤 1、内容1 (1)实习内容 我在项目中担任代码编写的工作,负责账号管理模块和计费查询模块的制作。首先是账号管理,实现系统的登录功能。 (2)主要步骤 一、登录流程图

Java EE期末考试题及答案 桂电三院

Java EE期末考试 ?填空题: ?Java EE为满足开发多层体系结构的企业级应用的需求,提出_组件-容器________的编程思想。Java EE应用的基本软件单元是_Java EE组件_______. 基本软件单元的运行环境被称为___容器________. ?两层体系结构应用程序分为__客户层_____和____服务器层_____. ?所谓的企业级应用程序,并不是特指为企业开发的应用软件,而是泛指那些为_大型组织部门__创建的应用程序。 ?在三层分布式企业应用程序中,包括_客户层____,__应用服务器层_____,____数据服务器层______三层。 ?Java EE客户端组件既可以是__一个Web浏览器__________、___一个Applet________,也可以是一个__应用程序______. ?Servlet组件在进行重定向时,需要使用ServletResponse接口的方法是__sendRedirect()______. ?httpServletRequest提供了两个方法用于从请求中解析出上传的文件:___Part getPart (String name)___________和__CollectiongetParts()___________。 ?Java EE 6提供的组件主要包括三类:_客户端组件____,__Web组件____,_业务组件____. ?Servlet配置参数保存在__ServletConfig()______________对象中,一个Servlet的该配置对象(能/否)___否(不能)__________被其他Servlet访问。 ?Servlet支持两种格式的输入/输出流:__字符输入/输出流______和__字节输入/输出流_。?MIME的全称是_多媒体Internet邮件扩展____, ServletResponse中响应正文的默认MIME 类型为_text/plain______________, 而HttpServetResponse中的响应正文的默认MIME类型为__text/html_________________. ?PDF文件的MIME类型是__application/pdf________________, Microsoft Word文档的类型是__application/msword___________。在Servlet中设置MIME类型应使用__response__对象的方法_____setContentType()________. ?所有的Servlet都必须实现下面的两个接口之一:__通用Servlet接口______和__HttpServlet接口_________。 ?HTTP协议是一种__无状态____协议,服务器不记录关于客户的任何信息。

springhibernatejpa联表查询复杂查询

Spring Hibernate JPA 联表查询复杂查询 今天刷网,才发现: 1)如果想用hibernate注解,是不是一定会用到jpa的?是。如果hibernate认为jpa的注解够用,就直接用。否则会弄一个自己的出来作为补充。 2)jpa和hibernate都提供了Entity,我们应该用哪个,还是说可以两个一起用? Hibernate的Entity是继承了jpa的,所以如果觉得jpa的不够用,直接使用hibernate的即可 正文: 一、Hibernate VS Mybatis 1、简介 Hibernate对数据库结构提供了较为完整的封装,Hibernate的O/R Mapping实现了POJO 和数据库表之间的映射,以及SQL 的自动生成和执行。程序员往往只需定义好了POJO 到数据库表的映射关系,即可通过Hibernate 提供的方法完成持久层操作。程序员甚至不需要对SQL 的熟练掌握,Hibernate/OJB 会根据制定的存储逻辑,自动生成对应的SQL 并调用JDBC 接口加以执行。 iBATIS 的着力点,则在于POJO 与SQL之间的映射

关系。然后通过映射配置文件,将SQL所需的参数,以及返回的结果字段映射到指定POJO。相对Hibernate“O/R”而言,iBATIS 是一种“Sql Mapping”的ORM实现 2、开发对比 Hibernate的真正掌握要比Mybatis来得难些。Mybatis 框架相对简单很容易上手,但也相对简陋些。个人觉得要用好Mybatis还是首先要先理解好Hibernate。针对高级查询,Mybatis需要手动编写SQL语句,以及ResultMap。而Hibernate有良好的映射机制,开发者无需关心SQL的生成与结果映射,可以更专注于业务流程 3、系统调优对比 Hibernate调优方案: 制定合理的缓存策略;尽量使用延迟加载特性;采用合理的Session管理机制;使用批量抓取,设定合理的批处理参数(batch_size);进行合理的O/R映射设计 Mybatis调优方案: MyBatis在Session方面和Hibernate的Session生命周期是一致的,同样需要合理的Session管理机制。MyBatis 同样具有二级缓存机制。MyBatis可以进行详细的SQL优化设计。 SQL优化方面: Hibernate的查询会将表中的所有字段查询出来,这一

Java课程学习路线图

Java课程学习路线图【最全】 Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。千锋Java课程紧跟热门互联网行业,采用真实企业项目实战,并特设专业技能提升课,让学员保持长足的成长。 第一阶段 1、JavaSE编程基础 DOS常用命令 安装JDK、设置环境变量 DOS系统编译、执行Java程序 Java的注释 标识符、标识符的命名规范 Java 关键字 Java的数据类型 变量的定义及初始化 Java的运算符 表达式 转义字符 运算符的优先级 类型转换 Java分支if...else 多重if、嵌套if

Java switch Switch vs if Java循环for、while 、doWhile 循环的嵌套 break、continue、return 方法的定义 方法的形参和实参 无返回值的方法 有返回值的方法 方法的重载 2、Java数组 Java 数组的定义 数组的静态赋值 数组的动态赋值 数组单个元素的访问 数组的遍历访问 数组的增强for循环 数组的排序 数组的顺序查找 数组的二分法查找 命令行参数args的使用 可变参数的应用

Arrays工具类的使用 二维数组的使用 3、Java面向对象 面向对象的分析与设计 面向对象与面向过程的区别 Java与面向对象 类的定义 对象的定义 类中成员变量及方法的定义 构造方法的定义和调用 构造方法的重载 面向对象的封装特性 this调用属性、方法、构造方法 局部变量和成员变量的作用域问题static静态属性、方法、代码块 工具类的概念及工具类的制作super关键字的使用及理解 Java中访问权限控制机制 继承中构造方法的细节 方法的重写 equals及toString方法的正确理解Java中的包机制

JPA_Basic

JPA 教程 1.JPA概述 JPA(Java Persistence API)作为Java EE 5.0平台标准的ORM规范,将得到所有Java EE服务器的支持。Sun这次吸取了之前EJB规范惨痛失败的经历,在充分吸收现有ORM框架的基础上,得到了一个易于使用、伸缩性强的ORM规范。从目前的开发社区的反应上看,JPA受到了极大的支持和赞扬,JPA作为ORM领域标准化整合者的目标应该不难实现。 JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中,图 1很好地描述了JPA的结构: Sun引入新的JPA ORM规范出于两个原因:其一,简化现有Java EE和Java SE应用的对象持久化的开发工作;其二,Sun希望整合对ORM技术,实现天下归一。JPA由EJB 3.0软件专家组开发,作为JSR-220实现的一部分。但它不囿于EJB 3.0,你可以在Web应用、甚至桌面应用中使用。JPA的宗旨是为POJO提供持久化标准规范,由此可见,经过这几年的实践探索,能够脱离容器独立运行,方便开发和测试的理念已经深入人心了。目前Hibernate 3.2、TopLink 10.1.3以及OpenJpa都提供了JPA的实现。

JPA的总体思想和现有Hibernate、TopLink,JDO等ORM框架大体一致。总的来说,JPA包括以下3方面的技术: ORM映射元数据,JPA支持XML和JDK 5.0注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中; JPA 的API,用来操作实体对象,执行CRUD操作,框架在后台替我们完成所有的事情,开发者从繁琐的JDBC和SQL代码中解脱出来。 查询语言,这是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合。 2.实体对象 访问数据库前,我们总是要设计在应用层承载数据的领域对象(Domain Object),ORM框架将它们持久化到数据库表中。为了方便后面的讲解,我们用论坛应用为例,建立以下的领域对象: Topic是论坛的主题,而PollTopic是调查性质的论坛主题,它扩展于Topic,一个调查主题拥有多个选项PollOption。这三个领域对象很好地展现了领域对象之间继承和关联这两大核心的关系。这3个领域对象将被映射到数据库的两张表中:

JavaEE简答题

JavaEE简答题修改版(30分,6题*5分) (一)第一章概述 1.三层体系结构的优点有哪些?P2 ①安全性高; ②易维护; ③快速响应; ④系统扩展灵活。 2.两层体系结构的缺点有哪些?p2-3 ①安全性低; ②部署困难; ③耗费系统资源。 3.简述Java EE的“组件-容器”编程思想。(P5,有两点,与填空题第1题互斥) ①JavaEE应用的基本单元是JavaEE组件,所有的javaEE组件都运行在特定的环境中。 ②组件的运行环境被称为容器。 4.Java EE体系结构的优点?p11,4点 ①独立于硬件配置和操作系统; ②坚持面向对象的设计原则; ③灵活性、可移植性和互操作性; ④轻松的企业信息系统集成。 (二)第三章Servlet 5.Servlet的基本工作流程?p21:6点 ①客户端将请求发送到服务器; ②服务器上的Web容器实例化Servlet,并为Servlet创建线程; ③Web容器将请求信息发送到Servlet; ④Servlet创建一个响应,并将其返回到Web容器; ⑤Web容器将响应返回客户端; ⑥服务器关闭或Servlet空闲时间超过一定限度时,调用dertory()方法退出。

6.在创建Web应用程序时,通过Servlet上下文可以实现哪些功能?p61,4点 ①访问Web应用程序资源; ②在Servlet上下文属性中保存Web应用程序信息; ③获取应用初始化参数信息; ④提供日志支持。 7.HttpServletResponse的sendRedirect方法与RequestDispatcher的forward方法有什么区 别?p68:3点 ①从操作本质上,RequestDispatcher.forward()是容器控制权的转向,在客户端浏览器的地址栏中不会显示出转向后的地址,而sendRedirect()则是完全的跳转,浏览器将会得到跳转的地址,并重新发送请求连接。 ②从性能上,前者仍是在同一次请求处理过程中,后者是结束第一次请求,由浏览器发起一次新的请求。因此前者更高效。 ③从跳转的范围上,HttpServletResponse()能够跳转到其他服务器上的资源,而RequestDispatcher.forward()只能转向Web应用内部的资源。 8.Filter的主要用途是什么?p69: 3点 ①访问特定资源时的身份验证; ②访问资源的记录跟踪; ③访问资源的转换。 (三)第四章JSP 9.列举JSP的5个内置对象,并做简要说明。 答:request、response、out、session、application、config、pageContext、page、exception (任选5个,并用一句话说明) ①request对象:代表来自客户端的请求,它封装了用户提交的信息; ②response对象:代表服务器对客户端的响应; ③out对象:代表向客户端发送数据的对象; ④application对象:代表运行在服务器上的Web应用程序,相当于Servlet上下文; ⑤exception对象:用来处理JSP文件在执行时所有发生的错误和异常。 10.与response.sendRedirect()实现重定位有何不同?p114 response.sendRedirect()其实是向浏览器发送一个特殊的Header,然后由浏览器来做转向,转到指定的页面,在浏览器上的地址栏上可以看到地址的变化; 而则不同,它是直接在服务器端执行重定位的,浏览器并不知道。

jpa查询语言

JPA查询语言(JPQL) JPQL,SQL和批量处理 白汉奇[译] 目录 概述 (1) 类型 (2) 保留标志符 (4) 路径表达式 (4) 界定变量(Range Variables) (6) JOINS (6) INNER JOIN (7) LEFT OUTER JOIN (7) FETCH JOIN (8) WHERE,GROUP BY,HAVING (10) 条件表达式(CONDITIONAL EXPRESSIONS) (10) 函数与表达式(FUNCTIONS AND EXPRESSIONS) (10) 字符串函数(STRING FUNCTIONS) (13) 数学函数(ARITHMETIC FUNCTIONS) (13) 时间函数(DATETIME FUNCTIONS) (14) SECLECT函数 (14) 构造器函数(CONSTRUCTOR EXPRESSION) (15) 统计函数(AGGREGATE FUNCTIONS) (15) 使用法则(RULES OF USAGE) (16) 排序(ORDER BY) (16) 批量处理(BULK OPERATIONS) (17) 实例 (18) 总结(SUMMARY) (20) 本章探讨Java持久化查询语言(JPQL),在简单的向你介绍JPQL后,会直接切入创建查询这个话题。 本章会涉及一个查询的方方面面,包括fetch join操作。fetch join操作会提前读取延时关 联(lazy relationship),以消除LazyInitializationException异常,这在使用ORM方案时,常 常困扰很多应用程序的开发。接下来,会了解一下JPQL的打量操作支持。学习完本章时,你会对 JPQL有一个全面的认识。 概述 JPQL是一种与数据库无关的,基于实体(entity-based)的查询语言。它是EJB QL的一个扩展,并加 入了很多EJB QL中所没有的新特性。JPQL支持projection(可以查询某个实体的字段而不需要查询 整个实体),批量操作(update和delete),子查询,join,group by和having操作。所有的JPQL操作都 在静态查询(命名查询,named query)和动态查询中得到支持。另外,JPQL支持多态,当读取Rank 会返回SpecialRank和PostCountRank实例(instance)(Rank是一个抽象类,JPQL只返回具体 类)。 JPQL在语法上与SQL相似:“ select from[where][group by][having][order by] ”。如果你熟悉SQL,那么对大部分的JPQL语法也不会陌生。JPQL同样支持SQL类似的函数功能, 如max和min,但是并不能取代SQL。不管如何相似,但两者之间有一个重要的区别,JPQL操作的 是“抽象持久化模型(abstract persistence schema)”,而不是数据库定义的物理模型。抽象持久化模型

jee考试题带答案

西北农林科技大学本科课程考试试题(卷) 2012—2013学年第1学期《J2EE技术》课程A卷专业班级:命题教师:审题教师: 学生姓名:学号:考试成绩: 本试卷由笔试和机试两部分组成。一到三题为笔试部分,第四题为机试部分 一、选择题(每题3分【按空分配分数】,共30分)得分:分 1. 相比于Spring,基于EJB的Java EE技术作为企业级应用解决方案的主要优势体现在(),使得开发出的应用是可向外伸缩的 (scale-out)。 A. 安全性 B. 运行的时空效率 C. 事务处理能力 D. 支持分布的能力 企业级的与普通javabean的区别是企业级的不仅可以供本地客户端访问,还可以供远程客户端访问。本质区别是访问者和被访问者是否位于同一台虚拟机上。 2.消息服务 (Message Service) 与方法调用 (Method Invocation)两者的最大区别就是:消息服务还可以实现()、()以及异构系统集成。 Java消息服务(JMS)是一个消息标准,它允许javaEE应用程序组件生成、发送、接收和读取消息。它能够进行分布式的、松耦合的、可靠地、异步的信息交流。 A. 异步 B. 业务调用 C. 松耦合 D. 消息传递 3. 关于无状态会话bean和有状态会话bean中“状态”说法正确的是()。 A. 有状态会话bean实例有对应的生命周期,而无状态会话bean则没有 B. 有状态会话bean可维持同一个客户端的多个调用之间的状态信息,无状态会话bean则不能 C. 有状态会话bean可以实现业务对象的持久化,无状态会话bean不能 D. 有状态会话bean可以维护HTTP客户端的状态,无状态会话bean不能 4.JPA实体之间的关系包括一对一、多对多、(对多一)和(一对多)共四种关联关系,以及( D )关系。 Java Persistence API java持久化,实体类表示对象,是对数据库中记录的表示 A. 一对多 B. 多对一 C. 继承 D. 映射 5. 判断访问EJB的方式是本地 (local) 访问还是远程 (remote) 访问取决于

Koala优势

企业级应用快速开发工具 ————考拉的几大优势 完整的技术开发解决方案 使用Koala,可以完整的覆盖从项目创建开始,到编码,测试,部署发布,监控等各方面,解决项目开发的技术问题 Koala包含以下组件: 向导式项目定制与生成,不用再去整合各种技术,写大量配置,只需轻松定制,生成全新项目 丰富的组件,包含缓存,国际化,异常机制,FTP,EXCEL读取等,这些都是在大量的项目实践的基础上提取出来的组件,具有较高的重用性 向导式的增删改查的功能实现,实体的增删改查经常是非常重复的工作,现在K oala为你提供了向导式的生成且生成原生的java,jsp等,没有侵入性。 权限子系统,你可以立刻使用Koala的权限子系统,基于RBAC3模型的以用户,角色,资源为核心的关系而建立,可以控制任意URL,方法,按钮,图片等。 流程子系统,基于JBPM5的流程平台,包含流程设计平台与流程引擎平台,你只须关注如何设计一个流程,其它的平台为你解决。 监控子系统,为你监控http请求,看到请求最多或最耗时的业务;为你监控方法,请求最多或最耗时或异常的方法;为你监控数据库资源,连接池健康状态监控以及 SQL监控,还有更多的监控 方便的测试支持,无须关心任何细节与测试的配置,开发人员只专注于业务测试,不需要搭建任何测试支持环境; 统一的代码风格约束,基于checkstyle及pmd的代码检查集成,包含针对开发人员的eclipse插件以及针对检查人员或上级领导的代码质量报告,轻松约束整个项目 组的代码风格规范 透明的部署机制:只需开发一次,你可以轻松的把你项目中的服务发布成soap webservice,restful webservice以及EJB,还可以把项目发布成WAR+EJB或WAR两 种部署形式。这些都是向导式的过程,无须开发人员进行任何代码的修改,Koala 为你生成新的源码及发布包。 WS的安全机制,使用koala发布的Webservice,你立刻就可以获得基于IP过滤及用户名密码验证,方法级权限控制的webservice安全机制,发布便集成,无须任 何开发。 从数据库到实体的自动化生成过程,同样是向导式的,节省大量时间 通用查询组件,项目中的一些查询需求,你只需要通过通用查询组件轻松定制就可,方便快捷 持续集成支持,从Koala创建项目开始,你可以立刻获得包含bug管理,每日构建以及svn,git版本管理支持功能。

JPA学习笔记

目录 目录 (1) 一、JPA基础 (2) 1.1JPA基础 (2) 1.2JPA开发过程 (3) 1.3 实体的生命周期及实体管理器常用方法 (4) 二、环境搭建 (5) 2.1 添加JPA支持 (6) 2.2 添加配置文件 (6) 2.3测试配置 (6) 2.4 环境搭建附表 (6) 三、常用注解 (12) 3.1 批注完全参考 (12) 3.2 ID相关的 (12) 3.3主键生成策略 (13) 3.4字段、添加字段、添加表关联 (13) 3.5映射相关 (14) 3.6其他 (14) 四、JPA映射 (14) 4.1一对一映射 (15) 4.1.1共享主键映射 (15) 4.1.2关联外键映射 (17) 4.1.3添加表关联 (17) 4.2一对多关联 (18) 4.2.1添加字段的一对多、多对一关联 (18) 4.2.2添加表的一对多、多对一关联 (19) 4.3多对多关联 (20) 4.4继承映射 (21) 五、JPQL (21) 六、常见异常 (22)

一、JPA基础 1.1 JPA基础 JPA:java persistence api 支持XML、JDK5.0注解俩种元数据的形式,是SUN公司引入的JPA ORM规范 元数据:对象和表之间的映射关系 实体:entity,需要使用Javax.persistence.Entity注解或xml映射,需要无参构造函数,类和相关字段不能使用final关键字 游离状态实体以值方式进行传递,需要serializable JPA是一套规范、有很多框架支持(如Hibernate3.2以上、Toplink,一般用Hibernate 就行 oracle可以用toplink) JPQL 1、与数据库无关的,基于实体的查询语言 2、操作的是抽象持久化模型 3、JPQL是一种强类型语言,一个JPQL语句中每个表达式都有类型 4、EJBQL的扩展 5、支持projection(可以查询某个实体的字段而不需要查询整个实体)、批量操作(update、delete)、子查询、join、group by having(group by聚合后 having 聚合函数比较条件) 弱类型语言:没有明显的类型、根据情况变化、容易出错 强类型语言:没个变量都有固定的类型。不容易出错 虽然JPA规范中明确表示无法访问一个集合关系字段 抽象模型类型:JPQL规范将一个实体(属性)中所饮食的各种类型称为抽象模型类型状态字段 关联字段

EJB3 JPA 调用原生SQL 和 函数 存储过程

1. 调查JPQL如何使用原生SQL …………….//创建EntityManager em List users = em.createNativeQuery("SELECT * FROM USER").getResultList(); for(int i=0;i< users.size();i++){ Object[] object = (Object[])users.get(i); for(int j=0;j9980) order by cid desc; 执行时间0.03秒 2.按分析函数来分 select * from (select t.*,row_number() over(order by cid desc) rk from t_xiaoxi t) where rk<10000 and rk>9980; 执行时间1.01秒 3.按ROWNUM来分 select * from(select t.*,rownum rn from(select * from t_xiaoxi order by cid desc) t where rownum<10000) where rn>9980;执行时间0.1秒 其中t_xiaoxi为表名称,cid为表的关键字段,取按CID降序排序后的第9981-9999条记录,t_xiaoxi表有70000多条记录 个人感觉1的效率最好,3次之,2最差

JPA开发文档(大全)

JPA开发文档(大全) 这是一份比较全面的JPA文档,希望能够帮助大家,让大家更好的学习工作。 1.发展中的持久化技术 3 1.1 JDBC (3) 1.2 关系对象映射(Object Relational Mapping,ORM) (3) 1.3 Java 数据对象(Java Data Object,JDO) (3) 1.4 Java Persistence API(JPA) (3) 2.JPA 体系架构 (5) 3.Entity Bean (7) 3.1定义对Entity中属性变量的访问 (7) 3.2 主键和实体标识(Primary Key and Entity Identity) (9) 4.EntityManager (10) 4.1 配置和获得EntityManager (10) 4.2 Entity的生命周期和状态 (10) 4.3 持久化Entity(Persist) (11) 4.4 获取Entity (13) 4.5 更新Entity (13) 4.6 删除Entity (13) 4.7 脱离/附合(Detach/Merge) (14) 5.JPA Query (14) 5.1 Query接口 (15) 5.2 简单查询 (15) 5.3 使用参数查询 (16) 5.4 排序(order by) (16) 5.5 查询部分属性 (17) 5.6 查询中使用构造器(Constructor) (17) 5.7 聚合查询(Aggregation) (18)

5.8 关联(join) (19) 5.9比较Entity (20) 5.10 批量更新(Batch Update) (21) 5.11批量删除(Batch Remove) (21) 1.发展中的持久化技术 1.1 JDBC 很多企业应用的开发者选择使用JDBC 管理关系型数据库中的数据。JDBC支持处理大量的数据,能够保证数据的一致性,支持信息的并发访问,提供SQL 查询语言查找数据。JDBC 所使用的关系模型不是为保存对象而设计的,因此迫使开发者选择在处理持久数据时放弃面向对象编程,或者自己去开发将面向对象特性(比如:类之间的继承)和关系型数据库进行映射的专有解决方案。 1.2 关系对象映射(Object Relational Mapping,ORM) ORM 是目前完成对象和关系数据表之间的映射最好的一种技术,这些ORM 框架处理对象和关系数据库之间的协调工作,将开发者从这部分工作中解脱出来,集中精力处理对象模型。阻碍ORM 发展的问题是,现有的每一种ORM 产品都有自己特有的API,开发者只能将自己的代码绑定到某一个框架提供商的接口上,这种状况形成了厂商锁定,意味着一旦该框架提供商无法解决系统中出现的严重错误,或者因为其它的原因转而采用其它的框架,将会给开发者的企业应用带来极大的困难,唯一的解决办法是重写所有的持久化代码。 1.3 Java 数据对象(Java Data Object,JDO) JDO 是Java EE 标准中另外一个支持管理持久化数据的规范,JDO 规范使用和JPA 非常类似的API,只是通常是通过JCA 技术集成到应用服务器上。但是JDO 是针对轻量级容器而设计的,不能够支持容器级别的声明式安全、事务特性,也无法对远程方法调用提供支持。 1.4 Java Persistence API(JPA)

JavaEE学习心得与总结

学习Java EE心得体会 这学期通过对Java EE五部分的学习,掌握了 java的基本开发方法, 学习JavaEE基础部分分为6大部分,分别是基础服务,Java Web开发,Web Service, JSF框架,EJB部分和JPA。 其中第一部分是基础服务部分,此部分包括六章:第一章是概述,介绍了 java EE的发 展历史,架构,组件,服务,容器等概念,并介绍了平台角色以及开发环境和应用服务的选择与安装。第二章讲了使用 JNDI访问明明和目录服务,介绍了什么是命名和服务目录, 以及如何通过 JNDI访问Weblogic提供的命名目录服务。第三章讲了使用JDBC访问 数据库,介绍了 JDBC的基本用法以及连接池的配置和访问。第四章讲了使用JTA进行事 物处理,介绍了事物处理概念以及如何通过JTA进行事务处理。第五章RMI :远程方法 调用,介绍了 RMI的结构以及如何使用 RMI进行编程。第六章,使用JMS接发消息,介绍了消息服务的概念,在Weblogic中消息服务相关的配置以及如何通过JMS开发消息发送 和接受程序。 J2EE是一种技术,旨在简化企业应用程序的设计和实施。在本教程中,您将学习 J2EE是什么,它的好处,J2EE的主要组成部分,企业应用框架的演变,为什么要使用 J2EE,J2EE平台架构,J2EE API和技术和J2EE参考实现。在继续之前,我们的J2EE讨论让定义企业应用程序是什么。企业应用程序是一个应用程序, 它可能要继续使用他们,同时添加或迁移到一个新的利用互联网,电子商务等新技术的应用, 集传统的现有应用程序和数据库。 Java EE架构分为四层,客户端层,Web层,EJB层和数据库层,其中,数据 库层为系统提供数据存储和数据库管理功能,在整个企业级应用中可能村爱很多个数据库,并且采用不同类型的数据库管理系统进行管理。EJB层也称为业务逻辑层,用于完成系统中复杂的或者共享的业务,这些功能主要是提供客户端层和Web层调 用,用户不会直接调用该层。Web层是基于HTTP的访问方式,客户通过Web层 访问系统的业务逻辑和数据等。客户端层包括Applet客户端和Application客户端,客户通过客户端的形式访问系统的业务逻辑和数据等。逻辑中的四层可能不同时出 现在系统中,例如某个系统可能只提供Web形式的客户端,并且不使用EJB技术, 此时系统图只留下Web层和数据库层。 Java运行环境定义了五种类型的应用组件,包括客户端组件 Application和Applet,Web 层组件JSP和Servlet,EJB组件等,这些组件类型是 Java EE产品必须支持的。 其中的JPA是我学习的重点。JPA包括以下3方面的技术:(1). ORM映射元数据,JPA 支持XML和JDK 5.0注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中?( 2). JPA的API,用来操作实体对象,执行CRUD操作, 框架在后台替我们完成所有的事情,开发者从繁琐的JDBC和SQL代码中解脱出来。(3).查 询语言,这是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询语言查 询数据,避免程序的 SQL语句紧密耦合。JPA的优势包括:1标准化,JPA是JCP组织发布的Java EE 标准之一,因此任何声称符合JPA标准的框架都遵循同样的架构,提供相 同的访问API,这保证了基于JPA开发的企业应用能够经过少量的修改就能够在不同的JPA 框架下运行。2对容器级特性的支持,JPA框架中支持大数据集、事务、并发等容器级事务,这使得JPA超越了简单持久化框架的局限,在企业应用发挥更大的作用。3简单易用,集成方便,JPA的主要目标之一就是提供更加简单的编程模型:在JPA框架下创建实 体和创建Java类一样简单,没有任何的约束和限制,只需要使用javax.persistence.Entity 进行注释;JPA的框架和接口也都非常简单,没有太多特别的规则和设计模式的要求,开发 者可以很容易的掌握。JPA基于非侵入式原则设计,因此可以很容易的和其它框架或者容器

JPA_Basic

好书 JPA 教程 1.JPA概述 JPA(Java Persistence API)作为Java EE 5.0平台标准的ORM规范,将得到所有Java EE服务器的支持。Sun这次吸取了之前EJB规范惨痛失败的经历,在充分吸收现有ORM框架的基础上,得到了一个易于使用、伸缩性强的ORM规范。从目前的开发社区的反应上看,JPA受到了极大的支持和赞扬,JPA作为ORM领域标准化整合者的目标应该不难实现。 JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中,图 1很好地描述了JPA的结构: Sun引入新的JPA ORM规范出于两个原因:其一,简化现有Java EE和Java SE应用的对象持久化的开发工作;其二,Sun希望整合对ORM技术,实现天下归一。JPA由EJB 3.0软件专家组开发,作为JSR-220实现的一部分。但它不囿于EJB 3.0,你可以在Web应用、甚至桌面应用中使用。JPA的宗旨是为POJO提供持久化标准规范,由此可见,经过这几年的实践探索,能够脱离容器独立运行,方便开发和测试的理念已经深入人心了。目前Hibernate 3.2、TopLink 10.1.3以及OpenJpa都提供了JPA的实现。

JPA的总体思想和现有Hibernate、TopLink,JDO等ORM框架大体一致。总的来说,JPA包括以下3方面的技术: ORM映射元数据,JPA支持XML和JDK 5.0注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中; JPA 的API,用来操作实体对象,执行CRUD操作,框架在后台替我们完成所有的事情,开发者从繁琐的JDBC和SQL代码中解脱出来。 查询语言,这是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合。 2.实体对象 访问数据库前,我们总是要设计在应用层承载数据的领域对象(Domain Object),ORM框架将它们持久化到数据库表中。为了方便后面的讲解,我们用论坛应用为例,建立以下的领域对象: Topic是论坛的主题,而PollTopic是调查性质的论坛主题,它扩展于Topic,一个调查主题拥有多个选项PollOption。这三个领域对象很好地展现了领域对象之间继承和关联这两大核心的关系。这3个领域对象将被映射到数据库的两张表中:

JPA 各种基本用法

JPA 各种基本用法 JPQL就是一种查询语言,具有与SQL 相类似的特征,JPQL 是完全面向对象的,具备继承、多态和关联等特性,和hibernate HQL很相似。 查询语句的参数 JPQL 语句支持两种方式的参数定义方式: 命名参数和位置参数。。在同一个查询语句中只允许使用一种参数定义方式。 命令参数的格式为:“ : + 参数名” 例: Query query = em.createQuery("select p from Person p where p.personid=:Id "); query.setParameter("Id",new Integer(1)); 位置参数的格式为“ ?+ 位置编号” 例:

Query query = em.createQuery("select p from Person p where p.personid=?1 "); query.setParameter(1,new Integer(1)); 如果你需要传递java.util.Date 或java.util.Calendar 参数进一个参数查询,你需要使用一个特殊的setParameter() 方法,相关的setParameter 方法定义如下: public interface Query { // 命名参数查询时使用,参数类型为java.util.Date Query setParameter(String name, java.util.Date value, TemporalType temporalType); // 命名参数查询时使用,参数类型为java.util.Calendar

相关主题
文本预览
相关文档 最新文档