MyEclipse6Java开发中文教程 第十三章开发JPA应用 第十三章开发JPA应用 131介绍 1311JPA简介 312 MyEclipse提供的JPA开发功能 13.13JPA的代码结构和相关理论知识 1313.1JPA代码结构 13.1.32配置文件 persistence. xml 12244446 13133实体类及标注 13134使用 EntityManager来管理实体 13 13135 Query对象 13136JPA查询语言( JPA QL)简介 13.137回调方法 132准备工作 133创建 JPAHello项目 13.3.1创建表格 1332创建 HelloJPA Java Project 1333添加 JPA Capabilities到现有项目. 1334使用JPA配置文件编辑器修改文件 23358 133.5使用反向工程快速生成JPA实体类和DAO 13.36调整生成的实体类标注 1337编写测试代码 134JPA工具高级部分 134.1 MyEclipse Java Persistence Perspective透视图…… 1342 JPA Details视图 1343JPA代码编辑辅助 1344生成一对多等复杂映射代码 13.5 Spring整合JPA开发… 58 13.51添加 Spring开发功能 1352从数据库反向工程生成实体和 Spring D 1353编写并运行测试代码 13531支持标注事务时的调试代码 13532不支持标注事务时的调试代码 7777 136小结 137参考资料 刘长炯著
MyEclipse 6 Java 开发中文教程 1 刘长炯著 第十三章 开发 JPA 应用 第十三章 开发JPA应用 ..................................................................................................... 1 13.1 介绍................................................................................................................... 2 13.1.1 JPA 简介.................................................................................................. 2 13.1.2 MyEclipse提供的JPA开发功能 ................................................................. 4 13.1.3 JPA的代码结构和相关理论知识................................................................ 4 13.1.3.1 JPA代码结构.................................................................................. 4 13.1.3.2 配置文件persistence.xml............................................................... 4 13.1.3.3 实体类及标注 ................................................................................ 6 13.1.3.4 使用EntityManager来管理实体.................................................... 13 13.1.3.5 Query对象.................................................................................... 18 13.1.3.6 JPA 查询语言(JPA QL)简介 .................................................... 19 13.1.3.7 回调方法 ..................................................................................... 21 13.2 准备工作.......................................................................................................... 22 13.3 创建JPAHello项目 ............................................................................................ 22 13.3.1 创建表格................................................................................................. 22 13.3.2 创建 HelloJPA Java Project ................................................................... 23 13.3.3 添加 JPA Capabilities 到现有项目......................................................... 23 13.3.4 使用JPA配置文件编辑器修改文件 ......................................................... 25 13.3.5 使用反向工程快速生成JPA实体类和DAO.............................................. 28 13.3.6 调整生成的实体类标注 .......................................................................... 42 13.3.7 编写测试代码 ........................................................................................ 43 13.4 JPA 工具高级部分............................................................................................ 46 13.4.1 MyEclipse Java Persistence Perspective透视图.................................... 46 13.4.2 JPA Details 视图.................................................................................... 47 13.4.3 JPA 代码编辑辅助 ................................................................................. 49 13.4.4 生成一对多等复杂映射代码................................................................... 49 13.5 Spring整合JPA开发.......................................................................................... 58 13.5.1 添加Spring开发功能 .............................................................................. 59 13.5.2 从数据库反向工程生成实体和Spring DAO............................................. 60 13.5.3 编写并运行测试代码.............................................................................. 71 13.5.3.1 支持标注事务时的调试代码......................................................... 71 13.5.3.2 不支持标注事务时的调试代码 ..................................................... 73 13.6 小结................................................................................................................. 74 13.7 参考资料.......................................................................................................... 75
MyEclipse6Java开发中文教程 在本章我们将会介绍JPA的开发,一共包括三部分内容:独立运行的JPA应用开发 Spring整合JPA开发;EJB査询语言开发。其实关于JPA还有一部分是基于EJB容器环境 的开发,那一部分内容我们将会放到后面的EJB开发一章来介绍。由于 MyEclipse6对JPA 开发提供了很方便的支持,因此我们的内容主要就集中在如何使用 MyEclipse进行快速开发 这个话题上。 131介绍 1311JPA简介 前面我们已经介绍了 Hibernate,但是实际在开发中所存在的这种进行数据库开发的 ORM框架不止一种,包括JDO,Bats, TopLink,KODo, OpenJPA等等多种开源的和 商业的产品。那么这有什么问题呢?假设现在我们的项目是用 Hibernate开发的,运行于 Oracle数据库之上,然而上线运行一段时间后,发现有一些性能上的问题,而这时候我们 想找人来做技术支持,希望它来帮我们解决这些问题,因为开发人员并不是个个都能读懂 Hibernate的源码然后找到问题所在的。这是第一种可能:客户(通常是有钱的大客户)希 望能在遇到问题时有人提供商业的技术支持和顾问服务。第匚种可能: Oracle公司推出了 专用于对 Oracle数据库特别优化过的ORM产品,名为 TopLink,然而很不幸,虽然它能解 决我们的问题,但是,因为 Hibernate的类库的包结构和 TopLink的相差太远,一个是以 org. hibernate开头的,另一个却是以 com. oracle开头的,更要命的是,两者之间的类库根 本就没有相似之处!那我们的项目并不能通过简单的将代码的包换一下,就能迁移成功,下 载岂不是要所有涉及 Hibernate的地方都得重写!换句话说,当我们使用 Hibernate或者其 它ORM框架开发时,我们的代码已经被绑死了!虽然代码是和数据库无关的,然而数据库 访问的Java代码却是死死的和某种框架绑定在一起了 针对这种情况,即Java的ORM框架再次出现诸侯割据,烽烟混战的局面,而Java 程序员却被迫只能选择一种框架,而无法在项目开发之后变更框架的情况,Sun公司- Java和 Java ee规范的领导者,就像在当年JDBC规范出现之前所作的那样,在 Java ee 5的规范制定中,特地提出了JPA( Java Persistence AP)这一新的ORM规范,意图结束这 种混乱的局面,并革命性的使用标注作为开发模式,很大程度上减少了开发人员的负担:包 括背诵包和类的负担以及辛辛苦苦的编写XML配置文件来进行实体映射的负担,并使用 POJO的方式进行开发。和之前的JDBC一样,在充分吸收现有ORM框架的基础上,得到 了一个易于使用、伸缩性强的ORM规范,它不仅仅提供基础的映射功能,还使这些JPA 的框架提供者能够提供高级功能。Sun引入新的 JPA ORM规范出于两个原因:其一,简化 现有 Java ee和 Java se应用的对象持久化的开发工作;其二,Sun希望整合对ORM技 术,实现天下归 JPA由EJB30软件专家组开发( Hibernate的发明者 Gavin King老师也加入其中), 作为JSR220实现的一部分。但它不局限于EJB30,你可以在Web应用、甚至桌面应用 中使用。JPA的宗旨是为POJO提供持久化标准规范,由此可见,经过这几年的实践探索, 能够脱离容器独立运行,方便开发和测试的理念已经深入人心了。目前 Hibernate3(确切 说是配合 Hibernate Entity Manager)、 TopLink、KODO以及 OpenJPA都提供了JPA的实 现,甚至还包括一些以前的JDO产品。而截至目前,所有支持 Java ee5的服务器(需要 通过Sun的认证才行),都支持JPA规范,这些服务器包括: Apache Geronimo-21(开源 服务器), WebLogic Server v10.0(商业,BEA公司产品,现并入 Oracle), IBM WASCE 2 刘长炯著
MyEclipse 6 Java 开发中文教程 2 刘长炯著 在本章我们将会介绍 JPA 的开发,一共包括三部分内容:独立运行的 JPA 应用开发; Spring 整合 JPA 开发;EJB 查询语言开发。其实关于 JPA 还有一部分是基于 EJB 容器环境 的开发,那一部分内容我们将会放到后面的 EJB 开发一章来介绍。由于 MyEclipse 6 对 JPA 开发提供了很方便的支持,因此我们的内容主要就集中在如何使用 MyEclipse 进行快速开发 这个话题上。 13.1 介绍 13.1.1 JPA 简介 前面我们已经介绍了 Hibernate,但是实际在开发中所存在的这种进行数据库开发的 ORM 框架不止一种,包括 JDO,iBatis,TopLink,KODO,OpenJPA 等等多种开源的和 商业的产品。那么这有什么问题呢?假设现在我们的项目是用 Hibernate 开发的,运行于 Oracle 数据库之上,然而上线运行一段时间后,发现有一些性能上的问题,而这时候我们 想找人来做技术支持,希望它来帮我们解决这些问题,因为开发人员并不是个个都能读懂 Hibernate 的源码然后找到问题所在的。这是第一种可能:客户(通常是有钱的大客户)希 望能在遇到问题时有人提供商业的技术支持和顾问服务。第二种可能:Oracle 公司推出了 专用于对 Oracle 数据库特别优化过的 ORM 产品,名为 TopLink,然而很不幸,虽然它能解 决我们的问题,但是,因为 Hibernate 的类库的包结构和 TopLink 的相差太远,一个是以 org.hibernate 开头的,另一个却是以 com.oracle 开头的,更要命的是,两者之间的类库根 本就没有相似之处!那我们的项目并不能通过简单的将代码的包换一下,就能迁移成功,下 载岂不是要所有涉及 Hibernate 的地方都得重写!换句话说,当我们使用 Hibernate 或者其 它 ORM 框架开发时,我们的代码已经被绑死了!虽然代码是和数据库无关的,然而数据库 访问的 Java 代码却是死死的和某种框架绑定在一起了。 针对这种情况,即 Java 的 ORM 框架再次出现诸侯割据,烽烟混战的局面,而 Java 程序员却被迫只能选择一种框架,而无法在项目开发之后变更框架的情况,Sun 公司―― Java 和 Java EE 规范的领导者,就像在当年 JDBC 规范出现之前所作的那样,在 Java EE 5 的规范制定中,特地提出了 JPA(Java Persistence API)这一新的 ORM 规范,意图结束这 种混乱的局面,并革命性的使用标注作为开发模式,很大程度上减少了开发人员的负担:包 括背诵包和类的负担以及辛辛苦苦的编写 XML 配置文件来进行实体映射的负担,并使用 POJO 的方式进行开发。和之前的 JDBC 一样,在充分吸收现有 ORM 框架的基础上,得到 了一个易于使用、伸缩性强的 ORM 规范,它不仅仅提供基础的映射功能,还使这些 JPA 的框架提供者能够提供高级功能。Sun 引入新的 JPA ORM 规范出于两个原因:其一,简化 现有 Java EE 和 Java SE 应用的对象持久化的开发工作;其二,Sun 希望整合对 ORM 技 术,实现天下归一。 JPA 由 EJB 3.0 软件专家组开发(Hibernate 的发明者 Gavin King 老师也加入其中), 作为 JSR-220 实现的一部分。但它不局限于 EJB 3.0,你可以在 Web 应用、甚至桌面应用 中使用。JPA 的宗旨是为 POJO 提供持久化标准规范,由此可见,经过这几年的实践探索, 能够脱离容器独立运行,方便开发和测试的理念已经深入人心了。目前 Hibernate 3(确切 说是配合 Hibernate Entity Manager)、TopLink、KODO 以及 OpenJPA 都提供了 JPA 的实 现,甚至还包括一些以前的 JDO 产品。而截至目前,所有支持 Java EE 5 的服务器(需要 通过 Sun 的认证才行),都支持 JPA 规范,这些服务器包括:Apache Geronimo-2.1(开源 服务器), WebLogic Server v10.0(商业,BEA 公司产品,现并入 Oracle),IBM WASCE
MyEclipse6Jaa开发中文教程 20(商业服务器), Apusic Application Server(v50)(国产,金蝶中间件,商业), Oracle Application Server11(商业), SAP NetWeaver7.1(商业), Sun Java System Application erver Platform Edition9(商业,单免费使用), Tmax Soft JEUS6(不详), GlassFish Application Server(开源软件)。在这里提一下 JBoss,最新的4和5都支持JPA,然而, 它却没通过 Java ee5的认证,它的JPA是基于 Hibernate实现的,因为 Hibernate的作者 现在加入了 JBoss公司(确切的说是 Redhat公司,它收购了 JBoss)。 JPA的总体思想和现有 Hibernate、 TopLink,JDO等ORM框架大体一致。总的来说 JPA包括以下3方面的技术: ●ORM映射元数据,JPA支持XML和JDK5.0注解两种元数据的形式,元数据描述对 象和表之间的映射关系,框架据此将实体对象持久化到数据库表中; ●JPA的AP,用来操作实体对象,执行CRUD操作,框架在后台替我们完成所有的事 情,开发者从繁琐的JDBC和SQL代码中解脱出来。 查询语言,这是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询 语言查询数据,避免程序的SQL语句紧密耦合, 最后,需要说明的是,JPA只是一个规范,就好像规定所有的手机都必须能打电话一样, 但是,JPA本身不是电话,我们能说手机提供了通话功能,但是我们不能说通话功能就是 个手机。很显然手机提供了通话功能之外的其它很多附加的能力,同样的,JPA的实现者也 可以根据自己的情况,提供基本功能之外的附加功能。其系统结构图如图13.1所示。这样, 其实JPA一共分成了两部分,一部分就是JPA规范,它是套编程的接口(AP,供开发 人员来进行调用;另一部分就是JPA规范的实现者,一般情况下他们在现有ORM框架的 基础上,再编写一套基于JPA的实现类,当然这时候他们也会根据实际情况进行一些增强 的功能。我们程序员,则处于JPA规范之般来说不需要特别的熟悉底层ORM的详 细信息,当然如果能有所了解就更好了。ORM框架则生成SQL语句,调用JDBC,通过 JDBC再去操作最终的数据库。 JPA规范 程序员的实体类和DAO ORM框架+JPA实现类+增强 业务层和表示层 JDBC 数据库 图13.1JPA的系统结构图 目前支持JPA的开发工具(DE)是比较多的,包括 MyEclipse6, Eclipse IDE for Java EE Developers(最新的33)版本, Netbeans556, BEA Workshop10, Oracle JDeveloper 等等,其中不乏一些免费的选择。其中支持最标准的当属免费的 Netbeans6了,不光能生 成JPA代码,还能附带生成增删改查的JSF页面,以及支持最新的Swng桌面应用框架, 支持Swng应用中直接通过JPA修改底层数据。 刘长炯著
MyEclipse 6 Java 开发中文教程 3 刘长炯著 2.0(商业服务器),Apusic Application Server (v5.0)(国产,金蝶中间件,商业), Oracle Application Server 11 (商业),SAP NetWeaver 7.1(商业),Sun Java System Application Server Platform Edition 9(商业,单免费使用),TmaxSoft JEUS 6(不详),GlassFish Application Server(开源软件)。在这里提一下 JBoss,最新的 4 和 5 都支持 JPA,然而, 它却没通过 Java EE 5 的认证,它的 JPA 是基于 Hibernate 实现的,因为 Hibernate 的作者 现在加入了 JBoss 公司(确切的说是 RedHat 公司,它收购了 JBoss)。 JPA 的总体思想和现有 Hibernate、TopLink,JDO 等 ORM 框架大体一致。总的来说, JPA 包括以下 3 方面的技术: z ORM 映射元数据,JPA 支持 XML 和 JDK 5.0 注解两种元数据的形式,元数据描述对 象和表之间的映射关系,框架据此将实体对象持久化到数据库表中; z JPA 的 API,用来操作实体对象,执行 CRUD 操作,框架在后台替我们完成所有的事 情,开发者从繁琐的 JDBC 和 SQL 代码中解脱出来。 z 查询语言,这是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询 语言查询数据,避免程序的 SQL 语句紧密耦合。 最后,需要说明的是,JPA 只是一个规范,就好像规定所有的手机都必须能打电话一样, 但是,JPA 本身不是电话,我们能说手机提供了通话功能,但是我们不能说通话功能就是一 个手机。很显然手机提供了通话功能之外的其它很多附加的能力,同样的,JPA 的实现者也 可以根据自己的情况,提供基本功能之外的附加功能。其系统结构图如图 13.1 所示。这样, 其实 JPA 一共分成了两部分,一部分就是 JPA 规范,它是一套编程的接口(API),供开发 人员来进行调用;另一部分就是 JPA 规范的实现者,一般情况下他们在现有 ORM 框架的 基础上,再编写一套基于 JPA 的实现类,当然这时候他们也会根据实际情况进行一些增强 的功能。我们程序员,则处于 JPA 规范之上,一般来说不需要特别的熟悉底层 ORM 的详 细信息,当然如果能有所了解就更好了。ORM 框架则生成 SQL 语句,调用 JDBC,通过 JDBC 再去操作最终的数据库。 图 13.1 JPA 的系统结构图 目前支持 JPA 的开发工具(IDE)是比较多的,包括 MyEclipse 6,Eclipse IDE for Java EE Developers(最新的 3.3)版本,Netbeans 5.5/6,BEA Workshop 10,Oracle JDeveloper 等等,其中不乏一些免费的选择。其中支持最标准的当属免费的 Netbeans 6 了,不光能生 成 JPA 代码,还能附带生成增删改查的 JSF 页面,以及支持最新的 Swing 桌面应用框架, 支持 Swing 应用中直接通过 JPA 修改底层数据
MyEclipse6Java开发中文教程 1312 My Eclipse提供的JPA开发功能 MyEclipse6对JPA的开发提供了全面的支持,包括:添加、修改JPA的实现类库的 功能;从数据库反向工程直接生成实体类和DAO的功能;增强的JPA实体信息编辑器;实 体标注编写自动提示功能;实体信息验证:内置 Spring+JPA整合向导和 Spring DAO代码 生成功能等等。 1313JPA的代码结构和相关理论知识 注意:本节内容读者可以放在做完练习之后再来阅读,或者是碰到不熟悉的写法时再来 阅读,会比较好一些。因为实际情况来说,每个框架都有成千上万的知识点,而对于开发人 员来说,一般掌握最常用的部分即可。当然也可以先阅读,后练习。本节内容相对多而且有 些,因为JPA的应用越来越广泛,而 My Eclipse6实际上是能够生成绝大多数的代码(甚 至包括一对多等映射关系),所以我们提供这些内容主要是处于帮助大家理解并修改代码的 目的。而JPA还支持纯ⅩML配置非标注的开发方式,因为比较少用我们就先不做介绍了。 13131JPA代码结构 由于 Hibernate自动生成的代码封装的比较厉害,可能不太便于初学者理解。由图13.1 我们可以看到,一个JPA的项目离不开途中所说的几个部分。首先当然是要有数据库服务 器了,其次,需要JDBC的驱动程序,接着,是JPA的实现类和JPA本身的包,最后,我 们才能开发JPA的应用 其源代码目录结构一般如下 OMETA-INF/D persistence.xml 目 Entity 1. java 自Ent! DAO. java 开发过程一般是:JPA配置文件声明持久化单元睁编写带标注的实体类睁编写DAO 131.32配置文件 persistence. xml 首先第一个,就是JPA的配置文件 persistence.xm,一般位于目录 META-INF下,注 意大小写不能写错了。这个文件的结构如图132所示 刘长炯著
MyEclipse 6 Java 开发中文教程 4 刘长炯著 13.1.2 MyEclipse 提供的 JPA 开发功能 MyEclipse 6 对 JPA 的开发提供了全面的支持,包括:添加、修改 JPA 的实现类库的 功能;从数据库反向工程直接生成实体类和 DAO 的功能;增强的 JPA 实体信息编辑器;实 体标注编写自动提示功能;实体信息验证;内置 Spring + JPA 整合向导和 Spring DAO 代码 生成功能等等。 13.1.3 JPA 的代码结构和相关理论知识 注意:本节内容读者可以放在做完练习之后再来阅读,或者是碰到不熟悉的写法时再来 阅读,会比较好一些。因为实际情况来说,每个框架都有成千上万的知识点,而对于开发人 员来说,一般掌握最常用的部分即可。当然也可以先阅读,后练习。本节内容相对多而且有 些,因为 JPA 的应用越来越广泛,而 MyEclipse 6 实际上是能够生成绝大多数的代码(甚 至包括一对多等映射关系),所以我们提供这些内容主要是处于帮助大家理解并修改代码的 目的。而 JPA 还支持纯 XML 配置非标注的开发方式,因为比较少用我们就先不做介绍了。 13.1.3.1 JPA 代码结构 由于 Hibernate 自动生成的代码封装的比较厉害,可能不太便于初学者理解。由图 13.1 我们可以看到,一个 JPA 的项目离不开途中所说的几个部分。首先当然是要有数据库服务 器了,其次,需要 JDBC 的驱动程序,接着,是 JPA 的实现类和 JPA 本身的包,最后,我 们才能开发 JPA 的应用。 其源代码目录结构一般如下: META-INF/ persistence.xml Entity1.java EntityDAO.java 开发过程一般是:JPA配置文件声明持久化单元 编写带标注的实体类 编写DAO 类。 13.1.3.2 配置文件 persistence.xml 首先第一个,就是 JPA 的配置文件 persistence.xml,一般位于目录 META-INF 下,注 意大小写不能写错了。这个文件的结构如图 13.2 所示
MyEclipse6Java开发中文教程 persistence. xml name="PU1" name="PU2 provider class class class property propert 图132 persistence. xm的结构图 我们列出一份示例的代码清单,如下所示 xminsxsi="http://ww.w3.org/2001/xmlschema-instance Xsi.schemalocation="http./java.sun.com/xmi/ns/persistence httpava.sun.com/xm/ns/persistence/persistence10.xsd"version=1.0> spersistence-unit name= JPADemoPU ction-type=RESOURCE LOCAL oracle toplink essentials. PersistenceProvider /persistence> 这个文件的内容包括一个或者多个持久化单元( persistence unit)的定义,这是和 刘长炯著
MyEclipse 6 Java 开发中文教程 5 刘长炯著 图 13.2 persistence.xml 的结构图 我们列出一份示例的代码清单,如下所示: oracle.toplink.essentials.PersistenceProvider jpadao.Myuser 。 这个文件的内容包括一个或者多个持久化单元(persistence unit)的定义,这是和
MyEclipse6Java开发中文教程 Hibernate不同的,每个持久化单元可以连接到各自的数据库上去。每个持久化单元都有自 己的名字(name属性)和事务类型的定义( transaction-type属性)。名字用来访问数据的 时候根据其取值来创建持久化单元。事务类型则分为 RESOURCE LOCAL(本地事务,适 用于独立运行的或者没有EJB容器的环境)和JTA( Java transaction aPl,Java事务APl 般用于带有EJB容器的环境,或者说运行于服务器中)。如上面代码所示,这份文件中定 义了一个名为 JPADemoPU的持久化单元。 在每个持久化单元的定义里面,还需要定义 provider,它指定了JPA的底层实现类。 前面已经介绍过了,JPA核心是一套接口(规范,本身无功能,只是规定应该有什么样的行 为),它一定要有底层的实现类才可以。这个提供者,就是类似于 Hibernate Entity Manager, KODO, TopLink这样的框架中所提供的核心实现类了。JPA的优点就在于,如果我们想切 换到别的框架上,只需要将这个提供者改掉,相关的属性(见后面 properties)加以修改即 可,别的所有的Java代码都不需要重新变动即可工作。 再接着的内容,就是cass定义,它定义了有哪些类是实体类,可以用来做持久化管理。 在例子中取值为 jiadao. Muse,它是一个普通的 Javabean。因为JPA中的实体类就是普 通的加了些标注的 JavaBean,因此在独立运行的情况下,这样的符合要求的 JavaBean有 成千上亿个之多,如果一个个的去检查这些类是不是加了标注,那将是十分消耗时间的。所 以,在普通模式下,我们通过多个cass标签来列出哪些是需要被作为实体类来处理的,这 样系统的复杂度和启动速度都会大大加快。这就好像是要你找出本市的所有女人一样(咱们 假设不算流动人口),最直接的办法就是把所有女人集中到一个广场里,数一数有多少个是 女人:然而还有一个办法,是通过查国家安全部门的身份证,因为每个人都是有标注的(身 份证信息),可以表明它是男还是女,这样,就很快可以精确的找到北京有多少个人了,很 显然,这些信息是要保存在一个地方的,就像是在这个配置文件中通过cass标签来声明有 多少个类是实体类一样 最后面出现的内容是 properties(复数的属性)标签,它的下面是对应的定义了一个或 者多个的 property(单个属性)子标签。这些属性的名称和取值,一般都是和特定的JPA 实现相关的。不过,一般来说这些属性包括了和数据库相关联的信息,包括驱动,URL,用 户名和密码等等。另外,还可以多设置一些额外的信息例如和特定的ORM实现相关的扩展, 例如 Hibernate可以设置一个属性来打印出每次操作所使用的SQL语句 关于这个文件还有一些别的配置信息,例如∫ta-data- source标记,是用于服务器环境 下的数据源访问的,它指定实体Bean使用的数据源JNDI名称,将在EJB一节进行讨论, 在这里我们暂时还不多做介绍。 13133实体类及标注 开发的第二步,就是编写实体类。和 Hibernate中的实体类一样,它一般是和数据库中 的某个表相对应的。不过在JPA中,实体类可以加入标注,因此它还担负着如何让实体类 中的属性和数据库中的表和字段相对应的责任。简言之就是JPA实体类就是一个普通的带 有属性的 Javabean外加实体标注。在图113中,左侧列出了 My SQL数据库中的test数 据库中的表user及其表的三个字段,而在右侧则列出了实体类及所标注的各个信息和表的 对应关系。 刘长炯著
MyEclipse 6 Java 开发中文教程 6 刘长炯著 Hibernate 不同的,每个持久化单元可以连接到各自的数据库上去。每个持久化单元都有自 己的名字(name 属性)和事务类型的定义(transaction-type 属性)。名字用来访问数据的 时候根据其取值来创建持久化单元。事务类型则分为 RESOURCE_LOCAL(本地事务,适 用于独立运行的或者没有 EJB 容器的环境)和 JTA(Java Transaction API,Java 事务 API, 一般用于带有 EJB 容器的环境,或者说运行于服务器中)。如上面代码所示,这份文件中定 义了一个名为 JPADemoPU 的持久化单元。 在每个持久化单元的定义里面,还需要定义 provider,它指定了 JPA 的底层实现类。 前面已经介绍过了,JPA 核心是一套接口(规范,本身无功能,只是规定应该有什么样的行 为),它一定要有底层的实现类才可以。这个提供者,就是类似于 Hibernate EntityManager, KODO,TopLink 这样的框架中所提供的核心实现类了。JPA 的优点就在于,如果我们想切 换到别的框架上,只需要将这个提供者改掉,相关的属性(见后面 properties)加以修改即 可,别的所有的 Java 代码都不需要重新变动即可工作。 再接着的内容,就是 class 定义,它定义了有哪些类是实体类,可以用来做持久化管理。 在例子中取值为 jpadao.Myuser,它是一个普通的 JavaBean。因为 JPA 中的实体类就是普 通的加了些标注的 JavaBean,因此在独立运行的情况下,这样的符合要求的 JavaBean 有 成千上亿个之多,如果一个个的去检查这些类是不是加了标注,那将是十分消耗时间的。所 以,在普通模式下,我们通过多个 class 标签来列出哪些是需要被作为实体类来处理的,这 样系统的复杂度和启动速度都会大大加快。这就好像是要你找出本市的所有女人一样(咱们 假设不算流动人口),最直接的办法就是把所有女人集中到一个广场里,数一数有多少个是 女人;然而还有一个办法,是通过查国家安全部门的身份证,因为每个人都是有标注的(身 份证信息),可以表明它是男还是女,这样,就很快可以精确的找到北京有多少个人了,很 显然,这些信息是要保存在一个地方的,就像是在这个配置文件中通过 class 标签来声明有 多少个类是实体类一样。 最后面出现的内容是 properties(复数的属性)标签,它的下面是对应的定义了一个或 者多个的 property(单个属性)子标签。这些属性的名称和取值,一般都是和特定的 JPA 实现相关的。不过,一般来说这些属性包括了和数据库相关联的信息,包括驱动,URL,用 户名和密码等等。另外,还可以多设置一些额外的信息例如和特定的 ORM 实现相关的扩展, 例如 Hibernate 可以设置一个属性来打印出每次操作所使用的 SQL 语句。 关于这个文件还有一些别的配置信息,例如 jta-data-source 标记,是用于服务器环境 下的数据源访问的,它指定实体 Bean 使用的数据源 JNDI 名称,将在 EJB 一节进行讨论, 在这里我们暂时还不多做介绍。 13.1.3.3 实体类及标注 开发的第二步,就是编写实体类。和 Hibernate 中的实体类一样,它一般是和数据库中 的某个表相对应的。不过在 JPA 中,实体类可以加入标注,因此它还担负着如何让实体类 中的属性和数据库中的表和字段相对应的责任。简言之就是 JPA 实体类就是一个普通的带 有属性的 JavaBean 外加实体标注。在图 11.3 中,左侧列出了 MySQL 数据库中的 test 数 据库中的表 user 及其表的三个字段,而在右侧则列出了实体类及所标注的各个信息和表的 对应关系
MyEclipse6Java开发中文教程 百 mydatabase 214 eTable(na CL三"test";unic +百 LOCAL TEMPORARY //Fie⊥ds 20 private String- username iwate st 图133实体类标注和数据库表格的对应关系 现在我们来列出一个简单的实体类代码,并加以分析和介绍 package users; lmport javax. persistence.* ENtity (name=User" @Table(name ="myuser", catalog ="test", uniqueConstraints =() public class Myuser implements java. io Serializable i /变量定义 private Integer id private string username private String password public Myuser()i Property acce @Column id", unique true, nullable false, insertable true, updatable aGene alue(strategy=GenerationType IDENTITY) public Integer getId(t return this. id public void setId(Integer id)( this, id id @Column(name unique false, nullable false, insertable true, updatable rue, length 200 public string getUsername()i return this username 刘长炯著
MyEclipse 6 Java 开发中文教程 7 刘长炯著 图 13.3 实体类标注和数据库表格的对应关系 现在我们来列出一个简单的实体类代码,并加以分析和介绍: package users; import javax.persistence.*; @Entity(name="User") @Table(name = "myuser", catalog = "test", uniqueConstraints = {}) public class Myuser implements java.io.Serializable { // 变量定义 private Integer id; private String username; private String password; public Myuser() { } // Property accessors @Id @Column(name = "id", unique = true, nullable = false, insertable = true, updatable = true) @GeneratedValue(strategy=GenerationType.IDENTITY) public Integer getId() { return this.id; } public void setId(Integer id) { this.id = id; } @Column(name = "username", unique = false, nullable = false, insertable = true, updatable = true, length = 200) public String getUsername() { return this.username;
MyEclipse6Java开发中文教程 public void setUsername(String username) I this, username username //省略更多属性定义 首先可能部分读者对Java5的标注还不是特别的熟悉。比较正式的文档都会这样介绍: Annotation提供一种机制,将程序中元素(如类、方法、属性等)和元数据联系起来。这 样编译器可以将元数据保存的cass文件中。代码分析工具就可以使用这些元数据执行的额 外任务。注释采用“at”标记形式(@),后面是注释名称。那么标注呢,其实就是。个特 殊的只是用来附加一些信息用的类,在英文中它的写法是 Annotation,本意就是注释的意思 关于这个词还有其它的一些翻译方式,例如叫元数据,注解,注释等等,都是指代的同一个 东西。不管怎么说,它其实就相当于一个超市里商品的标签,虽然大家都知道店面上摆着 排苹果,从外观来看大概这些苹果也相同,但是定价和产地等信息呢,一般则是卖家提供的 所以他们会在上面贴一个标签,表明定价,产地等信息。再比如说,大家买一台电脑,店家 肯定不是只告诉你一个总价钱了事,这样你也不会答应啊,所以,这台电脑的各个部件都会 有说明信息,店家会给你一个列表,标明: CPU Intel权核,主频2G,内存大小2G等等 类似的信息,这和中的标注也是类似的,它可以标到类型的声明上,或者是构造器 变量和方法上。要用一个标注,首先当然是需要创建一个标注类了,选择菜单Fie>New> Annotation,输入标注名,就可以创建标注了,下面列出了我们所创建的一个名 TestAnnotation的标注的代码清单,并列出了它的示例用法 import java. lang annotation. ted//是否 的时候列出此标 tArget(ElementType. TYPE, ElementType CONSTRUCTOR ElementType METHOD, Element Type FIELD]) /指定目标,可以标到类型构造器,方法和变量上 rEtention( Retention1icy.RMIM)/设置保持性 iNherited public interface TestAnnotation String va1ue() default"test1";//这里定义了一个属性 value(通过方法名来定 义,不是变量声明),并指定了默认值test1 String name()default ""i @TestAnnotation(name="Samplel",value="Valuel") //标注的使用简单示例 class sampleS t @TestAnnotation(value =id 1") private int id 刘长炯著
MyEclipse 6 Java 开发中文教程 8 刘长炯著 } public void setUsername(String username) { this.username = username; } //省略更多属性定义 } 首先可能部分读者对 Java 5 的标注还不是特别的熟悉。比较正式的文档都会这样介绍: Annotation 提供一种机制,将程序中元素(如类、方法、属性等)和元数据联系起来。这 样编译器可以将元数据保存的 class 文件中。代码分析工具就可以使用这些元数据执行的额 外任务。注释采用“at”标记形式 ( @ ),后面是注释名称。那么标注呢,其实就是一个特 殊的只是用来附加一些信息用的类,在英文中它的写法是 Annotation,本意就是注释的意思。 关于这个词还有其它的一些翻译方式,例如叫元数据,注解,注释等等,都是指代的同一个 东西。不管怎么说,它其实就相当于一个超市里商品的标签,虽然大家都知道店面上摆着一 排苹果,从外观来看大概这些苹果也相同,但是定价和产地等信息呢,一般则是卖家提供的, 所以他们会在上面贴一个标签,表明定价,产地等信息。再比如说,大家买一台电脑,店家 肯定不是只告诉你一个总价钱了事,这样你也不会答应啊,所以,这台电脑的各个部件都会 有说明信息,店家会给你一个列表,标明:CPU Intel 双核,主频 2G,内存大小 2G 等等 类似的信息。这和 Java 中的标注也是类似的,它可以标注到类型的声明上,或者是构造器, 变量和方法上。要用一个标注,首先当然是需要创建一个标注类了,选择菜单 File > New > Annotation,输入标注名,就可以创建标注了。下面列出了我们所创建的一个名为 TestAnnotation 的标注的代码清单,并列出了它的示例用法: import java.lang.annotation.*; @Documented// 是否产生JavaDoc的时候列出此标注信息 @Target({ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD}) //指定目标, 可以标到类型,构造器,方法和变量上 @Retention(RetentionPolicy.RUNTIME)//设置保持性 @Inherited public @interface TestAnnotation { String value() default "test1";//这里定义了一个属性 value(通过方法名来定 义,不是变量声明),并指定了默认值test1 String name() default ""; } @TestAnnotation(name="Sample1", value="Value1") // 标注的使用简单示例 class SampleUse { @TestAnnotation(value = "id_1") private int id;
MyEclipse6Java开发中文教程 TestAnnotation("id2")//当只有一个名为 的属性的时候,可以省略属性名 public int getid)[ return id; 。它使用@ Dinterface这样的关键字来定义的。好了,这些标注到底有什么用?Java的发明 者为什么要发明这个玩意呢?希望通过刚才的例子,读者已经可以简单理解到标注可以自己 带一些值附加到当前类上,那么很好,它的好处就在这里:给类多一些附加的信息。这些信 息可以通过反射( reflection)的APl读取出来,然后进行更进一步的处理。必须澄清一个 概念:依赖注入和代码写标注以及容器解析标注是三码事,要实现标注注入缺一不可。把自 己写的类加个写个@ Entity或者@EJB,不放入对应的容器里执行,那就还是普通的类而 已。所有的 Annotation本身什么也不能做,要做注入需要通过容器来获取对应的实例然后 解析上面的标注后做对应的操作。换句话说你自己new一个带标注的Bean,是什么效果 也没有的,只能通过容器来初始化,用类似于 getBean的方式,容器才能有机会进行注入 操作。 JPA通过定义一些不同的标注类型,将原来的配置文件信息从ⅩML配置文件中转移到 了Java类中。那么有什么好处呢?有一些资料已经列出了它的一些好处: 类似于 Hibernate的传统模式的ORM框架大都是采用xm作为配置文件,但采用文本 的xm配置存在一些缺陷: 描述符多,不容易记忆和掌握 ●无法做自动的校验,需要人工排错 当系统变大时,大量的xm配置难以管理 读取和解析xm配置非常耗时,导致应用启动缓慢,不利于测试和维护 做 O/R Mapping的时候需要在java文件和xm配置文件之间交替,增大了工作量 运行中保存xm配置需要消耗额外的内存 采用标注可以很好的解决这些问题 1.描述符大量减少。以往在xm配置中往往需要描述java属性的类型,关系等等。 而标注本身就是java语言,从而省略了大量的描述符 2.编译期校验。错误的批注在编译期间就会报错 3.标注批注在java代码中,避免了额外的文件维护工作 4.标注被编译成 java bytecode,消耗小的多内存,读取也非常迅速,往往比xm配 置解析快几个数据量级,利于测试和维护 。好了,这就是它的优点,最大的好处恐怕不在于3,而在于1和。4勉强算一个,因为3 和4都牵扯到改动信息的时候,需要找到类的源代码才可以,而且必须通过编译这一步, 所以有时候,例如成百上千的标注需要修改的时候,优势就不是那么的明显了。 注意:由于JPA依赖标注进行工作,所以JAP应用和标注代码都必须运行在Java5(JDK 15)或者更高版本上! 好了,现在我们的话题已经跑的足够远了,需要回过头来再看看刚才的实体类定义了 先来看看类的标注。 @ Entity:将 JavaBean标注为一个实体,表示需要保存到数据库中,默认情况下类名 即为表名,通过name属性可以显式指定实体名。在这个地方某些资料介绍有误,实体名 并不等于表名,只能说默认情况下实体名和表名以及类名这三者是一致的。然而,实体名最 刘长炯著
MyEclipse 6 Java 开发中文教程 9 刘长炯著 @TestAnnotation("id_2")//当只有一个名为value的属性的时候,可以省略属性名 value public int getID() { return id; } } 。它使用@interface 这样的关键字来定义的。好了,这些标注到底有什么用?Java 的发明 者为什么要发明这个玩意呢?希望通过刚才的例子,读者已经可以简单理解到标注可以自己 带一些值附加到当前类上,那么很好,它的好处就在这里:给类多一些附加的信息。这些信 息可以通过反射(reflection)的 API 读取出来,然后进行更进一步的处理。必须澄清一个 概念:依赖注入和代码写标注以及容器解析标注是三码事,要实现标注注入缺一不可。把自 己写的类加个写个 @Entity 或者 @EJB,不放入对应的容器里执行,那就还是普通的类而 已。所有的 Annotation 本身什么也不能做,要做注入需要通过容器来获取对应的实例然后 解析上面的标注后做对应的操作。换句话说你自己 new 一个带标注的 Bean,是什么效果 也没有的,只能通过容器来初始化,用类似于 getBean 的方式,容器才能有机会进行注入 操作。 JPA 通过定义一些不同的标注类型,将原来的配置文件信息从 XML 配置文件中转移到 了 Java 类中。那么有什么好处呢?有一些资料已经列出了它的一些好处: 类似于 Hibernate 的传统模式的 ORM 框架大都是采用 xml 作为配置文件,但采用文本 的 xml 配置存在一些缺陷: z 描述符多,不容易记忆和掌握 z 无法做自动的校验,需要人工排错 z 当系统变大时,大量的 xml 配置难以管理 z 读取和解析 xml 配置非常耗时,导致应用启动缓慢,不利于测试和维护 z 做 O/R Mapping 的时候需要在 java 文件和 xml 配置文件之间交替,增大了工作量 z 运行中保存 xml 配置需要消耗额外的内存 采用标注可以很好的解决这些问题: 1. 描述符大量减少。以往在 xml 配置中往往需要描述 java 属性的类型,关系等等。 而标注本身就是 java 语言,从而省略了大量的描述符 2. 编译期校验。错误的批注在编译期间就会报错。 3. 标注批注在 java 代码中,避免了额外的文件维护工作 4. 标注被编译成 java bytecode,消耗小的多内存,读取也非常迅速,往往比 xml 配 置解析快几个数据量级,利于测试和维护 。好了,这就是它的优点,最大的好处恐怕不在于 3,而在于 1 和。4 勉强算一个,因为 3 和 4 都牵扯到改动信息的时候,需要找到类的源代码才可以,而且必须通过编译这一步, 所以有时候,例如成百上千的标注需要修改的时候,优势就不是那么的明显了。 注意:由于JPA依赖标注进行工作,所以JAP应用和标注代码都必须运行在Java 5(JDK 1.5)或者更高版本上! 好了,现在我们的话题已经跑的足够远了,需要回过头来再看看刚才的实体类定义了。 先来看看类的标注。 @Entity:将 JavaBean 标注为一个实体,表示需要保存到数据库中,默认情况下类名 即为表名,通过 name 属性可以显式指定实体名。在这个地方某些资料介绍有误,实体名 并不等于表名,只能说默认情况下实体名和表名以及类名这三者是一致的。然而,实体名最
MyEclipse6Java开发中文教程 主要的用途是为了进行查询时(通过 JPA QL)区分不同的实体,例如下面的查询代码: select mode/ from User model和 select model from Myuser model,将会最终去寻找不同 的实体定义。而例子中的实体名则是User。实际使用中可以不用写name属性,只写一个 @ Entity的标注,这时候实体名等于类名(不含包路径,例如 entity. MyUser最后对应的实 体名是 MyUser)。和 Hibernate中一样,这个实体名必须是唯一的!而此标注也是必须的! @ Table:顾名思义,定义当前 Entity对应数据库中的表,需要注意的是主表( pnmary tabe),因为其它的表还可以通过@ Secondary Table或者@ Secondary Tables来进行标注 在例子中它对应的数据库中的表是 myuser(用name属性定义),所在的数据库名为test (用 catalog属性定义)。实践中此标记及其附属的属性都可以省略不写,这时候对应的数 据库表就是对应着实体的名字。这个标注可以不用定义,不是必须的 @d:定义了实体的主键信息。在一个实体类中只有一个主键标注,而此标注也是必须 的!它本身没有任何额外的属性可以设置。默认情况下它对应数据库中的类型和名字和当前 属性或者实体的变量相同的列(这是因为属性可以标注在属性和变量上,后文会有进一步的 介绍)。如果下面有@ Column标记,那么对应的数据库列信息以此标记中的内容为准。 @ Generatedvalue:一般它和ID的标注配合使用,用来制定主键的生产策略。通过 strategy属性指定。默认情况下,JPA自动选择一个最适合底层数据库的主键生成策略,如 Sq| Server对应 identity,MySq对应 auto increment e在 javax. persistence. GenerationType 这个枚举类中定义了以下几种可供选择的策略: 1)∥ DENT/TY:表自增键字段, Oracle不支持这种方式; 2)AUTO:JPA自动选择合适的策略,是默认选项(不幸的是大部分时候都会选择成 Sequence); 3) SEQUENCE:通过序列产生主键,还可以进一步通过@ Sequence Generator标注来指定 更详细的生产方式,MySq不支持这种方式(注:@ Sequence Generator用法示例: @Generatedvaluestrategy=Generation Type SEQUENCE) @ Sequence Generator(name="sEQ_TEST,∥此生成器的别名 sequence Name=" ser SEQ"∥对应的 Oracle sequence的名字 allocation Size=25) ) 4) TABLE:通过表彥生主键,框架借由表模拟序列( sequence)产生主键,使用该策略可 以使应用更易于数据库移植。不同的JPA厂商所默认生成的表名是不同的,如 OpenJPA 生成 openjpa sequence table表, Hibernate生成一个 hibernate sequences表,而 TopLink则生成 sequence表。这些表都具有一个序列名和对应值两个字段,如SEQ_NAME 和SEQ_ COUNT 另外还有一个重要的属性就是 generator,它可以更进一步制定主键生成器所采用的参 数,例如 sequence表的表名可以这样定义:@ Generated Value( strategy= SEQUENCE, generator="CUST_SEQ")。同样的也可以用于 TABLE方式的生成器上 @Generated Value(strategy= TABLE, generator="CUST GEN) @ Column:属性或者变量对应的表字段。一般来说我们并不需要指定表字段的类型, 因为JPA会根据反射从实体属性中获取类型;如果是字符串类型,我们可以指定字段长度, 以便可以自动生成DDL语句:还可以指定一些其它的属性例如是否唯一( unique),是否可 以为空( nullable),是否可以插入和更新等等( insertable和 updatable);name属性指定 了它对应于数据库中的列名。如果是时间类型,一般还需要指定精度,用@7 emporal来进 行标注。同样的这个标注也不是必须的,如果没有写任何参数的话,它的名字和类型都和当 前标注的属性或者变量的名字和类型相同 刘长炯著
MyEclipse 6 Java 开发中文教程 10 刘长炯著 主要的用途是为了进行查询时(通过 JPA QL)区分不同的实体,例如下面的查询代码: select model from User model 和 select model from Myuser model,将会最终去寻找不同 的实体定义。而例子中的实体名则是 User。实际使用中可以不用写 name 属性,只写一个 @Entity 的标注,这时候实体名等于类名(不含包路径,例如 entity.MyUser 最后对应的实 体名是 MyUser)。和 Hibernate 中一样,这个实体名必须是唯一的!而此标注也是必须的! @Table:顾名思义,定义当前 Entity 对应数据库中的表,需要注意的是主表(primary table),因为其它的表还可以通过@SecondaryTable 或者@SecondaryTables 来进行标注。 在例子中它对应的数据库中的表是 myuser(用 name 属性定义),所在的数据库名为 test (用 catalog 属性定义)。实践中此标记及其附属的属性都可以省略不写,这时候对应的数 据库表就是对应着实体的名字。这个标注可以不用定义,不是必须的。 @Id:定义了实体的主键信息。在一个实体类中只有一个主键标注,而此标注也是必须 的!它本身没有任何额外的属性可以设置。默认情况下它对应数据库中的类型和名字和当前 属性或者实体的变量相同的列(这是因为属性可以标注在属性和变量上,后文会有进一步的 介绍)。如果下面有@Column 标记,那么对应的数据库列信息以此标记中的内容为准。 @GeneratedValue:一般它和 ID 的标注配合使用,用来制定主键的生产策略。通过 strategy 属性指定。默认情况下,JPA 自动选择一个最适合底层数据库的主键生成策略,如 SqlServer 对应 identity,MySql 对应 auto increment。在 javax.persistence.GenerationType 这个枚举类中定义了以下几种可供选择的策略: 1) IDENTITY:表自增键字段,Oracle 不支持这种方式; 2) AUTO: JPA 自动选择合适的策略,是默认选项(不幸的是大部分时候都会选择成 Sequence); 3) SEQUENCE:通过序列产生主键,还可以进一步通过@SequenceGenerator 标注来指定 更详细的生产方式,MySql 不支持这种方式(注:@SequenceGenerator 用法示例: @GeneratedValue(strategy=GenerationType.SEQUENCE) @SequenceGenerator(name="SEQ_TEST", // 此生成器的别名 sequenceName="User_SEQ",// 对应的 Oracle sequence 的名字 allocationSize=25) ); 4) TABLE:通过表产生主键,框架借由表模拟序列(sequence)产生主键,使用该策略可 以使应用更易于数据库移植。不同的 JPA 厂商所默认生成的表名是不同的,如 OpenJPA 生成 openjpa_sequence_table 表,Hibernate 生成一个 hibernate_sequences 表,而 TopLink 则生成 sequence 表。这些表都具有一个序列名和对应值两个字段,如 SEQ_NAME 和 SEQ_COUNT。 另外还有一个重要的属性就是 generator,它可以更进一步制定主键生成器所采用的参 数,例如 sequence 表的表名可以这样定义:@GeneratedValue(strategy=SEQUENCE, generator="CUST_SEQ") 。同样的也可以用于 TABLE 方式的生成器上: @GeneratedValue(strategy=TABLE, generator="CUST_GEN")。 @Column:属性或者变量对应的表字段。一般来说我们并不需要指定表字段的类型, 因为 JPA 会根据反射从实体属性中获取类型;如果是字符串类型,我们可以指定字段长度, 以便可以自动生成 DDL 语句;还可以指定一些其它的属性例如是否唯一(unique),是否可 以为空(nullable),是否可以插入和更新等等(insertable 和 updatable);name 属性指定 了它对应于数据库中的列名。如果是时间类型,一般还需要指定精度,用@Temporal 来进 行标注。同样的这个标注也不是必须的,如果没有写任何参数的话,它的名字和类型都和当 前标注的属性或者变量的名字和类型相同