目前企业级应用一般均采用面向对象的开发方法,而内存中的对象数据不能永久存在,如想借用关系数据库来永久保存这些数据的话,无疑就存在一个对象-关系的映射过程。在这种情形下,诞生了许多解决对象持久化的中间件,其中开源的Hibernate由于其功能与性能的优越而备受Java程序员青睐。
为了使读者对Hibernate有一个初步的了解,本章讲解的主要内容包括:
ORM简介
Hibernate简介
Hibernate的映射机制
1、 ORM简介
对象-关系映射ORM(Object-Relation Mapping)是用来将对象和对象之间的关系对应到数据库表与表之间的关系的一种模式。
1.1 持久化与持久层
所谓持久化就是把内存中的数据同步保存到数据库(如关系数据库)或永久存储设备(如硬盘、磁带等)中,其原理如图4-1所示。
大家以前使用的JDBC操作(如新增记录、删除记录及修改记录)其实就是一个持久化的过程。
所谓持久层就是专门负责持久化工作的逻辑层,由它统一与数据库层打交道。这样一来,便可以将以前的三层模型(表示层、业务逻辑层和数据库层)修改成四层模型(表示层、业务逻辑层、持久层和数据库层)。四层模型的内部关系如图4-2所示。
从上图不难发现,持久层封装了所有与数据库有关的操作和细节,作为一个专业的持久层中间件(如Hibernate),除了具备基本的新增数据、删除数据、修改数据、查询数据功能之外,还必须提供连接管理、事务管理、性能管理、缓存管理、对象-关系映射等高级功能,以满足专业的开发需求。
1.2 JDBC劣势
对于小型的应用开发而言,使用JDBC也许感觉还不错。但对于大型应用开发而言,单凭JDBC就显得有些力不从心了,例如,从上百张拥有几十个字段的数据表中取数据的话,可以想象要写多少个getXXX()语句完成数据读取工作,暂不说烦琐的代码,最让人头痛的还有高出错率和低复用性。
在当今多层体系结构的软件开发中,使用JDBC很难将持久层进行分离,负责业务逻辑代码编写的程序员必须密切关注数据库各表的结构关系,以确保其SQL语句工作的正常。如果引入Hibernate这样的持久层中间件的话,业务逻辑层的开发人员整天面对的就是一个又一个的对象而不必关心数据表,既有利于团队分工协作,又提高了软件产品的可移植性。
从易用性与高效性角度来说,JDBC在记录的批量操作、多表连接、表单级联方面表现并不优秀,Hibernate对此提供了自己的解决方案,使得与数据库层的交互既高效又稳定。
1.3 实体域模型与关系数据模型
模型是对现实的一种抽象。
实体域模型则是对真实世界中的物质实体(如学生、老师、商品等)的抽象,它由实体域对象组成,实体域对象用来代表这些真实世界中的物质实体。在Java EE应用中,实体域对象是指实体EJB或POJO(JavaBean形式的实体域对象),若无特别声明,本书所说的实体域对象默指POJO。
例如,在客户关系管理系统中城市实体类City.java为:
14.return this.clientSet;
15. }
16.public void setClientSet(java.util.Set clientSet){
17.this.clientSet = clientSet;
18. }
19.//重载Object的equals方法
20.public boolean equals(Object rhs){
21.if (rhs == null)
22.return false;
23.if (! (rhs instanceof City))
24.return false;
25. City that = (City) rhs;
26.if (this.getCityid() == null || that.getCityid() == null)
27.return false;
28.return (this.getCityid().equals(that.getCityid()));
29. }
30.//重载Object的hashCode方法
31.public int hashCode(){
32.if (this.hashValue == 0)
33. {
34.int result = 17;
35.int cityidValue = this.getCityid() ==
36.null ? 0 : this.getCityid().hashCode();
37. result = result * 37 + cityidValue;
38.this.hashValue = result;
39. }
40.return this.hashValue;
41. }
42.}
目前,关系型数据库的应用最为广泛,关系数据模型便是对关系型数据库中关系数据(如表、视图等)的一种静态描述。例如,与上面City实体域对象对应的关系模型如表4-1所示。
表4-1 City数据表
读者也可以使用E-R图来描述关系模型,例如,某电子商城的关系模型如图4-3所示。
综上所述,实体域模型是面向对象的,而关系数据模型是面向关系型数据库的,它们之间的数据交换需要一个映射的过程。例如,实体域对象City与关系数据表city之间可通过Hibernate的映射配置文件City.hbm.xml进行映射。
1.4 ORM中间件
大量的企业应用开发人员的实践表明,直接采用第三方提供的ORM中间件是可行之道。因为企业自行开发ORM中间件的话,不但对开发人员的专业知识要求相当高,而且产品质量与性能很难保证。目前,市面上除了几款商业化的ORM中间件(如TopLink、FrontierSuite 等)外,优秀的开源ORM中间件(如Hibernate、IBATIS、JPOX等)也不少。
无论使用商业化的ORM中间件,还是使用开源的ORM中间件,我们都应该使业务逻辑层与ORM中间件保持相对独立,这有利于以后应用的升级与移植。
2.2 Hibernate简介
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的封装,使得Java程序员可以随心所欲地使用面向对象的编程思想来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java Application中使用,也可以在Servlet/JSP 的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的Java EE架构中取代CMP,完成数据持久化的重任。
2.2.1 Hibernate体系结构
在分层体系架构中,Hibernate负责应用程序与数据库之间的数据交换,起ORM中间件的作用,具体关系如图4-4所示。
从上图可以看出,Hibernate与数据库的连接配置信息均封装到hibernate.properties或hibernate.cfg.xml文件中,对象-关系的映射工作依靠ORM映射文件进行,最终完成对象与关系间的平滑映射。
2.2.2 Hibernate API简介
Hibernate作为ORM中间件出现,使得应用程序通过Hibernate的API就可以访问数据库。由于Hibernate只是对JDBC做了一个轻量级的封装(未完全封装),因此亦可绕过Hibernate,直接使用JDBC API来访问数据库。不过,作为面向对象的应用开发技术体系而言,笔者推荐尽量使用Hibernate API。
Hibernate API根据版本的不同,所属的包也不一样。Hibernate2.1的API位于net.sf.hibernate包中,而Hibernate 3.X的API 则位于org.hibernate包中。为了使大家更进一步地认识Hibernate 3.X,灵活应用Hibernate,其核心API介绍如表4-2所示。
表4-2 Hibernate API介绍
在应用中使用Hibernate,首先必须进行Hibernate与数据库连接设置、连接池参数设置及ORM映射文件的创建,如图4-5所示。
在使用了Hibernate的应用(简称"Hibernate应用")中,Hibernate的启动与内部分工协作的关系如图4-6所示。
综上所述,不难看出,Hibernate Web应用的开发一般经过以下几个步骤。
(1)创建数据库。
(2)将Hibernate所需的JAR包复制到WEB-INF/lib下。
(3)创建Hibernate的配置文件。
(4)利用Hibernate的第三方工具或Eclipse的有关插件从数据库中创建出相应的实体对象及其ORM映射文件。
(5)创建Hibernate的SessionFactory类。
(6)通过SessionFactory创建Session实例。
(7)通过创建的Session实例进行持久化对象的管理。
(8)通过创建的Transaction实例进行事务管理。
(9)通过创建的Query或Criteria实例实现数据库的查询
2.2.3 配置Hibernate
配置Hibernate主要就是创建Hibernate的配置文件和SessionFactory类,Hibernate的配置文件可以是hibernate.properties 或hibernate.cfg.xml(二者任选其一),由于hibernate.cfg.xml配置的便捷与完整性,使之成为Hibernate配置文件之首选。
下面重点介绍hibernate.cfg.xml的配置方法。
配置好hibernate.cfg.xml后,推荐将其保存到WEB-INF/classes下,接下来就可以创建自己的SessionFactory了,例如,MySessionFactory.java。
1.package com.ORM;
2.import org.hibernate.HibernateException;
3.import org.hibernate.Session;
4.import org.hibernate.cfg.Configuration;
5.public class MySessionFactory {
6.//定义一个静态字符串变量存放Hibernate的配置文件名
7.private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
8.//创建一个线程局部变量对象
9.private static final ThreadLocal threadLocal = new ThreadLocal();
10.//创建一个静态的Configuration对象
11.private static final Configuration cfg = new Configuration();
12.//定义一个静态的SessionFactory对象
13.private static org.hibernate.SessionFactory sessionFactory;
14.//取得一个当前的Session对象
15.public static Session currentSession() throws HibernateException {
16.Session session = (Session) threadLocal.get();
17.if (session == null) {
18.if (sessionFactory == null) {
19.try {
20.//根据配置文件,配置Hibernate
21. cfg.configure(CONFIG_FILE_LOCATION);
22.//通过Configuration对象创建SessionFactory对象
23. sessionFactory = cfg.buildSessionFactory();
24. }
25.catch (Exception e) {
26. System.err.println("【系统错误】
27.创建SessionFactory对象时出错,原因是:");
28. e.printStackTrace();
29. }
30. }
31.//通过SessionFactory对象创建Session对象
32. session = sessionFactory.openSession();
33. threadLocal.set(session);
34.}
35.return session;
36. }
37.//关闭一个Session对象
38.public static void closeSession() throws HibernateException {
39.Session session = (Session) threadLocal.get();
40.threadLocal.set(null);
41.if (session != null) {
42. session.close();
43.}
44. }
45.//构造方法
46.private MySessionFactory() {}
到此为止,已经可以方便地在应用中调用Hibernate API进行持久化操作了,例如,SystemPart.java:
1.package com.service;
2.import org.hibernate.*;
3.import com.ORM.*;
4.import java.util.*;
5.public class SystemPart{
6.//用户验证
7.public boolean userCheck(String loginName, String loginPass)
8.throws Exception {
9.//创建一个Session对象
10.Session session = MySessionFactory.currentSession();
11.//定义一个Transaction对象
12.Transaction ts = null;
13.try{
14.List result = null;
15.//创建一个Query查询对象
16.Query query = session.createQuery("select a from Admin as a
17.where https://www.doczj.com/doc/e41095802.html,ername=:loginname and a.loginpass=:loginpass");
18.//设置查询参数值
19.query.setString("loginname",loginName);
20.query.setString("loginpass",loginPass);
21.//创建一个Transaction对象
22.ts = session.beginTransaction();
23.//执行查询,得到查询结果
24.result = query.list();
25.//提交事务
https://www.doczj.com/doc/e41095802.html,mit();
27.if (result.size()>0)return true;
28.else return false;
29.}catch(Exception ex){
30.//事务回滚
31.if(ts!=null)ts.rollback();
32.System.out.println("【系统错误】在执行用户验证时出错,原因是:");
33.ex.printStackTrace();
34.return false;
35.}finally{
36.//关闭Session对象
37.MySessionFactory.closeSession();
38.}
39.}
40.}
2.2.4 Hibernate的映射配置文件
Hibernate的映射配置文件是实体对象与数据库关系表之间相互转换的重要依据,一般而言,一个映射配置文件对应数据库中一个关系表,关系表之间的关联关系也在映射文件中进行配置。
目前,已经有很多的第三方工具(如Middlegen和MyEclipse等)能自动从数据库中导出相应的映射配置文件。
假如在MySQL数据库中有一个用户表users,如表4-3所示。
表4-3 users数据表
其对应的持久化类Users.java:
1.package com.ORM;
2.import java.io.Serializable;
3.import java.util.Date;
4.public class Users implements Serializable{
5.private https://www.doczj.com/doc/e41095802.html,ng.Integer id; //ID号
6.private https://www.doczj.com/doc/e41095802.html,ng.String username; //用户姓名
7.private https://www.doczj.com/doc/e41095802.html,ng.String password; //用户密码
8.private java.util.Date birthday; //出生日期
9.private https://www.doczj.com/doc/e41095802.html,ng.String phone; //联系电话
10.private https://www.doczj.com/doc/e41095802.html,ng.String address; //联系地址
11.private https://www.doczj.com/doc/e41095802.html,ng.String email; //电子邮箱
12.private java.util.Date regdate; //注册时间
13.public Users(){} //构造方法
14.//省略上述各属性的get/set方法对
15.}
数据库关系表users与应用中的持久化类Users.java的映射文件Users.hbm.xml为:
2.2.5 体验Hibernate(会员管理)
这里以一个比较简单的"会员管理"应用为实例来演示Hibernate应用的开发过程,使大家在体验中尽快找到Hibernate应用开发的感觉。
本实例以MySQL 5.0作为数据库服务器,会员表users、会员持久化类Users.java及其ORM映射文件Users.hbm.xml均在上面介绍过,这里就不多讲了。
(1)创建Hibernate配置文件hibernate.cfg.xml。
1.
2.
3."-//Hibernate/Hibernate Configuration DTD 3.0//EN"
4. "https://www.doczj.com/doc/e41095802.html,
5. /hibernate-configuration-3.0.dtd">
6.
7.
8.
9.
10.jdbc:mysql://localhost:3306/member?useUnicode=true&
11.characterEncoding=gb2312
12.
13.
14.
15.
https://www.doczj.com/doc/e41095802.html,.mysql.jdbc.Driver
17.
18.
https://www.doczj.com/doc/e41095802.html,.hibernate.dialect.MySQLDialect
20.
21.
22.
https://www.doczj.com/doc/e41095802.html,.hibernate.connection.C3P0ConnectionProvider
24.
25.
26.
27.
28.
29.
30.
31.
32.
34.
35.
(2)创建MySessionFactory.java。
1.package com.ORM;
2.import org.hibernate.HibernateException;
3.import org.hibernate.Session;
4.import org.hibernate.cfg.Configuration;
5.public class MySessionFactory {
6.//定义一个静态字符串变量存放Hibernate的配置文件名
7.private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
8.//创建一个线程局部变量对象
9.private static final ThreadLocal threadLocal = new ThreadLocal();
10.//创建一个静态的Configuration对象
11.private static final Configuration cfg = new Configuration();
12.//定义一个静态的SessionFactory对象
13.private static org.hibernate.SessionFactory sessionFactory;
14.//取得一个当前的Session对象
15.public static Session currentSession() throws HibernateException {
16. Session session = (Session) threadLocal.get();
17.if (session == null) {
18.if (sessionFactory == null) {
19.try {
20.//根据配置文件,配置Hibernate
21. cfg.configure(CONFIG_FILE_LOCATION);
22.//通过Configuration对象创建SessionFactory对象
23. sessionFactory = cfg.buildSessionFactory();
24.}
25.catch (Exception e) {
26. System.err.println("【系统错误】
27.创建SessionFactory对象时出错,原因是:");
28. e.printStackTrace();
29.}
30. }
31.//通过SessionFactory对象创建Session对象
32. session = sessionFactory.openSession();
33. threadLocal.set(session);
34. }
35.return session;
36. }
37.//关闭一个Session对象
38.public static void closeSession() throws HibernateException {
39. Session session = (Session) threadLocal.get();
40. threadLocal.set(null);
41.if (session != null) {
42. session.close();
43. }
44. }
45.//构造方法
46.private MySessionFactory() {}
47.}
(3)创建数据库访问DAO接口MemberDAO.java。
1.package com.DAO;
2.import java.util.List;
3.import https://www.doczj.com/doc/e41095802.html,ers;
4.public interface MemberDAO {
5.//新增会员
6.public void addMember(Users user);
7.//浏览会员
8.public List allMember();
9.//删除会员
10.public void delMember(Integer id);
11.//装载会员
12.public Users loadMember(Integer id);
13.//修改会员
14.public void modiMember(Users user);
15.}
(4)创建数据库访问DAO接口实现类MemberDAOImpl.java。
1.package com.DAO;
2.import java.util.*;
3.import org.hibernate.*;
4.import com.ORM.*;
5.public class MemberDAOImpl implements MemberDAO {
6.//新增会员
7.public void addMember(Users user) {
8.//创建一个Session对象
9.Session session = MySessionFactory.currentSession();
10.//定义一个Transaction对象
11.Transaction ts = null;
12.try{
13.//创建一个Transaction对象
14.ts = session.beginTransaction();
15.//调用Session对象的save方法将持久化对象保存到数据库
16.session.save(user);
17.//提交事务
https://www.doczj.com/doc/e41095802.html,mit();
19.}catch(Exception ex){
20.//回滚事务
21.if(ts!=null)ts.rollback();
22.System.out.println("
23.【系统错误】在保存持久化对象时出错,原因是:");
24.ex.printStackTrace();
25.}finally{
26.//关闭Session对象
27.MySessionFactory.closeSession();
28.}
29.}
30.//浏览会员
31.public List allMember() {
32.List members = new ArrayList();
33.//创建一个Session对象
34.Session session = MySessionFactory.currentSession();
35.//定义一个Transaction对象
36.Transaction ts = null;
37.try{
38.String HQL = "select a from Users as a order by a.id";
39.//创建一个Query查询对象
40.Query query = session.createQuery(HQL);
41.//创建一个Transaction对象
42.ts = session.beginTransaction();
43.//执行查询,取得查询结果
44.members = query.list();
45.//提交事务
https://www.doczj.com/doc/e41095802.html,mit();
47.if (!Hibernate.isInitialized(members))Hibernate.initialize(members);
48.}catch(Exception ex){
49.//回滚事务
50.if(ts!=null)ts.rollback();
51.System.out.println("【系统错误】
52.在查询出所有持久化对象时出错,原因是:");
53.ex.printStackTrace();
54.}finally{
55.//关闭Session对象
56.MySessionFactory.closeSession();
57.}
58.return members;
59.}
60.//删除会员
61.public void delMember(Integer id) {
62.//创建一个Session对象
63.Session session = MySessionFactory.currentSession();
64.//定义一个Transaction对象
65.Transaction ts = null;
67.//创建一个Transaction对象
68.ts = session.beginTransaction();
69.//调用Session对象的load方法装载指定ID的会员对象到内存中
https://www.doczj.com/doc/e41095802.html,ers user = (Users)session.load(Users.class,id);
71.//调用Session对象的delete方法将持久化对象删除
72.session.delete(user);
73.//提交事务
https://www.doczj.com/doc/e41095802.html,mit();
75.}catch(Exception ex){
76.//回滚事务
77.if(ts!=null)ts.rollback();
78.System.out.println("【系统错误】在删除持久化对象时出错,原因是:");
79.ex.printStackTrace();
80.}finally{
81.//关闭Session对象
82.MySessionFactory.closeSession();
83.}
84.}
85.//装载会员
86.public Users loadMember(Integer id) {
87.//创建一个Session对象
88.Session session = MySessionFactory.currentSession();
89.//定义一个Transaction对象
90.Transaction ts = null;
https://www.doczj.com/doc/e41095802.html,ers user = null;
92.try{
93.//创建一个Transaction对象
94.ts = session.beginTransaction();
95.//调用Session对象的get方法装载指定ID的会员对象到内存中
https://www.doczj.com/doc/e41095802.html,er = (Users)session.get(Users.class,id);
97.//提交事务
https://www.doczj.com/doc/e41095802.html,mit();
99.}catch(Exception ex){
100.//回滚事务
101.if(ts!=null)ts.rollback();
102.System.out.println("【系统错误】
103.在装载持久化对象时出错,原因是:");
104.ex.printStackTrace();
105.}finally{
106.//关闭Session对象
107.MySessionFactory.closeSession();
108.}
109.return user;
110.}
111.//修改会员
112.public void modiMember(Users user) {
113.//创建一个Session对象
114.Session session = MySessionFactory.currentSession();
115.//定义一个Transaction对象
116.Transaction ts = null;
117.try{
118.//创建一个Transaction对象
119.ts = session.beginTransaction();
120.//调用Session对象的update方法将持久化对象更新到数据库
121.session.update(user);
122.//提交事务
https://www.doczj.com/doc/e41095802.html,mit();
124.}catch(Exception ex){
125.//回滚事务
126.if(ts!=null)ts.rollback();
127.System.out.println("【系统错误】
128.在更新持久化对象时出错,原因是:");
129.ex.printStackTrace();
130.}finally{
131.//关闭Session对象
132.MySessionFactory.closeSession();
133.}
134.}
135.}
(5)创建代理数据库访问接口MemberService.java。
1.package com.service;
2.import java.util.List;
3.import https://www.doczj.com/doc/e41095802.html,ers;
4.public interface MemberService {
5.//新增会员
6.public void addMember(Users user);
7.//浏览会员
8.public List allMember();
9.//删除会员
10.public void delMember(Integer id);
11.//装载会员
12.public Users loadMember(Integer id);
13.//修改会员
14.public void modiMember(Users user);
15.}
(6)创建代理数据库访问接口实现类MemberServiceImpl.java。
1.package com.service;
2.import java.util.List;
3.import https://www.doczj.com/doc/e41095802.html,ers;
4.import com.DAO.*;
5.public class MemberServiceImpl implements MemberService {
6.//创建一个数据库访问对象DAO
7.private MemberDAO dao = new MemberDAOImpl();
8.//新增会员
9.public void addMember(Users user) {
10.dao.addMember(user);
11.}
12.//浏览会员
13.public List allMember() {
14.return dao.allMember();
15.}
16.//删除会员
17.public void delMember(Integer id) {
18.dao.delMember(id);
19.}
20.//装载会员
21.public Users loadMember(Integer id) {
22.return dao.loadMember(id);
23.}
24.//修改会员
25.public void modiMember(Users user) {
26.dao.modiMember(user);
27.}
28.}
(7)创建调用MemberService实现会员管理(增、删、改、查)的MemberAction.java。
1.package com.test.struts.action;
2.
3.import com.opensymphony.xwork2.ActionSupport;
4.import com.opensymphony.xwork2.ModelDriven;
5.import com.ORM.*;
6.import com.service.*;
7.import java.util.*;
8.import java.util.regex.Pattern;
9.import https://www.doczj.com/doc/e41095802.html,mons.beanutils.BeanUtils;
10.import java.sql.Timestamp;
11.
12./** 会员管理控制器 */
13.public class MemberAction extends
14.ActionSupport implements ModelDriven
15.//创建业务逻辑层对象
16.MemberService service = new MemberServiceImpl();