扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
尽管有不少选择可以用来来构建应用程序的持久化层,但是并没有一个统一的标准可以用在Java EE环境和Java SE环境中。EJB3Java持久化API为我们带来了好消息,作为EJB 3.0规范(JSR-220)中的一部分,它标准化了Java平台下的持久化API。JSR-220已经被O-R Mapping软件生产商广泛支持,例如TopLink 和 Hibernate,同时它还被一些应用服务器生产商和JDO生产商所支持。EJB3规范为Java企业应用构建持久化层提供了一个强制性的选择。
在这篇文章中,笔者将会使用一个简单的对象模型作为例子来介绍EJB3 Java 持久化 API。
领域模型
当你构建一个企业应用时,你首先设计需要持久化到数据库中的领域模型。然后,你需要和数据库设计人员一起设计好数据库结构。领域模型是持久化对象或者实体的代表。一个实体可以是一个人,一个地方,或者任何其他你想要存储的数据。它同时包含了数据和行为。一个rich领域模型具有所有的OO的特征,例如继承和多态(inheritance and polymorphism)。
我们作为示例使用的这个简单的领域模型如下,部门(Department)和雇员(Employee)实体之间具有双向的一对多关系,而全职员工(FullTime)和承包工(Contractor)实体都是从雇员实体继承而来。
图 1. 示例领域对象模型
O-R映射框架和EJB3 JPA的基础
如果你使用过Oracle TopLink这样的O-R映射框架构建过应用程序的持久化层,那么你会注意到每个持久化框架都会提供3种机制
1. 声明性的O-R 映射方法。这种方法,叫做O-R映射元数据,使得你可以将一个对象映射到数据库中的一个或者多个表。大部分的O-R映射框架都使用XML来存储O-R映射的元数据。
2. 用来操作实体的API(例如,来执行CRUD操作)。API让你用来持久化,获取,更新或者删除对象。基于O-R映射元数据和API的使用,O-R映射框架代替你来完成各种数据库操作。API将你从繁琐的JDBC和SQL代码中解救出来。
3. 一种查询语言来获取对象。这是持久化操作的很重要的一个方面,因为不合适的SQL语句会使得你的数据库操作变慢。这种查询语言避免了在应用程序中混杂大量SQL语句的现象。
EJB3 Java 持久化API标准化了Java平台下的持久化操作,它提供一种标准的O-R映射机制,一组EntityManager API来进行CRUD操作,以及一种扩展的EJB-QL语言来获取实体。笔者将在分别讨论这3个方面。
元数据标注
Java SE 5.0 引入了元数据标注。Java EE的所有组件,包括 EJB3 JPA,都大量使用了元数据标注来简化企业Java应用的开发。想要了解更多的元数据标注方面的知识,请参阅Kyle Downey 写的Bridging the Gap: J2SE 5.0 Annotations文章。在EJB3 JPA中,元数据可以用来定义对象,关系,O-R映射以及持久化上下文(Context)的注入。JPA同样提供了使用XML描述符来提供持久化元数据的方法。而笔者则会重点讲述使用标注的方式,因为这使得开发变得更加简单。但是,在产品部署阶段,你或许会倾向于使用XML描述符,你可以使用XML描述符来覆盖标注定义的持久化行为。
在JPA中将O-R映射标准化
定义持久化对象:实体
一个实体是一个轻量级的领域对象――一个需要持久化到关系数据库中的POJO。与其他的POJO一样,一个实体可以是抽象类或者具体类,而且它可以从其他POJO扩展得到。可以使用javax.persistence.Entity标注将一个POJO标注成一个实体
下面是如何将领域模型中的Department对象变成一个实体的例子:
package onjava; import java.io.Serializable; import java.util.Collection; import javax.persistence.*; @Entity @NamedQuery(name="findAllDepartment", query="select o from Department o") @Table(name="DEPT") public class Department implements Serializable { @Id @Column(nullable=false) protected Long deptNo; @Column(name="DNAME") protected String name; @Column(name="LOC") protected String location; @OneToMany(mappedBy="department") protected Collection<Employee> employees; public Department() { } ... public Collection<Employee> getEmployees() { return employees; } public void setEmployees(Collection<Employee> employees) { this.employees = employees; } public Employee addEmployee(Employee employee) { getEmployees().add(employee); employee.setDepartment(this); return employee; } public Employee removeEmployee(Employee employee) { getEmployees().remove(employee); employee.setDepartment(null); return employee; } } |
每一个实体都有一个主键;可以在一个持久化字段(field)或者属性上使用Id标注来将它作为一个主键。一个实体可以通过使用字段或者属性(通过 setter and getter 方法)来维护自己的状态。这取决于你在何处使用Id标注。上面的例子中采用了基于字段的访问,我们在deptNo字段上使用了Id标注。如果要使用基于属性的访问,你需要在属性上使用Id这样的标注。
@Id public Long getDeptNo() { return deptNo; } public void setDeptNo(Long deptNo) { this.deptNo = deptNo; } |
必须注意,在一个实体继承体系中的所有实体,都必须使用通用的访问类型,或者都使用字段,或者都使用属性。
一个实体中定义的所有字段,默认情况下,都会进行持久化。如果你不想存储某个字段(或者属性),你必须将字段(或者属性)定义成临时的,通过采用@Transient标注或者采用transient修饰符。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者