第二章 java对象持久化技术概述
本章介绍对象持久化的集中模式
1.在业务逻辑层直接通过JDBCAPI来持久化实体域对象,业务逻辑和数据访问耦合。
2.主动域对象模式
3.ORM模式
4.JDO模式
5.CMP模式
2.1通过JDBC API来持久化实体域对象
Java应用访问数据库的最直接的方式就是直接访问JDBC API,JDBC是Java Database Connectivity的缩写。
java.sql包提供了JDBC API。在java.sql包中常用的接口和类包括:
DriverManager:驱动程序管理器,负责创建数据库连接。
Connection:代表数据库连接。
Statement:负责执行SQL语句。
PreparedStatement:负责执行SQL语句,具有预定义SQL语句的功能。
ResultSet:代表SQL查询语句的查询结果集
JDBC驱动程序
Java应用必须通过JDBC驱动程序来和特定的数据库系统连接。
JDBC驱动程序由数据库厂商或第三方提供。
负责持久化Customer对象的BusinessService
saveCustomer():把Customer域对象永久保存到数据库中。
updateCustomer():更新数据库中Customer域对象的状态。
deleteCustomer():从数据库中删除一个Customer域对象。
loadCustomer():根据特定的OID,把一个Customer域对象从数据库加载到内存中。
findCustomerByName():根据特定的客户姓名,把符合查询条件的Customer域对象从数据库加载到内存中。
业务逻辑代码与数据访问代码耦合的saveCustomer()方法
con=getConnection(); //获得数据库连接
//开始一个数据库事务
con.setAutoCommit(false);
//以下是业务逻辑代码,检查客户姓名是否为空
if(customer.getName()==null)
throw new BusinessException("客户姓名不允许为空");
//以下是数据访问代码,持久化Customer对象
//为新的CUSTOMERS记录分配惟一的ID
long customerId=getNextId(con,"CUSTOMERS");
//把Customer对象映射为面向关系的SQL语句
stmt=con.prepareStatement("insert into CUSTOMERS(ID,NAME,AGE) values(?,?,?)");
stmt.setLong(1,customerId);
stmt.setString(2,customer.getName());
stmt.setInt(3,customer.getAge());
stmt.execute();
业务逻辑代码与数据访问代码耦合的saveCustomer()方法
Iterator iterator =customer.getOrders().iterator();
while (iterator.hasNext() ) {
//以下是业务逻辑代码,检查订单编号是否为空
Order order=(Order)iterator.next();
if(order.getOrderNumber()==null)
throw new BusinessException("订单编号不允许为空");
//以下是数据访问代码,级联持久化Order对象
//为新的ORDERS记录分配惟一的ID
long orderId=getNextId(con,"ORDERS");
//把Order对象映射为面向关系的SQL语句
stmt=con.prepareStatement("insert into ORDERS(ID,ORDER_NUMBER,PRICE,CUSTOMER_ID)values(?,?,?,?)");
stmt.setLong(1,orderId);
stmt.setString(2,order.getOrderNumber());
stmt.setDouble(3,order.getPrice());
stmt.setLong(4,customerId);
stmt.execute();
}
//提交数据库事务
con.commit();
JDBC编程的缺点
实现业务逻辑的代码和数据库访问代码掺杂在一起,使程序结构不清晰,可读性差。
在程序代码中嵌入面向关系的SQL语句,使开发人员不能完全运用面向对象的思维来编写程序。
业务逻辑和关系数据模型绑定,如果关系数据模型发生变化,例如修改了CUSTOMERS表的结构,那么必须手工修改程序代码中所有相关的SQL语句,这增加了维护软件的难度。
如果程序代码中的SQL语句包含语法错误,在编译时不能检查这种错误,只有在运行时才能发现这种错误,这增加了调试程序的难度。
数据访问模式
业务逻辑和数据访问耦合
ORM模式:在单个组件中负责所有实体域对象的持久化,封装数据访问细节。
主动域对象模式:由实体域对象本身负责管理自己的持久化
JDO模式: SUN公司制定的描述对象持久化语义的标准API
CMP模式:由容器负责管理持久化
2.2ORM简介
对象-关系映射(即Object-Relation Mapping)模式是指在单个组件中负责所有实体域对象的持久化,封转数据访问细节。
2.2.1对象-关系映射(Object-Relation Mapping)的概念
ORM解决的主要问题就是对象-关系的映射。域模型和关系模型都分别建立在概念模型的基础上。域模型是面向对象的,而关系数据模型是面向关系的.
一般情况下,一个持久化类和一个表对应,类的每个实例对应表中的一条记录。
域模型与关系模型之间存在许多不匹配之处:
域模型中有继承关系,关系模型不能直接表示继承关系
域模型中有多对多关联关系,关系模型通过连接表来表示多对多关联关系
域模型中有双向关联关系,关系模型只有单向参照关系,而且总是many方参照one方。
域模型提倡精粒度模型,而关系模型提倡粗粒度模型
域模型与关系模型之间的不匹配举例
2.2.3 ORM中间件的使用方法
ORM中间件采用元数据来描述对象-关系映射文件细节,元数据采用XML格式,而且保存在专门的对象-关系映射文件中。
在图中Session接口向业务逻辑提供了读写和删除域对象的方法,他不公开任何数据访问细节,SessionImpl实现这个接口。SessionFactroy负责创建Session实例。Hibernate在初始阶段把对象-关系映射文件的映射元数据读入到SessionFactory中。
Public void deleteCustomer(Customer customer)
{
Session sesion=getSession();
Session.delete(customer);
}
Session的delete()方法执行以下步骤:
1>运用Java反射机制,获得customer对象的类型为Customer.class
2>参考对象-关系映射元数据,了解到和Customer类对应的表为CUSTOMERS表,此外Customers类和Order类关联,Order类和ORDER表对应,ORDERS表的外键CUSTOMER_ID参照CUSTOMER表的ID主键
3>根据以上映射信息,生成SQL语句
Delete from ORDERS where CUSTOMER_ID=?
Delete from CUSTOMERS where ID=?
4>通过JDBC API来执行以上SQL语句
2.2.3 常用的ORM中间件
ORM软件 | URL |
Hibernate | |
TopLink | http://otn.oracle.com/products/ias/toplink/content.html |
Torque | http://jakarta.apache.org/turbine/torque/index.html |
ObjectRelatinalBridge | |
FrontierSuite | |
Castor | |
FreeFORM | |
Expresso | |
JRelationalFframework | |
VBSF | |
Jgrinder | |
JPA | 直接对轻量级的基于JavaBean形式的实体域进行持久化 |
2.3实体域对象的其他持久化模式
2.3.1主动域对象模式
主动域是实体域对象的一种形式,在它的实现中封装了关系数据模型和数据访问细节。
在EJB中分实体Bean分为:由EJB本身管理持久化,即BMP是主动域对象模型的一个例子,BMP表示有实体EJB本身管理数据访问细节。
主动域对象模式的优点:
A>在实体域对象中封装自身的数据访问细节,过程域对象完全负责业务逻辑,是程序结构清晰
B>如果关系数据模型发生冲突,只需改变主动域对象的代码,不需要修改过程域对象的业务方法。
主动域对象模式的缺点:
A>在实体域对象的实现中仍然包含sql语句
B>每个实体域对象都负责自身的数据访问实现。
2.3.2JDO模式
Java Data Objects(JDO)是sun制定的描述对象持久化语义的标准API
采用JDO模式的应用的分层结构
JDO支持关系数据库。面向对象的数据库.基于XML的数据库和其他专用存储系统
2.3.3 CMP模式
CMP模式表示由EJB容器来管理实体EJB持久化,EJB容器封装了对象-关系的映射及数据访问细节。
2.4HibernateAPI简介
1.提供访问数据库的操作(如保存.跟新.删除和查询对象)的接口。包括Session.Transacction和Query接口。
2.用于配置Hibernate的接口。包括Configuration
3.使应用程序拦截Hibernate内部发生事件,并做出相关的反应。这些接口:Interceptor.LoadEventListener和SaveEventListener
4.用于扩展Hibernate的功能接口。如UserType.CompositeUserType和IdentifierGenerator接口。
Hibernate内部封装了JDBC,JTA(JAVA Naming and Directory Interface).JDBC提供底层的数据访问操作,只要用户提供相应的JDBC驱动程序,Hibernate可以访问任何数据库。JNDI和JTA使Hibernate能够和j2ee应用服务器集成。
2.4.1hibernate的核心接口
1.Configuration接口是配置Hibernate并且根启动Hibernate,创建SessionFactory对象。Hiberante应用通过Configuration实例来获得对象-关系映射文件中文件的元数据,以及动态配置Hibernate的属性,然后创建sessionFactory的实例
2.SessionFactory接口:初始化hiberante,充当数据存储源的代理,创建Session对象。一个SessionFactory实例对应一个数据存储源,应用以SessionFctory中获取Session实例。
SessionFctory的特点:
1.它是线程安全的,意味着它的同一实例可以被应用的 多个线程共享。
2.它是重量级,这意味着不能随意的创建或者销毁它的实例。访问一个数据库创建一个SessionFactory,访问多个就创建多个。(被称为重量级的是因为:1。它需要很大的缓存存放预定义的SQL语句及映射元数据等。还可以配置SessionFactory的缓存插件,被称为Hibernate的二次缓存,用来存放被工作单元读过的数据,将来其他工作单元会重用这些数据,因此这个缓存中的数据能够被所有工作单元共享,一个工作单元对应一个数据库事务。)
3.Session接口:负责保存.更新.加载和查询对象,被称为持久化管理器
特点:1。不是线程安全的
2.。是轻量级的,是指创建和销毁不需要消耗太多的资源
注意:Session有一个缓存,被称为Hibernate的一级缓存,它用来存放当前工作单元加载的对象。每个session实例都有自己的缓存,这个session实例的缓存只能被当前工作单元锁使用
4.Transaction:管理事务。是hibernate的数据库事务接口,它对底层的事务接口做了封装,这些递呈的事务接口包括:
1。JDBCAPI
2。JTA(Java Transaction API)
3.CORBA(Common Object Requet Broker Architecture)API
5.Query和Criteria:执行数据库查询.Qurey包装了一个HQl查询语句,Criteria接口封装了基于字符串形式的查询语句,擅长执行动态的查询
Hibernte核心接口的类框图
2.4.2时间处理接口
当程序通过hibernate来加载.保存.跟新和删除对象时,会触发Hibernate的拦截器及事件监听器做出的恶性一处理:
1.事件及事件监听接口:在HibernateAPI,针对每一种事件都有相应的事件监听器,如加载对象会触发org.hibernate.event.LoadEven事件,该事件有org.hibernate.event.LoadeventListener监听器处理。保存对象触发org.hibernate.event.SaveEvent事件,该事件由org.hibernate.event.SaveEventListener监听器处理
2.org.hibernate.Interceptor接口:应用程序可以定义实现Interceptor接口的类,Interceptor实现类负责响应持久化类的实例被加载.保存更新或者删除的事件。
2.4.3映射类型接口
org.hibernate.type.Type接口表示Hibernate映射类型,用于把域对象映射为数据库的关系数据。Hiberante为Type接口提供了各种实现类:
1.PrimitiveType类型:映射java的基本类型:ByteType。shortType。IntegerType。LongType。
FloatType。DoubleType。characterType和BooleanType这八个类
2.DateType:映射Java日期类型
3.BinaryType:硬塞Byte[]