- 浏览: 305533 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (167)
- <HTML and JavaScript and CSS> (6)
- 《Java2 基础知识及概念》 (3)
- Java2 Tools及其他 (11)
- EJB2.0 相关 (3)
- 英语学习 (4)
- Oracle Database Server (27)
- 计算机理论 (9)
- Java持久层框架 (2)
- 《Linux操作系统》 (24)
- 杂项技术 (4)
- Application Server (15)
- Windows操作系统 (7)
- Java中间件 (6)
- 娱乐生活 (4)
- 《Java设计模式》 (3)
- 《Interview Skill》 (1)
- 《Struts原理及应用》 (1)
- Workflow (2)
- 云计算 (3)
- 项目实践 (3)
- WEB相关技术 (10)
- JavaScript技巧及应用 (1)
最新评论
本文中我们将以实体之间的一对一关联关系为例,深入地讲述如何使用 OpenJPA 框架提供的注释,实现企业应用中实体之间的关联关系。文中将提供一个简单的例子,详细的说明如何定义类和类之间的一对一关联关系的步骤,同时会重点讲述这些注释所支持的属性。一对多、多对一和多对多这三种关联关系在 OpenJPA 中的实现过程和一对一关联关系的实现过程是一致的,只是需要选择使用不同的注释,在本文的最后,会对实现这三种关联关系进行简单说明,读者可以参考一对一关系的实现过程来实现一对多、多对一和多对多的关联关系。
在面向对象的世界里,类 A 和类 B 之间形成一对一关系必须满足如下条件:
- 对象 A1 引用了对象 B1;
- 类 A 的其它对象 An 不能引用同样的对象 B1。
在关系数据库中,我们通常使用唯一外键的方式来实现一对一关系,下面这个图说明了这种的情况。
下面开始介绍 OpenJPA 中实现实体之间一对一关联关系的相关知识,为了说明的需要,我们首先定义一个简单的应用场景。
假定开发者要完成一个图书馆管理系统,我们需要记录书的基本信息如编号、书名、出版日期等基本信息,还需要记录书的前言,序等信息。
为了说明实体之间的一对一关系,我们将书设计成一个类(Book),包括书的编号和名称两个属性,同时将书的前言设计成另外一个类(BookExtend),它包括书的编号和前言两个属性。由于一本书有前言而且也不可能有其它书的前言部分会和它一样,所以类 Book 和 BookExtend 之间很自然的形成了一对一的关系。这两个类的属性以及类之间的关系如下图所示。
[注]:为了说明的简单,本例子设计时每个对象只选择了必要的属性。
在 OpenJPA 中,开发者用来描述实体之间一对一关系时可选择的注释包括 javax.persistence.OneToOne
和 javax.persistence.JoinColumn
。其中 javax.persistence.OneToOne
注释是必须使用的,它被用来声明类和类之间存在着一对一关系,javax.persistence.JoinColumn
注释是可选的,开发者使用 JoinColumn
注释来声明两个类在数据库中对应的表之间关联时的细节,包括主表中关联字段的名称、从表中使用什么字段来进行关联等。
javax.persistence.OneToOne
注释支持如下 5 个属性,它们可以被开发者用来定义实体和实体之间一对一关联关系的细节内容。
target Entity
targetEntity
属性是 Class 类型的属性。定义实体一对一关系中处于从属地位的实体类的类型。如果没有为该属性设置值,OpenJPA 容器默认 targetEntity
属性的值是该成员属性对应的类类型,所以实体关系定义时通常不需要为 targetEntity
属性设置值。
mappedBy
mappedBy
属性是 String 类型的属性。mappedBy
属性的值是当前实体在关联实体中的属性名称,使用 mappedBy
可以定义实体类之间的双向关系。如果类之间是单向关系,不需要提供定义,如果类和类之间形成双向关系,我们就需要使用这个属性进行定义,否则可能引起数据一致性的问题。
以演示场景中 Book 和 BookExtend 实体为例,假设我们只定义 Book 类有 BookExtend 类型的属性,而 BookExtend 并没有 Book 类型的属性,那么说明 Book 和 BookExtend 实体之间是单向关系;如果 BookExtend 中也定义了 Book 属性,那么 Book 和 BookExtend 实体之间就构成了双向关系。
cascade
cascade
属性的类型是 CascadeType[]
类型。cascade
属性定义实体和实体之间的级联关系。使用 cascade
属性定义的级联关系将被容器视为对当前类对象及其关联类对象采取相同的操作,而且这种关系是递归调用的。
以演示场景中 Book 和 BookExtend 实体为例:如果设置 Book 和 BookExtend 存在级联关系,那么删除 Book 时将同时删除它所对应的 BookExtend 对象。而如果 BookExtend 还和其它的对象之间有级联关系,那么这样的操作会一直递归执行下去。
cascade
的值只能从 CascadeType.PERSIST
(级联新建)、CascadeType.REMOVE
(级联删除)、CascadeType.REFRESH
(级联刷新)、CascadeType.MERGE
(级联更新)中选择一个或多个。还有一个更方便的选择是使用 CascadeType.ALL
,表示选择上面全部四项。
fetch
fetch
属性是 FetchType
类型的属性。可选择项包括:FetchType.EAGER
和 FetchType.LAZY
。前者表示关联关系的从类在主类加载的时候同时加载,后者表示关联关系的从类在自己被访问时才加载。默认值是 FetchType.EAGER
。
optional
optional
属性是 boolean 类型的属性。optional
属性用于定义关联关系的从类对象是否必须存在。如果设置为 false,那么该属性就不能设置为 null。默认值是 true。
javax.persistence.OneToOne 用法举例
public class Book { // 其它实体映射内容… /* * 使用 OneToOne 注释表示该属性和 Book 类形成一对一关系,OneToOne * 注释的 option 属性设为 True 表示该对象可以不存在,cascade 属性 * 设置为 CascadeType.ALL,表示 Book 和 BookExtend 对象级联新建、 更新、删除、刷新 */ @OneToOne(optional=true,cascade=CascadeType.ALL) public BookExtend bookExtend; } |
javax.persistence.JoinColumn
注释可以和 javax.persistence.OneToOne
注释一起使用,用于定义关联关系中的主类在数据库中对应的表通过什么字段和关联关系中的从类的主键进行关联,这个注释是可选的,如果不提供该注释,OpenJPA 会默认使用”对象名_ID”和关联表的主键字段进行关联。
以演示场景中 Book 和 BookExtend 实体为例:如果 Book 的 bookExtend 属性没有使用 javax.persistence.JoinColumn
注释进行声明,我们使用 OpenJPA 提供的 Mapping Tool 工具生成表格的时候,Book 类对应的表 Book 中将自动加入列 bookExtend_ID,它的类型将和 BookExtend 对应表的主键字段id类型保持一致。
JoinColumn
注释支持两个重要属性:name
和 referencedColumnName
属性。
name
name
属性的类型是 String 类型。name
属性用于指定关联关系中的主类对应的表中和关联关系中的从类的主键进行关联的字段的名称。以演示场景中 Book 和 BookExtend 实体的关系为例:如果 Book 实体对应的表使用“beID”字段和 BookExtend 实体对应表的主键进行对应,我们可以在 Book 类中为 bookExtend 属性提供 javax.persistence.JoinColumn
注释,设置它的 name 属性为“beID”。
referencedColumnName
referencedColumnName
属性的类型是 String 类型。referencedColumnName
属性指定关联关系中的从类与关联关系中的主类对应的表之间形成关联关系的字段名称,通常用于关联关系中的从类的关联字段不是自己的主键的情况。以演示场景中 Book 和 BookExtend 实体的关系为例:BookExtend 表中默认使用 Id 字段和 Book 类的某个字段进行关联,但如果实际情况下 BookExtends 表需要使用“myID“字段和 Book 表进行关联,我们就可以设置 javax.persistence.JoinColumn
注释的属性值为“myID”。
javax.persistence.JoinColumn 用法举例
public class Book { // 其它内容… /* * 使用 OneToOne 注释表示该属性和 Book 类形成一对一关系,OneToOne * 注释的 option 属性设为 True 表示该对象可以不存在,cascade 属性 * 设置为 CascadeType.ALL,表示 Book 和 BookExtend 对象级联新建、 更新、删除、刷新 */ @OneToOne(optional = true, cascade = CascadeType.ALL) /* * 使用 JoinColumn 注释设置两个对象对应数据库表之间的关联字段 * name 属性指定关联关系中主类对应表中参与关联关系的字段名称, * referencedColumnNam 属性指定关联关系中从类对应表中参与关 * 联关系的字段名称, */ @JoinColumn(name = "beID", referencedColumnName = "myID") public BookExtend bookExtend; } |
根据模拟场景的需求,结合我们前面学习到的描述实体之间一对一关联关系的知识,我们可以采用如下设计:
- Book 类和 BookExtend 之间存在一对一关联关系;
- Book、BookExtend 对应的表的主键字段由 MySQL 自动生成;
- Book 表中参与关联关系的字段名为“beID“;
- BookExtend 表中参与关联关系的字段使用默认字段“ID”;
- Book 类和 BookExtend 类之间存在全部级联关系;
- 不是每一个 Book 对象都需要有对应的 BookExtend 对象。
根据这样的设计,我们可以开始编写实体 Book 和 BookExtend 对应的持久化类代码,下面是作者编写的两个实体类的全部代码,大家可以参考代码中加入的大量注释学习如何使用注释来描述实体和实体之间的一对一关联关系。
Book 类
1. package org.vivianj.openjpa.beans; 2. 3. import javax.persistence.Basic; 4. import javax.persistence.CascadeType; 5. import javax.persistence.Column; 6. import javax.persistence.Entity; 7. import javax.persistence.GeneratedValue; 8. import javax.persistence.GenerationType; 9. import javax.persistence.Id; 10. import javax.persistence.Inheritance; 11. import javax.persistence.InheritanceType; 12. import javax.persistence.JoinColumn; 13. import javax.persistence.OneToOne; 14. 15. /** 16. * Book 用于表征系统中的书籍对象,它有三个属性 id - 书籍编号, * 书籍编号将由 MySQL 数据库自动生成 name - 书名 bookExtend – 17. * 书的扩展信息,和 BookExtend 是一对一(OneToOne)关系 18. */ 19. 20. @Entity(name = "Book") 21. public class Book { 22. /* Id 注释表示该字段是标识字段 */ 23. @Id 24. /* 25. * GeneratedValue 注释定义了该标识字段的产生方式,我们的演示系统中 26. * id 由 MySQL 数据库字段自动生成,因此选择 GenerationType.IDENTITY 27. */ 28. @GeneratedValue(strategy = GenerationType.IDENTITY) 29. /* 30. * Column 注释的 name 属性定义了该类属性对应的数据字段的名称, * 为了最大限度保持系统和数据库之前的独立性,建议使用大写字符 31. */ 32. @Column(name = "ID") 33. public int id; 34. 35. /* Basic 注释表示该属性是基本属性 */ 36. @Basic 37. /* 38. * Column 注释的 name 属性定义了该类属性对应的数据字段的名称, * 为了最大限度保持系统和数据库之前的独立性,建议使用大写字符 39. */ 40. @Column(name = "NAME") 41. public String name = null; 42. 43. /* 44. * 使用 OneToOne 注释表示该属性和 Book 类形成一对一关系,OneToOne 45. * 注释的 option 属性设为 True 表示该对象可以不存在,cascade 属性 46. * 设置为 CascadeType.ALL,表示 Book 和 BookExtend 对象级联新建、 更新、删除、刷新 47. */ 48. @OneToOne(optional = true, cascade = CascadeType.ALL) 49. /* 使用 JoinColumn 注释设置两个对象对应数据库表之间的关联字段 */ 50. @JoinColumn(name = "extendID") 51. public BookExtend bookExtend; 52. } |
BookExtend 类
1. package org.vivianj.openjpa.beans; 2. 3. import javax.persistence.Basic; 4. import javax.persistence.Column; 5. import javax.persistence.Entity; 6. import javax.persistence.GeneratedValue; 7. import javax.persistence.GenerationType; 8. import javax.persistence.Id; 9. import javax.persistence.Inheritance; 10. import javax.persistence.InheritanceType; 11. 12. /** 13. * BookExtend 用于表征系统中书的扩展信息,它有两个属性: * id - 扩展信息编号,扩展信息编号将由 MySQL 数据库自动生成 14. * name -书的前言信息 15. */ 16. @Entity 17. public class BookExtend { 18. /* Id 注释表示该字段是标识字段 */ 19. @Id 20. /* 21. * GeneratedValue 注释定义了该标识字段的产生方式,我们的演示系统中 22. * id 由 MySQL 数据库字段自动生成,因此选择 GenerationType.IDENTITY 23. */ 24. @GeneratedValue(strategy = GenerationType.IDENTITY) 25. /* 26. * Column 注释的 name 属性定义了该类属性对应的数据字段的名称, * 为了最大限度保持系统和数据库之前的独立性,建议使用大写字符 27. */ 28. @Column(name = "ID") 29. public int id; 30. 31. /* Basic 注释表示该属性是基本属性 */ 32. @Basic 33. /* 34. * Column 注释的 name 属性定义了该类属性对应的数据字段的名称, * 为了最大限度保持系统和数据库之前的独立性,建议使用大写字符 35. */ 36. @Column(name = "NAME") 37. public String name = null; 38. } |
上面的代码中,我们已经准备好了符合要求的持久化类,下面我们看看 OpenJPA 中如何调用这两个类完成 Book 类和 BookExtend 类的创建、修改、删除工作。
由于篇幅的关系,这些没有讲述如何编译、加强这些类并且准备相应的配置文件来完成整个项目开发环境的建立,这部分的内容请参考另外一篇文章《OpenJPA:符合 EJB3 规范的持久层框架》。
级联新建对象
下面的这段代码演示了只需要调用 Book 类的 persist 方法就同时持久化 Book 类对象和 BookExtend 类对象的情况。请注意其中用粗体标识出的部分。
/* 获得 EJB 的实体管理器 */ EntityManagerFactory emf = Persistence.createEntityManagerFactory(null); EntityManager em = emf.createEntityManager(PersistenceContextType.EXTENDED); /* 开始事务 */ em.getTransaction().begin(); /* 创建新的 BookExtend 对象 */ BookExtend bookExtend = new BookExtend(); /* 设置对象属性 */ bookExtend.name = "前言 本书重点说明了..."; /* 创建新的 Book 对象 */ Book book = new Book(); /* 设置 Book 对象的 name 属性 */ book.name = "<<Web Services实践>>"; /* 建立对象之间的关系 */ book.bookExtend = bookExtend; /* 持久化对象,只需要持久化 Book 对象,不需要单独持久化 bookExtend 对象 */ em.persist(book); /* 结束事务 */ em.getTransaction().commit(); em.close(); emf.close(); |
产生的 SQL 语句
下面的这段 SQL 语句是运行上面的代码时 OpenJPA 自动生成的,我们可以从中看到 OpenJPA 级联新建对象时的处理过程:
-- 创建 Book 实体对应的数据库表 -- CREATE TABLE Book (ID INTEGER NOT NULL AUTO_INCREMENT, NME VARCHAR(255), extendID INTEGER, PRIMARY KEY (ID)); -- 创建 BookExtend 实体对应数据库表 -- CREATE TABLE BookExtend (ID INTEGER NOT NULL AUTO_INCREMET, NAME VARCHAR(255), PRIMARY KEY (ID)) ; -- 将 Book 实体对象插入数据库中 -- INSERT INTO Book (NAME) VALUES (‘<<Web Services实践>>’) -- 获取 Book 实体对象的编号 -- SELECT LAST_INSERT_ID(); -- 将 BookExtend 实体对象插入数据库中 -- INSERT INTO BookExtend (NAME) VALUES (‘前言 本书重点说明了...’) ; --获取 BookExtend 实体对象的编号 -- SELECT LAST_INSERT_ID(); -- 将 BookExtend 实体对象的编号更新到Book表中形成关联关系 -- UPDATE Book SET extendID = 1 WHERE ID = 1; |
级联更新对象状态
下面的这段代码演示了只需要调用 Book 类的 merge 方法就同时更新 Book 类对象和 BookExtend 类对象状态的情况。请注意其中用粗体标识出的部分。
/* 获得 EJB 的实体管理器 */ EntityManagerFactory emf = Persistence.createEntityManagerFactory(null); EntityManager em = emf.createEntityManager(PersistenceContextType.EXTENDED); /* 开始事务 */ em.getTransaction().begin(); /* 创建新的 Book 对象 */ Book book = new Book(); /* 设置 Book 对象的 id 属性 */ book.id= 1; book.name = “OpenJPA入门”; /* 创建新的 BookExtend 对象 */ BookExtend bookExtend = new BookExtend(); /* 设置对象属性 */ bookExtend.id=1; bookExtend.name = "OpenJPA开发EJB3.0应用 ..."; /* 建立对象之间的关系 */ book.bookExtend = bookExtend; /* 持久化对象,只需要调用 Book 对象的 merge 方法,不需要单独处理 bookExtend 对象 */ em.merge(book); /* 结束事务 */ em.getTransaction().commit(); em.close(); emf.close(); |
级联删除对象
下面的这段代码演示了只需要通过 Query 对象,就可以在删除 Book 类的同时,删除它对应的 BookExtend 实体对象的情况。请注意其中用粗体标识出的部分。
/* 获得 EJB 的实体管理器 */ EntityManagerFactory emf = Persistence.createEntityManagerFactory(null); EntityManager em = emf.createEntityManager(PersistenceContextType.EXTENDED); /* 开始事务 */ em.getTransaction().begin(); /* 使用查询删除对象,可以不必将对象加入到内存中,提高效率 */ Query q = entityManager.createQuery("delete from Book c WHERE c.id=:id"); int id = book.id; /* 设置被删除 Book 对象的主键值 */ q.setParameter("id", id); /* 当方法被调用时,Book 对象对应的 BookExtend 对象会同时被删除 */ q.executeUpdate(); /* 结束事务 */ em.getTransaction().commit(); em.close(); emf.close(); |
在上面的文章中我们学习了如何在 OpenJPA 中通过 javax.persistence.OneToOne 注释和 javax.persistence.JoinColumn 注释实现实体之间的一对一关联关系。在企业应用中,除了一对一关联关系,实体之间还可能存在一对多、多对一、多对多等关联关系,不过在 OpenJPA 容器中,这些实体之间关联关系的实现都大同小异,只是需要开发者选择使用不同的注释。
开发者用来描述实体之间一对多关联关系的注释是 javax.persistence.OneToMany 注释,用来描述实体之间多对一关联关系的注释是 javax.persistence.OneToMany 注释,用来描述实体之间多对多关联关系的注释是 javax.persistence.ManyToMany 注释。这三个注释都支持 targetEntity、mappedBy、cascade 和 fetch 这四个属性,这些属性的具体含义和 OneToOne 注释注释的同名属性一一对应,请大家参考前面章节中的内容。
javax.persistence.OneToMany、javax.persistence.OneToMany、javax.persistence.ManyToMany 这三个注释都可以和 javax.persistence.JoinColumns 注释一起使用,javax.persistence.JoinColumns 注释的作用是为一对多、多对一、多对多关联关系在数据库中的体现提供更多细节描述。javax.persistence.JoinColumns 注释中可以包含多个 javax.persistence.JoinColumn 注释的内容,javax.persistence.JoinColumn 注释的属性请参考本文前面部分的描述。
发表评论
文章已被作者锁定,不允许评论。
相关推荐
2. **实体Bean的简化**:EJB 3.0引入了JPA(Java Persistence API),它是对ORM(Object-Relational Mapping)的标准化。开发者可以使用@Entity、@Table、@Id等注解来定义实体类,实现数据持久化,而不再需要编写...
EJB(Enterprise JavaBeans)3.0是Java企业级应用开发的一个重要标准,它定义了如何在Java EE(Java Platform, Enterprise Edition)环境中构建可复用的、组件化的服务器端应用程序。EJB 3.0的发布极大地简化了EJB的...
JPA允许开发者使用实体类和注解来定义数据模型,并提供了查询语言(JPQL)来操作数据库,这使得EJB应用程序的数据访问层变得更加简洁和高效。 #### 无接口视图 在早期版本的EJB中,会话Bean必须实现特定的本地或...
通过这些图文教程,你可以逐步掌握EJB 3.0的基本要素,包括实体bean、消息驱动bean和session bean的开发和使用。在实践中,结合IDE(如Eclipse或NetBeans)和应用服务器(如GlassFish或JBoss),你将能更好地理解和...
EJB3.0是EJB规范的一个重要版本,它在EJB2.x的基础上进行了大量简化,提高了开发效率,并引入了注解驱动的开发方式,使得EJB更易于理解和使用。 在EJB3.0中,主要包含以下关键知识点: 1. **实体Bean(Entity ...
你将找到一个完整的示例,涵盖了上述所有步骤,包括具体的代码片段和执行过程,这对于初学者来说是一个很好的起点,可以快速理解并实践EJB 3.0在JBOSS和MyEclipse环境下的开发流程。通过这个初体验,你可以了解到...
EJB 3.0是EJB规范的一个重要版本,它在EJB 2.x的基础上进行了大幅度的简化,提升了开发效率,降低了学习曲线,使得Java EE应用程序的开发变得更加直观和高效。 **EJB 3.0 的核心特性** 1. **注解驱动**:EJB 3.0...
《Jbuilder2007开发EJB3.0》这一主题涵盖了Java企业级应用开发的重要技术,主要包括EJB(Enterprise JavaBeans)3.0的三种主要类型:Message Driven Bean、Session Bean和Entity Bean,以及如何利用Jbuilder2007这一...
EJB 3.0是EJB规范的一个重大革新,它极大地简化了开发过程,降低了学习曲线,使得更多开发者能够轻松地使用EJB进行企业级开发。 《EJB 3.0入门经典》是一本专门介绍EJB 3.0的著作,由黎活明编著。这本书深入浅出地...
EJB 3.0支持异步方法调用,通过`@Asynchronous`注解,可以在不阻塞调用线程的情况下执行长时间运行的任务,提高系统响应速度。 **8. 面向服务的架构(Service-Oriented Architecture,SOA)** EJB 3.0的设计理念...
这些变化使得EJB更加易于使用和集成,同时也保持了其作为企业级应用开发框架的核心价值。对于开发者而言,了解这些变化不仅有助于更好地掌握EJB的技术细节,还能帮助他们在实际项目中做出更合适的选择。
EJB(Enterprise JavaBeans)是Java EE平台的核心组件之一,用于构建可扩展、安全和事务处理的服务器端应用...这份开发文档将帮助新手快速理解并掌握EJB3.0的核心概念和技术,从而能高效地开发出可靠的企业级应用程序。
总结来说,EJB 3.0规范为Java EE平台带来了一次重大革新,通过注解、依赖注入和简化API,降低了开发企业级应用的复杂度。ejb-3_0-fr-spec-ejbcore.pdf、ejb-3_0-fr-spec-persistence.pdf和ejb-3_0-fr-spec-...
2. **实体bean的POJO化(Plain Old Java Objects)**:EJB 3.0引入了基于Java Persistence API(JPA)的实体bean,允许使用普通的Java类作为数据库对象,无需继承特定的EJB基类或实现接口,提高了代码的可重用性。...
**EJB3.0实例教程**是一份详细指导开发者如何使用Enterprise JavaBeans 3.0(EJB3.0)技术进行企业级应用开发的电子文档。EJB3.0是Java EE(Java Platform, Enterprise Edition)规范的一部分,旨在简化企业级组件的...
EJB(Enterprise JavaBeans)是Java EE平台的核心组件之一,主要负责实现企业级应用的业务逻辑。EJB 3.0是EJB规范的一个重要...对于学习者来说,这是一个宝贵的资源,可以帮助他们掌握企业级Java应用开发的关键技能。
**企业级JavaBeans (EJB) ...这些知识点涵盖了EJB 3.0规范的各个方面,对于理解Java EE平台的企业级应用开发至关重要。通过深入学习EJB 3.0规范,开发者能够更好地利用Java EE环境构建高效、可扩展的企业级解决方案。
EJB(Enterprise JavaBeans)是Java企业级应用开发的核心组件模型,主要用于构建可复用的、分布式的、事务处理的企业...通过深入学习这些文档,开发者可以全面掌握EJB3.0规范,有效提升在Java企业级应用开发中的技能。
《EJB3.0持久化开发手册》将详细讲解JPA的使用,包括实体管理器(EntityManager)、实体管理工厂(EntityManagerFactory)以及如何处理持久化操作,如保存(persist)、删除(remove)、查询(find)等。...
- **轻量级容器**:EJB 3.0支持轻量级容器,这意味着开发者可以在非Java EE服务器环境下运行EJB组件,从而提高了灵活性。 - **生命周期管理**:EJB 3.0提供了更强大的生命周期管理功能,包括自动管理的会话Bean和...