O/R Mapping基础

O/R Mapping基础

1、模型

1)模型用来表示真实世界的实体

在科学和工程技术领域,模型是一个很有用途的概念,它可以用来模拟一个真实的系统。在软件开发领域,模型用来表示真实世界的实体。

2)不同类型的模型

在软件开发的不同阶段,需要为目标系统创建不同类型的模型。

l         在分析阶段----需要创建概念模型

l         在设计阶段----需要创建域模型和数据模型

ü         其中,域模型是面向对象的,数据模型是面向关系的

ü         域模型和数据模型之间存在一种对象-关系映射。

 

3)概念模型

l         概念模型清楚地显示了问题域中的实体

不管是技术人员还是非技术人员都能看得懂概念模型,他们可以很容易地提出模型中存在的问题,帮助分析人员及早对模型进行修改。

在软件设计域开发周期中,模型的变更需求提出得越晚,所耗费得开发成本就越大。

l         概念模型描述了每个实体的概念和属性,以及实体之间的关系:一对一、一对多和多对多

在现实生活中都可以找到相应的例子,例如一只母鸡有很多小鸡是一对多关系,一位客户选购了很多商品,而这些商品也可以被许多客户选购,这是多对多关系。

4)关系数据模型

    到目前为止,关系数据库仍然是使用最广泛的数据库,它存储的是关系数据。关系数据模型是在概念模型的基础上建立起来的,用于描述这些关系数据的静态结构,它由以下内容组成:

l         一个或多个表

l         表的所有索引

l         视图

l         触发器

l         表与表之间的参照完整性

5)域模型

    域模型由以下内容组成:具有状态和行为的域对象;域对象之间的关系。

2、域对象

1)实体域对象

代表人、地点、事物或概念。通常,可以把业务领域中的名词,例如客户、订单、商品,当然也包括前面提到过的母鸡,作为实体域对象;

2)过程域对象

代表应用中的业务逻辑或流程。它通常依赖于实体域对象。

3)事件域对象

代表应用中的一些事件,例如异常、警告或超时等。

 

3、域对象之间的关系

    在域模型中,类之间存在下面下面的的几种关系。

1)关联(Association)

关联指的是类之间的引用关系(它使一个类指到另一个类的属性),这是实体域对象之间最普遍的一种关系。关联可以分为一对一、一对多和多对多关联。

2)依赖(Dependency)

依赖指的是类之间的访问关系。如果类A访问类B的属性或方法,或者说是A负责实例化B,那么可以说类A依赖类B。

依赖对象通过调用被依赖对象的方法来获得服务。一种比较松散的关系,并且是短期的。我们的业务处理过程与对象往往依赖于我们的实体域对象。如在struts 的 action中调用模型层的方法。

3)聚集(Aggregation)

聚集指的是整体与部分之间的关系,在实体域对象之间也很常见。其实聚合关系是关联关系的一种,是强的关联关系。聚合同时也体现整体和部分之间的关系。

例如,人与手就是聚集关系,在Person类中由一个hands集合,它存放被聚集的Hand对象:

public class Person

{

      private Set hands = new HashSet();

      …………

}

4)组合

也叫合成关系,组成关系是关联关系的一种,是比聚合关系强的关系。对象负责代表部分的对象的生命周期。

5)一般化(Generalization)

    一般化指的是类之间的继承关系。

4、既然聚合,组合关系属于关联关系,那么如何区分一般关联关系,聚合关系和组合关系呢?

1)一般关联

只要一个对象联系到另外一个对象就形成了关联关系。如:人和他的猫,黑豹乐队和窦魏,pc机和显示器。

2)聚合关系

一种强关联关系,它要求有部分和整体的关系,并且没有了整体,部分也可以独立存在。

在上面例子中人和它的猫显然没有部分和整体的关系,所以只能是一般的关联关系。而黑豹乐队和窦魏,窦魏等人组成,了黑豹乐队即:窦魏和黑豹是整体和部分的关系。而窦魏脱离了黑豹(早就离开了)更或者黑豹不存在了那么窦魏仍然可以以音乐人的身份存在(即对象仍然可以独立存在)所以它属于聚合关系。

组成关系是可以共享的。(窦魏也可以加入其他乐队)。

3)组合关系

一种更强的整体和部分的关系。它并且要求代表整体的对象负责代表部分的对象的生命周期,组成关系是不能共享的。如:pc机和显示器的关系。

4)注意的问题

如果两个实体是整体和部分的关系,那么它们到底是聚合还是组合,这取决于你的需求。比如说:pc机和显示器的关系,如果你的系统中,显示器脱离了pc机就不存在意义了也可以说:所有显示器的访问都是通过pc机进行的,那么你可以把关系设定为组合(如你在为一个只买品牌机的代理商作系统你可能是可以这么作的)。

如果你的显示器脱离的pc机仍然可以独立存在,也就是说在系统中可以直接访问显示器对象,那么你可以将关系设为聚合(如你在为一个买散件的代理商作系统你可能是可以这么作的)

 

5、域对象的持久化概念

1)什么是持久化

     狭义的理解,“持久化”仅仅指把域对象永久保存到数据库中;广义的理解,“持久化”包括和数据库相关的各种操作。

2)为什么要进行持久化

当实体域对象在内存中创建后,它们不可能永远存在。最后,他们要么从内存中清除,要么被持久化到数据存储库中。内存无法永久地保存数据,因此必须对实体域对象进行持久化。否则,如果对象没有被持久化,用户在应用运行时创建地订单信息将在应用结束运行后随之消失。

3)什么域对象需要持久化

当然,并不是所有的域对象都需要持久化,通常只有实体域对象才需要持久化,另外,有些实体域对象也不需要持久化。

4)持久化类

持久化类是指其实例需要被Hibernate持久化到数据库中的类。持久化类通常都是域模型中的实体域类,同时持久化类符合JavaBean的规范,包含一些属性,以及与之对应的getXXX()和setXXX()方法。

6、数据访问有哪些模式

1)业务逻辑层包含了业务数据和业务过程

l         实体域对象

在分层的软件结构中,业务逻辑层代表了业务数据和业务逻辑。域对象位于业务逻辑层,实体域对象代表应用运行时的业务数据,它存在于内存中,并借助于数据库实现用于存放永久性的业务数据。

业务数据在内存中表现为实体域对象形式,而在关系数据库中表现为关系数据形式。数据访问代码负责把实体域对象持久化到关系数据库中。

l         过程域对象

过程域对象代表应用的业务逻辑。

2)数据访问模式----业务逻辑和数据访问耦合

在此种模式种的过程域对象中,业务逻辑和数据访问代码混杂在一起,参见下图。

3)数据访问模式----主动域对象模式

由实体域对象负责自身的数据访问细节,这种实体域对象也被称为主动域对象,参见下图种的说明。J2EE平台中的BMP  EJB组件就是采用主动域对象模式的一种应用示例。

4)数据访问模式----ORM模式

在此种模式中,采用在单独的持久化层由ORM中间件封装数据访问细节,参见下图。而ORM中间件提供对象---关系映射服务,当向数据库保存一个域对象时,把业务数据由对象形式映射为关系数据形式;当从数据库加载一个域对象时,把业务数据由关系数据形式映射为对象形式。

5)数据访问模式---- JDO模式

Java Data ObjectsJDO)是SUN公司制定的描述对象持久化语义的标准API。因此采用JDO模式时,整个应用为四层应用结构,参见下图所示。

严格的说,JDO并不是对象-关系映射接口,因为它支持把对象持久化到任意一种存储系统中,包括: 关系数据库和面向对象的数据库。

 

6)数据访问模式----CMP模式

J2EE架构中,CMPContainer-managed Persistence)表示由EJB容器来管理实体EJB的持久化,EJB容器封装了对象-关系的映射以及数据访问细节。

CMPORM的相似之处在于,两者都提供对象-关系映射服务,都把对象持久化的任务从业务逻辑程序中分离出来;区别在于CMP负责持久化实体EJB组件,而ORM负责持久化POJO,它是普通的基于Java Bean形式的实体域对象。

CMPORM相比,前者有以下不足:

l         开发人员开发的实体EJB必须遵守复杂的J2EE规范,而多数ORM中间件不强迫域对象必须满足特定的规范。

l         实体EJB只能运行在EJB容器中,而POJO可以运行在任何一种Java环境中。

l         目前,对于复杂的域模型,EJB容器提供的对象-关系映射能力很有限。相比之下,许多ORM中间件提供了完善的对象-关系映射服务。

l         尽管按照J2EE的规范,EJB应该是一种可移植的组件,实际上却受到很大限制。因为不同厂商生产的CMP引擎差异很大,它们使用的对象-关系映射元数据各不相同,使得EJB不能顺利的从一个EJB容器移植到另一个EJB容器中。

使用ORM中间件就不存在这样的问题,以Hibernate为例,它可以无缝集成到任何一个Java系统中。在Java软件架构领域,在出现基于CMP的实体EJB之前,基于JavaBean形式的实体域对象早就存在了。但是把基于JavaBean形式的实体域对象称为POJO,却是最近才发生的事。

POJOPlain Old Java Object----又普通又古老的Java对象),它和基于CMP的实体EJB相比,既简单,又具有很高的可移植性,因此联合使用ORM映射工具和POJO,已经成为一种越来越受欢迎的,用于取代CMP的持久化方案。

 

7Java平台中的各种数据持久化技术

大多数应用程序都需要处理数据。Java应用程序运行时,往往把数据封装为相互连接的对象网络,但是当程序结束时,这些对象就会消失在一团逻辑中,所以需要有一些保存它们的方法。

有时候,甚至在编写应用程序之前,数据就已经存在了,所以需要有读入它们和将其表示为对象的方法。手动编写代码来执行这些任务不仅单调乏味、易于出错,而且会占用整个应用程序的很大一部分开发工作量。

1JDBC

大多数Java开发员都是用JDBC来和数据库进行通信,它可以通过DAO(Data Access Object)模式来进行改善和提高,然而,这种方式在大型应用程序中则会造成维护的"高消费"JDBC 提供了还算不错的数据库抽象,但是需要用痛苦的API。这些问题包括:

l         需要冗长的错误处理代码来确保ResultSetsStatements以及(最重要的)Connections在使用后关闭。这意味着对JDBC的正确使用可以快速地导致大量的代码量。它还是一个常见的错误来源。Connection leak可以在有负载的情况下快速宕掉应用程序。

l         SQLException相对来说不能说明任何问题。JDBC不提供异常的层次,而是用抛出SQLException来响应所有的错误。找出到底哪里出错了——例如,问题是死锁还是无效的SQL?——要去检查SQLState或错误代码。这意味着这些值在数据库之间是变化的。

2EJB

据调查EJB通常是在数据持久技术上的第二个选择,它是通过EntityBeans来对数据进行持久化。但我们首先必须购买一个价位合理的EJB容器--J2EE应用服务器;

其次全面采用EntityBean需要花“大量”的时间来理解EJB规范。在采用EJB之前你通常想在熟练掌握它的API

再有就是,你需要知道在每一个容器除了ejb-jar.xml以外所专有的部署描述符。对于JAVA开发员,在EJB中实现JDBC也比较复杂。

EJB中最为被关注的可能是无状态的会话BEAN(stateless-Session beans)和消息驱动BEAN(messaging driver beans)

3Hibernate技术

如何实现使这些工作自动化?如果每一种数据库管理系统都有它自己的方言,我们如何达到可移植性?答案是使用Hibernate技术

Hibernate技术的目标是成为Java中管理持续性数据问题的一种完整的解决方案。它协调应用与关系数据库的交互,让开发者解放出来专注于手中的业务问题。

Hibernate是一种非强迫性的解决方案。我们的意思是指在写业务逻辑与持续性类时,不会被要求遵循许多Hibernate特定的规则和设计模式。这样,Hibernate就可以与大多数新的和现有的应用平稳地集成,而不需要对应用的其余部分作破坏性的改动。

8ORM技术

1)什么是ORM?

简单地说,对象-关系映射就是Java应用中的对象到关系数据库中的表的自动的(和透明的)持续化,使用元数据对对象与数据库间的映射进行了描述。本质上,ORM的工作是将数据从一种表示(双向)转换为另一种。

2)ORM解决方案有以下四部分组成

l         在持续类的对象上执行基本的CRUD操作的一组API。

l         用于指定查询的一种语言或一组API,这些查询会引用类和类属性。

l         用于指定映射元数据的工具。

l         实现ORM的一项技术,用来与事务对象交互以完成脏检查、懒关联存取和其它优化功能。


O/R Mapping工具----Hibernate技术基础

 

1Hibernate基本概念

1Hibernate技术本质上是一个提供数据库服务的中间件

l         Hibernate 是一个面向Java 环境的对象/ 关系数据库映射工具,把Java类对应到数据库的table中,并且采用了xml技术、Java Reflection技术等。

l         Hibernate技术本质上也是遵守的ODMG标准的,它的出色源于不断的升级、不断的维护、修改。以及完善的文档、人气很旺的论坛。还有很重要的一点就是它的易学易用性。

l         Hibernate它不仅提供了从Java类到数据表的映射,也提供了数据查询和恢复等机制。可以大幅度减少开发时人工使用SQL JDBC 处理数据的时间。

2Hibernate是一个开放源代码的对象关系映射框架

l         OO的方式来操纵数据库

它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。

l         Hibernate可以应用在任何使用JDBC的场合

Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序实用,也可以在Servlet/JSPWeb应用中使用,最具革命意义的是,Hibernate可以在应用EJBJ2EE架构中取代CMP,完成数据持久化的重任。

    try

        {

           stmt=con.createStatement();

           rs=stmt.executeQuery("select * from  student");

           metaData = rs.getMetaData();

           for(int column = 0; column < metaData.getColumnCount(); column++)

            {

                System.out.print(metaData.getColumnName(column+1)+"/t");

椭圆形标注: 我们都写过这样的JDBC代码             }              

            System.out.println("");            

            while(rs.next())

            {

                for (int i = 1; i <= metaData.getColumnCount(); i++)

                {

                    System.out.print(rs.getObject(i)+"/t");

                }                  

                System.out.println("");

            }

           stmt.close();   //must close

           con.close();

        }

        catch(SQLException e)

        {

        }

3)主要的特点及与Entity EJB Bean的不同点

l         Hibernate是一个可以与Entity Bean同台较劲的技术,能够提供强大的Object/Relational Mapping能力,不需要透过任何J2EE的容器(Container),就能为我们提供Entity Bean的功能,但是又沒有Entity Bean的高复杂度。

l         实际上Hibernate与诸如EJB容器这样的环境在持久层实现的方式上有很大的不同。我们的持久类可以用在与容器无关的环境中,不像EJB必须要有某种EJB容器并且依赖该容器才能执行

注意:

无论是基于CMP的实体EJB,还是基于BMP的实体EJB,它们的共同特点是都必须运行在EJB容器中。而Hibernate支持的持久化类不过是普通的Java类,它们能够运行在任何一种Java环境中。

l         可以看出Hibernate 的最大特点就是数据持久化。

4)应用层和持久层的关系

l         持久(Persistence)。简单来讲,也就是把数据保存到可掉电式存储设备中供之后使用。

l         所谓“持久层”,也就是在系统逻辑层面上,专注于实现数据持久化的一个相对独立的领域(Domain)。

l         我们一般将应用层放在持久层的上部,实际上在传统的项目中,应用层充当着持久层的一个客户端角色。但对于一些简单的项目来说,应用层和持久层并没有区分得那么清楚,在这种情况下可以将应用层和持久层合并成为一层。

5)持久层设计与解耦合

l         何谓耦合:通俗地讲,就是事物之间的相互关联关系。

l         何谓解耦合:即采用一些手段降低关联的紧密程度。

l         解耦合设计的目标

ü         应用层解耦合――应用逻辑与数据逻辑相分离

ü         资源曾解耦合――逻辑结构与物力结构相分离

6)利用Hibernate技术不仅提高了编码的效率,同时也提高了数据库访问性能优化

l         提高了编码的效率

Hibernate是一个ORM工具,它不仅仅是实现了数据库访问性能优化和与数据库交互的常用操作(CRUD),还将数据表与对象进行了关联,让我们可以脱离数据表,而直接针对对象来与数据库交互,我们不再需要用字符串去描述表中字段,不再需要一个个”+“号去 组装Sql语句。这使得编码中可书写性提高。

l         提高了数据库访问性能优化

同时也不需要我们考虑与数据库交互的性能问题,如连接池、数据缓存等等

2、为什么要使用Hibernate工具

1)为应用系统提供统一的一致的数据库访问操作

l         JDBC技术

在常规的Java应用系统中的数据库访问技术使用的是JDBC并且进行JDBC编程。当项目越来越大时,觉得JDBC到处建立连接,或者使用直接的sql语句,修改或者项目变更起来很不方便;于是产生了数据访问的程序的应用需求,所有的数据访问都通过这个程序转换为JDBC的代码来访问数据库。

l         使用Hibernate API访问数据库

下图的左面是通过JDBC API访问数据库,而右图则是通过Hibernate API访问数据库。

             

l         使用Hibernate API访问数据库的基本的过程

首先应该在应用的启动阶段对Hibernate进行初始化,然后就可以通过HibernateSession接口来访问数据库。

l         优点

这种技术的采用确实给开发工作带来了十分的改观,所有的对数据库的操作变成了对某个对象的操作,并且采用Java语言特有的Reflection机制,动态的取得某个JavaBean的属性,然后对应到(mapping)某个数据库的表中,这样,客户端的代码就变得非常简单。

2Hibernate 的最大特点就是数据持久化

l         提高开发效率

Hibernate 不仅仅管理Java 类到数据库表的映射,还提供数据查询和获取数据的方法,可以大幅度减少开发时人工使用SQL JDBC 处理数据的时间;同时Hibernate封装了数据库访问、事务管理、数据缓存等工作。省去了自己去编写这些代码。

l         可以看出Hibernate 的最大特点就是数据持久化。

3)不用写一句SQL语句,甚至不需要懂得SQL语言!

在应用Hibernate时,只要我们定义好了持久类与数据库中表字段的对应关系,Hibernate会自动帮你生成SQL语句来对持久类对象进行插入、更新、删除、查找工作,你可以不写一句SQL语句,甚至不需要懂得SQL语言!

l         传统的数据库访问代码

insert into table (field_1,field_2,field_n) values('"+ field_value1 +"','" + field_value2 + "','" + field_value3 + "'")

l         借助Hibernate后数据库访问代码

session.save(table_Object)

 

由代码比较可以看出,数据表可以跟对象一样被操作,这样代码显得更加简洁,可读性也增强。在实际开发中,这里是业务变动 频繁的地方,保证代码的可读性和易维护,很有价值。

4)支持各种主流的数据源

目前所支持数据源包括:HypersonicSQLPostgreSQLDB2MySQLOracleSybaseMckoi SQLSAP DBMS SQL ServerJSQL DriverJTURBO DriverWebLogic Driver、纯Java驱动程序等。

5)Hibernate的一些弱点

Hibernate作为流行的企业应用和关系数据库之间的持久化中间件,受到越来越多的关注。虽然使用Hibernate可以使得项目易于维护,帮助开发人员更好地处理复杂关系模型,提供了很强的方便性,但却失去了JDBC原有的灵活性。如何在“灵活”与“方便”之间取舍、平衡显得重要起来。

主要体现在比如对象关系的映射配置过多,控制复杂;事务处理面临各种兼容问题;HQL语言增加学习成本等。也就是“灵活”的背后隐藏着“复杂”,“方便”的背后隐藏着“不便”,如何取舍与平衡,还是看实际需要。

l         提取表单中字典Value的不便。

    字典一般由ID和NAME两个字段组成,其ID号存储于数据库其他表中,当查询这些表信息时,Hibernate以List或Set形式返回的结果,没有办法将ID号显示为对应的NAME。在JDBC中,可以直接通过Map来存储字典,通过map.getValue()来返回字典的值。

 

l         Hibernate内置映射类型复杂化

    在开发过程中,时常会查找Hibernate映射类型--Java类型--标准SQL类型之间的关系。繁杂之处体现在两方面,一是各种数据库的数据类型和标准SQL之间会有一定的出入,二是Hibernate映射类型虽然大部分和Java类型相同,但也存在比较晦涩的地方,例如character类型对应Java的char / java.lang.Character / java.lang.String,text对应着Java的java.lang.String。

 

l         ID规定化生成

    Hibernate中内置标识符生成器给表单ID自动生成提供了方便,但却不能自定义各种ID形式。

3Hibernate系统

其实Hibernate本身是个独立的框架,它不需要任何web serverapplication server的支持。

1Hibernate的设计者Gavin King

Gavin KingHibernate的作者,EJB3.0专家委员会成员,JBoss核心成员之一。Hibernate诞生在200111月。Gavin King 1974年出生于澳大利亚,现在居住在澳大利亚默尔本市。

 

2)下载

hibernatesourceforge的一个子项目,我们可以从Hibernate 的网站http://www.hibernate.org/Hibernate 的中文网站是http://www.hibernate.org.cn/)或者http://hibernate.sourceforge.net上面获得下载的连接。

3)架构

l         上图显示了hibernate的工作原理

它是利用数据库以及其他一些配置文件如hibernate.properties,XML Mapping等来为应用程序提供数据持久服务的。

l         Hibernate是Java应用和关系数据库之间的桥梁

它负责Java对象和关系数据之间的映射。Hibernate内部封装了通过JDBC访问数据库的操作,向上层应用提供了面向对象的数据访问API。

4)“轻型”的体系结构方案

由于Hibernate非常灵活,且支持数种应用方案,。“轻型”的体系结构方案,要求应用程序提供自己的JDBC 连接并管理自己的事务。这种方案使用了Hibernate API的最小子集。

5)“全面解决”的体系结构方案

它是将应用层从底层的JDBC/JTA API中抽象出来,而让Hibernate来处理这些细节。

6)几个主要的工具功能

l         hbm2java是根据映射文件自动生成java源文件

l         hbm2ddl 是根据映射文件自动生成数据库schema

l         XDoclet 根据带有XDoclet的标记的java源文件生成映射文件

l         Middlegen 根据数据库Schema自动生成映射文件

4、Hibernate API中包含的一些主要的类

1)Hibernate的接口大致可以分为以下几种类型:

l         一些被用户的应用程序调用的,用来完成基本的创建、读取、更新、删除操作以及查询操作的接口。这些接口是Hibernate实现用户程序的商业逻辑的主要接口,它们包括Session、Transaction和Query等。

l         Hibernate用来读取诸如映射表这类配置文件的接口,典型的代表有Configuration类。

l         回调(Callback)接口。它允许应用程序能对一些事件的发生作出相应的操作,例如Interceptor、Lifecycle和Validatable都是这一类接口。

l         一些可以用来扩展Hibernate的映射机制的接口,例如UserType、CompositeUserType和IdentifierGenerator。这些接口可由用户程序来实现(如果有必要)。

  Hibernate使用了J2EE架构中的如下技术:JDBC、JTA、JNDI。其中JDBC是一个支持关系数据库操作的一个基础层;它与JNDI和JTA一起结合,使得Hibernate可以方便地集成到J2EE应用服务器中去。

2)Hibernate一共包括了几十个jar包,令人眼花缭乱

下文将讲解Hibernate主要的jar包的作用,便于你在应用中根据自己的需要进行取舍。

l         SessionFactory (net.sf.hibernate.SessionFactory):包含已经编译的映射(mappings),是制造session的工厂,可能含有一些可以在各个事务(transaction)之间共享的数据。

l         Session (net.sf.hibernate.Session) :单线程的,短寿命的对象,代表了一次会话的过程。实际上是把一个JDBC Connection打包了,它可以包含一些持久化对象的缓存。

l         Persistent Objects and Collections:单线程的,短寿命的对象,包含了各种属性字段以及一些商业逻辑,它们可能仅仅是一些普通的javabeans,但是它必然在某个时刻只能和一个session相关联。

5、有关Hibernate的中文资源

1)中文论坛(http://www.hibernate.org.cn

Hibernate中文论坛是中国最早的Hibernate专业用户论坛,为Hibernate在中国的推广做出了巨大的贡献,目标是成为一个高品质的,有思想深度的、原创精神的Java技术交流网站,为软件从业人员提供一个自由的交流技术,交流思想和交流信息的平台。

2)中文参考书

《深入浅出Hibernate》是国内第一本围绕Hibernate3进行讲解的技术书籍。

 

6、Hibernate的应用场合---Hibernate可以配置成可在任何Java环境中运行

Hibernate可以配置成可在任何Java环境中运行,一般说来,它通常被用在2-3层的C/S或者B/S模式的项目中,并被部署在服务端。

在这种项目中,Web浏览器、或Java GUI程序充当者客户端。尽管我们的焦点主要是集中在多层Web应用,但实际上在一些基于命令行的应用中也可以使用Hibernate。

 

7、Hibernate运行在两种环境下:受管理环境(Managed environment)和不受管理环境(Non-managed enviroment)

1)受管理环境――应用系统的整个执行过程在容器的控制之下

此时容器可为应用系统管理如下资源:池资源管理,诸如数据库连接池、还有事务管理、安全定义。一些典型的J2EE服务器(JBoss、Weblogic、WebSphere)已经实现了这些。

2)不受管理环境――应用系统的整个执行过程不在容器的控制之下

由应用本身负责管理数据库连接、定义事务边界以及管理安全。独立的桌面应用或命令行应用都运行在不受管理环境中。Servlet容器会负责管理线程池,有些Servlet容器,如Tomcat,还会管理数据库连接池,但是Servlet容器不会管理事务,因此它提供的仍然是不受管理的运行环境。

3)Hibernate允许Java应用在不同的环境中移植

Java应用从一个环境移植到另一个环境中时,只需要修改Hibernate的配置文件,而不需要修改或者只需要修改极少量的Java源代码。

8、如何学习Hibernate

1)Hibernate文档

Hibernate文档处处都是持久层设计的经验和最佳实践。Hibernate文档准确的来说,绝大部分内容都在讲对象的持久层设计,而不是简单的Hibernate使用。

2)学习要点

l         所以学习Hibernate,主要是在学习持久层的设计模式,如果你把Hibernate文档都看完了,还整天只会提那些 Hibernate的配置问题,Hibernate的类调用问题,我觉得这样的人还没有真正的入门,算是白学了

l         在学习Hibernate的时候即集中所有精力来理解Hibernate的运行原理,集中精力来掌握持久层设计应该把握的原则和技巧,这些才对我是最重用的东西----而如果在学习Hibernate时间,主要侧重于怎么配置,用工具怎么生成hbm文件,如果你把重点放在这里,基本上等于白学了Hibernate。

因为,如果这样进行学习,学习完Hibernate,肯定会对JDBC的编程也提高了一大截,更不要说对于J2EE架构的持久层的框架设计,基本上是了然于胸了,即使将来换了API,不用Hibernate的,改用JDO,Castor什么的,这些经验一样照用。

 

3)Hibernate的精华:在于无与伦比的灵巧的对象持久层设计

这些持久层设计经验不会因为你不用Hibernate而丧失掉,我自己学习Hibernate,已经明显感觉到对持久层设计能力已经长了很多经验值了,这些经验甚至不光可以用在Java上,用在.net上也是一样。

因为,不管JDO也好,Hibernate也好,TopLink也好,CocoBase也好,还是Castor,还是什么Torque,OJB,软件的使用和配置方法可以各异,但本质上都是ORM,都是对JDBC的对象持久层封装,所以万变不离其宗。

9、持久化生命周期

1)持久化类的实例的生命周期状态

对于持久化生命周期,不同的ORM 实现使用不同的术语,定义不同的状态及状态转换。Hibernate 仅仅定义了三种状态:瞬时、持久和脱管,对客户端代码隐藏了其内部实现的复杂性。

一个持久化类的实例可能处于三种不同状态中的某一种。这三种状态的定义则与所谓的持久化上下文(persistence context)有关---而 Hibernate的Session对象就是这个所谓的持久化上下文。

当应用程序通过new语句创建了一个对象,这个对象的生命周期就开始了,当不再有任何引用变量引用它,这个对象就结束生命周期,它占用的内存就可以被JVM的垃圾回收器回收。对于需要被持久化的Java对象,在它的生命周期中,可处于以下三个状态之一。下面是三种状态的切换过程:

从图中可以看出,Session的特定方法触发Java对象由一个状态转换到另一个状态;当Java对象处于临时状态或游离状态,只要不被任何变量引用,就会结束生命周期,它占用的内存就可以被JVM的垃圾回收器回收;当处于持久化状态,由于Session的缓存会引用它,因此它始终处于生命周期中。

2)瞬态(transient,临时)

l         瞬时对象

Hibernate中,使用new 操作符初始化的对象(或者使用Session的delete方法使游离态,持久化的对象也转变为临时状态)不是立刻就是持久的。它们的状态是瞬时的,也就是说它们没有跟任何数据库表的行相关联,只要应用不再引用这些对象(不再被任何其它对象所引用),它们的状态将会丢失。这时,那些对象的生命期将会有效地终止,变得不可访问,交给垃圾回收机制来回收。

l         特点

它也称为临时对象 ----不处于session的缓存中,不和任何的session实例关联,数据库中无记录。该实例从未与任何持久化上下文关联过。它没有持久化标识(相当于主键)。 例如:

Order order = new Order();  

l         瞬时实例都是非事务的

Hibernate 认为所有的瞬时实例都是非事务的,瞬时实例状态的修改不能在任何事务的上下文中执行。这就意味着Hibernate 不能对瞬时对象提供任何回滚功能----实际上Hibernate 不回滚任何对象所做的修改。

l         如何将对象从瞬时状态转换为持久状态

默认地,仅仅被其他瞬时实例引用的对象也是瞬时的。把实例从瞬时状态转换为持久状态有两种方式:调用持久管理器的save()方法或者从已经存在的持久实例中创建引用。

3)持久(persistent)

l         持久实例

持久实例是任何具有数据库标识的实例,也就是持久实例有一个主键值设为数据库标识符。

l         特点

ü         持久实例目前与某个持久化上下文有关联

它拥有持久化标识(相当于主键),并且可能在数据库中有一个对应的行(位于session的缓存中,总是被一个session实例关联,和数据库中记录对应)。

ü         持久实例通常是同Session相关的,是事务的

持久实例是在事务中进行操作的—它们的状态在事务结束时同数据库进行同步。当事务提交时,通过执行SQL的INSERT、UPDATE和DELETE语句把内存中的状态同步到数据库中。

l         如何将对象转变为持久实例

对于某一个特定的持久化上下文,Hibernate保证持久化标识与Java标识(其值代表对象在内存中的位置)等价。

ü         session的save方法使临时态变为持久化

ü         session的load,get方法返回对象总是处于持久化状态

ü         session的find方法返回list存放的都是持久化对象

ü         session的update,saveOrUpdate,lock方法使游离态转换为持久态对象

ü         一个持久化对象和临时对象有级联保存的时候session在清空缓存的时候会把临时对象转化为持久对象

l         注意点

持久实例通过调用持久管理器API 的delete()方法使其变成瞬时的,导致删除数据库中相应的行。

4)脱管(detached或者称为“游离态)

l         脱管对象

Hibernate 中,当实例曾经与某个持久化上下文发生过关联,不过那个上下文Session被关闭了, 或者这个实例是被序列化(serialize)到这个进程来的----不位于session的缓存中,不被session关联,数据库中可能有记录。

l         特点

它拥有持久化标识,并且在数据库中可能存在一个对应的行。

l         转换的方法

session的close方法使缓存清空,缓存中的所有持久化对象变为游离态

l         注意点

对于脱管状态的实例,Hibernate不保证任何持久化标识和Java标识的关系。

 

10、Hibernate中的核心接口API类的介绍--- Session接口

  以下的各个个核心接口几乎在任何实际开发中都会用到。通过这些接口,你不仅可以存储和获得持久对象,并且能够进行事务控制。

椭圆形标注: 如果对象占用的内存空间很小,就称为轻量级对象 1)它是轻量级的类

l         轻量级的类

对于Hibernate 开发人员来说它是一个最重要的接口。然而在Hibernate中,实例化的Session是一个轻量级的类,创建和销毁它都不会占用很多资源。这在实际项目中确实很重要,因为在客户程序中,可能会不断地创建以及销毁Session对象,如果Session的开销太大,会给系统带来不良影响。

l         是非线程安全的

但值得注意的是Session对象是非线程安全的,因此在你的设计中,最好是一个线程只创建一个Session对象。

2)Session看作介于数据连接与事务管理一种中间接口

l         是一种中间接口

Hibernate的设计者的头脑中,他们将session看作介于数据连接与事务管理的一种中间接口。我们可以将session想象成一个持久对象的缓冲区,Hibernate能检测到这些持久对象的改变,并及时刷新数据库。

l         每一个Session实例和一个数据库事务绑定

通常将每一个Session实例和一个数据库事务绑定,也就是说,每执行一个数据库事务,都应该先创建一个新的Session实例。如果事务执行中出现异常,应该撤销事务。不论事务执行成功与否,最后都应该调用Sessionclose()方法,从而释放Session实例占用的资源。

3)如何获得Session对象

l         首先创建SessionFactory对象

应用程序如果访问多个数据源时,则应该产生多个SessionFactory;但是仅仅为了服务于某个请求你不要创建一个新的SessionFactory,因为创建SessionFactory 需要耗费大量的资源。

l         然后根据SessionFactory再创建Session对象

Session session = sessionFactory.openSession();

  Transaction tx;

  try

  {  //开始一个事务

     tx = session.beginTransaction();

     //执行事务

     ...

     //提交事务

     tx.commit();

 }

 catch (Exception e)

{   //如果出现异常,就撤销事务

     if (tx!=null)

{

 tx.rollback();

}

     throw e;

 }

 finally

{   //不管事务执行成功与否,最后都关闭Session并且放在finally中以提高安全性

     session.close();

 }

4)Session同时也是一个持久层管理器

l         持久层管理器

我们有时也称Session是一个持久层管理器,因为它包含这一些持久层相关的操作,诸如存储持久对象至数据库,以及从数据库从获得它们。

l         持久管理器所提供的服务

ü         基本的CURD操作(save()方法:把Java对象保存数据库中、update()方法:更新数据库中的Java对象、delete()方法:把Java对象从数据库中删除、load()方法:从数据库中加载Java对象 和find()方法:从数据库中查询Java对象);

ü         执行查询;

ü         控制事务;

ü         事务级的缓存管理;

l         持久管理器所暴露的几个不同的接口

Hibernate 来说是----Session,Query,Criteria 和Transaction等接口。

l         所应该注意点

请注意,Hibernate 的session不同于JSP应用中的HttpSession。当我们使用session这个术语时,我们指的是Hibernate中的session,而我们以后会将HttpSesion对象称为用户session。

5)Session的编程规则---需要随时更新和释放

Session是一个轻量级对象。通常将每一个Session实例和一个数据库事务绑定,也就是说,每执行一个数据库事务,都应该先创建一个新的Session实例。如果事务执行中出现异常,应该撤销事务。

不论事务执行成功与否,最后都应该调用Session的close()方法,从而释放Session实例占用的资源。

 

6)Sessin 接口中的常用方法

l         save()方法:save() 和persist()方法产生SQL INSERT

session = HibernateUtil.currentSession();

      tx = session.beginTransaction();

      Book oneBook = new Book();     

 oneBook.setBookName(new String("J2EE应用开发".getBytes("gb2312"), "ISO8859-1"));

      oneBook.setBookKind('1');

      oneBook.setBookPrice(7.4f);

      session.save(oneBook);

      tx.commit();

l         Sessin 接口中的常用方法---- updata()和merge()方法产生SQL UPDATE

该方法调用Session的load()方法,加载Customer对象,然后再修改Customer对象的属性。

      session = HibernateUtil.currentSession();

      tx = session.beginTransaction();

      Book oneBook=(Book)session.load(Book.class,bookID);

 oneBook.setBookName(new String("Java应用开发".getBytes("gb2312"), "ISO8859-1"));

      oneBook.setBookKind('1');

      oneBook.setBookPrice(10.4f);

      tx.commit();

l         Sessin 接口中的常用方法---- load和get方法

session的load和get方法根据给定的OID从数据库中加载一个对象,load方法在没有找  到对象时抛出notFoundException异常,get方法返回null;

get和load和其他查询方法返回的对象位于session的缓存中,修改了对象的属性后,  session清理缓存时,会根据持久化对象的属性来更新数据库。

用来对数据库中检索对象,load()和get()方法按照给定的OID加载一个持久化对象

public Iterator getAllCourses()throws HibernateException

{

String queryString = "select courses from Course as courses";

beginTransaction();

Query query = session.createQuery(queryString);

Iterator it= query.iterate();

return it;

}

/**

*按course的名字进行模糊查找,返回的是包含有Course持久对象的Iterator。

*/

public Iterator getSomeCourse(String name)throws HibernateException

{

String queryString = "select c from Course as c where c.name like :name" ;

beginTransaction();

Query query = session.createQuery(queryString);

query.setString("name", "%"+name+"%");

Iterator it= query.iterate();

return it;

}

l         Sessin 接口中的常用方法---- delete()方法产生SQL DELETE

由于从数据库中删除对象对应的记录,如果出入的是持久化对象session就计划执行一个delete语句。

如果出入的参数是游离态对象,先使它成为持久化对象,然后计划执行一个delete语句。session只有在清理缓存的时候才会执行delete语句。只有当调用session的close()方法时才会从session的缓存中删除对象。

session = HibernateUtil.currentSession();

      tx = session.beginTransaction();

      Book oneBook=(Book)session.load(Book.class,bookID);

      session.delete(oneBook);

      tx.commit();

 

11、Hibernate中的核心接口API类的介绍---SessionFactory 接口

1)利用工厂类SessionFactory中取得Session的实例

这里用到了一个设计模式――工厂模式,用户程序从工厂类SessionFactory中取得Session的实例。

椭圆形标注: 如果对象的缓存很大,就称为重量级对象

 

2)SessionFactory并不是轻量级的

但要注意的是SessionFactory并不是轻量级的!实际上它的设计者的意图是让它能在整个应用中共享。

注意:

    由于Java语言是纯面向对象的语言,因此不可能像C语言那样直接操纵内存,例如声明一段可用的内存空间。以上所提到的缓存的概念其实指的是Java对象中的属性(通常是一些集合类型的属性)占用的内存空间。

 

3)只有一个数据存储源,只需创建一个SessionFactory

SessionFactory就是个重量级对象,如果应用只有一个数据存储源,只需创建一个SessionFactory实例,因为随意地创建SessionFactory实例会占用大量内存空间。

但是当你的项目要操作多个数据库时,那你必须为每个数据库指定一个SessionFactory。

 

4)SessionFactory的实现类

SessionFactory的实现类中定义了许多集合类型的属性,这些属性用于存放Hibernate配置信息、映射元数据信息等。

public final class SessionFactoryImpl implements SessionFactory, SessionFactoryImplementor {

    private final transient Map classPersisters;

    private final transient Map classPersistersByName;

    private final transient Map classMetadata;

    private final transient Map collectionPersisters;

    private final transient Map collectionMetadata;

    private final transient Map namedQueries;

    private final transient Map namedSqlQueries;

    private final transient Map imports;

    private final transient Templates templates;

    private final transient Interceptor interceptor;

    private final transient Settings settings;

    private final transient Properties properties;

    private transient SchemaExport schemaExport;

    private final transient TransactionManager transactionManager;

    private final transient QueryCache queryCache;

    private final transient UpdateTimestampsCache updateTimestampsCache;

    private final transient Map queryCaches;

    ……

}

5)SessionFactory的缓存

可分为两类:内置缓存和外置缓存。

SessionFactory的内置缓存中存放了Hibernate配置信息和映射元数据信息、同时也缓存了Hibernate自动生成的SQL语句等;

SessionFactory的外置缓存是一个可配置的缓存插件,在默认情况下,SessionFactory不会启用这个缓存插件。外置缓存能存放大量数据库数据的拷贝,外置缓存的物理介质可以是内存或者硬盘。

12、Hibernate中的核心接口API类的介绍---Configuration 接口

Configuration是hibernate的入口,在新建一个Configuration的实例的时候,hibernate会在classpath里面查找hibernate.properties文件,如果该文件存在,则将该文件的内容加载到一个Properties的实例GLOBAL_PROPERTIES里面,如果不存在,将打印信息:hibernate.properties not found

    然后是将所有系统环境变量(System.getProperties())也添加到GLOBAL_PROPERTIES里面。如果hibernate.properties文件存在,系统还会验证一下这个文件配置的有效性,对于一些已经不支持的配置参数,系统将打印警告信息。

1)作用---实现对Hibernate进行配置

l         Configuration接口的作用是对Hibernate进行配置,以及对它进行启动

Hibernate的启动过程中,Configuration类的实例首先定位映射文档的位置,读取这些配置,然后创建一个SessionFactory对象。

l         根据Configuration对象创建一个SessionFactory对象

为了能创建一个SessionFactory对象,你必须在Hibernate初始化时创建一个Configuration类的实例,并将已写好的映射文件交由它处理。这样,Configuration对象就可以创建一个SessionFactory对象,当SessionFactory对象创建成功后,Configuration对象就没有用了,你可以简单地抛弃它。

2)定义

3)它是启动hibernate的对象

虽然Configuration接口在整个Hibernate项目中只扮演着一个很小的角色,但它是启动hibernate时你所遇到的第一个对象。

4)编程示例

Configuration config = new Configuration();

config.addClass(Customer.class);

sessionFactory = config.buildSessionFactory();

或者:

    使用方法链编程风格,可以改写为:

sessionFactory = new Configuration()

.buildSessionFactory()

.addClass(Customer.class)

.buildSessionFactory();

 

注意:

方法链编程风格能使应用程序代码更加简捷。在使用这种编程风格时,最好把每个调用方法放在不同的行,否则在跟踪程序时,无法跳入每个调用方法中。

5)Configuration的其他用法

Configuration的configure ()方法还支持带参数的访问方式,你可以指定hbm.xml文件的位置,而不是使用默认的classpath下面的hibernate.cfg.xml这种方式,例如:

Configuration cfg = new Configuration().configure("myexample.xml");

 

13、Hibernate中的核心接口API类的介绍---Transaction 接口

1)Transaction接口是一个可选的API

事务将应用代码从下层的事务实现中抽象出来——这可能是一个JDBC事务,一个JTA用户事务或者甚至是一个公共对象请求代理结构(CORBA)——允许应用通过一组一致的API控制事务边界。

2)为什么要提供该Transaction 接口

Transaction接口是对实际事务实现的一个抽象。之所以这样设计是能让开发者能够使用一个统一事务的操作界面,使得自己的项目可以在不同的环境和容器之间方便地移值

 

14、Hibernate中的核心接口API类的介绍---Query和Criteria接口

1)Query接口

Query接口让你方便地对数据库及持久对象进行查询,它可以有两种表达方式:HQL语言或本地数据库的SQL语句。Query经常被用来绑定查询参数、限制查询记录数量,并最终执行查询操作。

值得注意的是Query接口也是轻量级的,它不能在Session之外使用。

Query query = session.createQuery("from Customer c where c.name =:name");

query.setParameter("name","tom",Hibernate.STRING);

2)Criteria接口

Criteria接口与Query接口非常类似,它允许你创建并执行面向对象的标准化查询。

15、Hibernate中的核心接口API类的介绍---其它的接口

1)Callback 方面的接口

当一些有用的事件发生时――例如持久对象的载入、存储、删除时,Callback接口会通知Hibernate去接收一个通知消息---它允许应用程序能对一些事件的发生作出相应的操作。

例如Interceptor、Lifecycle和Validatable都是这一类接口。一般而言,Callback接口在用户程序中并不是必须的,但你要在你的项目中创建审计日志时,你可能会用到它。

2)策略接口

l         高度的可扩展性

Hibernate与某些其它开源软件不同的还有一点――高度的可扩展性,这通过它的内置策略机制来实现。当你感觉到Hibernate的某些功能不足,或者有某些缺陷时,你可以开发一个自己的策略来替换它,而你所要做的仅仅只是继承它的某个策略接口,然后实现你的新策略就可以了。

l         以下是它的策略接口

ü         主键的生成 (IdentifierGenerator 接口)

ü         本地SQL语言支持 (Dialect 抽象类)

ü         缓冲机制 (Cache 和CacheProvider 接口)

ü         JDBC 连接管理 (ConnectionProvider接口)

ü         事务管理 (TransactionFactory, Transaction, 和 TransactionManagerLookup 接口)

ü         ORM 策略 (ClassPersister 接口)

ü         属性访问策略 (PropertyAccessor 接口)

ü         代理对象的创建 (ProxyFactory接口)

 

Hibernate为以上所列的机制分别创建了一个缺省的实现,因此如果你只是要增强它的某个策略的功能的话,只需简单地继承这个类就可以了,没有必要从头开始写代码。

16、一个重要的术语:Type

1)一个Type对象能将一个Java类型映射到数据库中一个表的字段中

l         Hibernate的设计者们发明了一个术语:Type,它在整个构架中是一个非常基础、有着强大功能的元素。一个Type对象能将一个Java类型映射到数据库中一个表的字段中去(实际上,它可以映射到表的多个字段中去)。

<hibernate-mapping>

    <class name="Event" table="EVENTS">

        <id name="id" column="EVENT_ID">

            <generator class="increment"/>

        </id>

        <property name="date" type="timestamp" column="EVENT_DATE"/>

        <property name="title"/>

    </class>

</hibernate-mapping>

l         它是Hibernate mapping types

并不像我们假想的那样,是Java data type, 同时也不是SQL database type。这些类型被称作Hibernate mapping types,它们把数据类型从Java转换到SQL data types。

l         持久类的所有属性都对应一个type

这种设计思想使用Hibernate有着高度的灵活性和扩展性。

2)关于缺省的type类型

如果映射的参数没有设置type类型,Hibernate也将尝试去确定正确的类型转换和它的映射类型。 在某些情况下这个自动检测(在Java class上使用反射机制)不会产生你所期待或者需要的缺省值----因此,最好我们来设定其类型。

上面的例子是关于date属性。Hibernate无法知道这个属性应该被映射成下面这些类型中的哪一个: SQL date,timestamp,time。 我们通过声明属性映射timestamp来表示我们希望保存所有的关于日期和时间的信息。

3)Hibernate内置的主要type类型

l         integer, long, short, float, double, character, byte, boolean, yes_no, true_false

这些类型都对应Java的原始类型或者其封装类,来符合(特定厂商的)SQL 字段类型。boolean, yes_no 和 true_false都是Java 中boolean 或者java.lang.Boolean的另外说法。

l         string

java.lang.String 到 VARCHAR (或者 Oracle的 VARCHAR2)的映射。

l         date, time, timestamp

java.util.Date和其子类到SQL类型DATE, TIME 和TIMESTAMP (或等价类型)的映射。

l         calendar, calendar_date

java.util.Calendar 到SQL 类型TIMESTAMP和 DATE(或等价类型)的映射。

l         big_decimal, big_integer

java.math.BigDecimal和java.math.BigInteger到NUMERIC (或者 Oracle 的NUMBER类型)的映射。

l         locale, timezone, currency

java.util.Locale, java.util.TimeZone 和java.util.Currency 到VARCHAR (或者 Oracle 的VARCHAR2类型)的映射. Locale和 Currency 的实例被映射为它们的ISO代码。TimeZone的实例被影射为它的ID。

l         class

java.lang.Class 到 VARCHAR (或者 Oracle 的VARCHAR2类型)的映射。Class被映射为它的全限定名。

l         binary

把字节数组(byte arrays)映射为对应的 SQL二进制类型。

l         text

把长Java字符串映射为SQL的CLOB或者TEXT类型。

l         serializable

把可序列化的Java类型映射到对应的SQL二进制类型。你也可以为一个并非默认为基本类型的可序列化Java类或者接口指定Hibernate类型serializable。

l         clob, blob

JDBC 类 java.sql.Clob 和 java.sql.Blob的映射。某些程序可能不适合使用这个类型,因为blob和clob对象可能在一个事务之外是无法重用的。(而且, 驱动程序对这种类型的支持充满着补丁和前后矛盾。)

4)示例

<id name="id" type="string" unsaved-value="null" >

            <column name="CAT_ID" sql-type="char(32)" not-null="true"/>

            <generator class="uuid.hex"/>

        </id>

注意:上面使用一个元素类型是 string(这里使用小写的名字是向你表明它是一个Hibernate的映射类型或者类型转换器)。

5)Java类型、Hibernate映射类型以及SQL类型之间的对应关系

 

Customer类的属性

Java类型

Hibernate映射类型

CUSTOMERS表的字段

SQL类型

name

java.lang.String

string

NAME

VARCHAR(15)

email

java.lang.String

string

EMAIL

VARCHAR(128)

password

java.lang.String

string

PASSWORD

VARCHAR(8)

phone

int

int

PHONE

INT

address

java.lang.String

string

ADDRESS

VARCHAR(255)

sex

char

character

SEX

CHAR(1)

married

boolean

boolean

IS_MARRIED

BIT

description

java.lang.String

text

DESCRIPTION

TEXT

image

byte[]

binary

IMAGE

BLOB

birthday

java.sql.Date

date

BIRTHDAY

DATE

registeredTime

java.sql.Timestamp

timestamp

REGISTERED_TIME

TIMESTAMP

6)Java类型、Hibernate映射类型以及SQL类型之间的对应关系应用示例

l         如果Customer类的属性为java.lang.String类型,并且与此对应的CUSTOMERS表的字段为VARCHAR类型,那么应该把Hibernate映射类型设为string,例如:

<property name="name" column="NAME" type="string" not-null="true" />

l         如果Customer类的属性为java.lang.String类型,并且与此对应的CUSTOMERS表的字段为TEXT类型,那么应该把Hibernate映射类型设为text,例如:

<property name="description" column="DESCRIPTION" type="text"/>

l         如果Customer类的属性为byte[]类型,并且与此对应的CUSTOMERS表的字段为BLOB类型,那么应该把Hibernate映射类型设为binary,例如:

<property name="image" column="IMAGE" type="binary"/>

l         如果没有显式设定映射类型,Hibernate会运用Java反射机制先识别出持久化类的属性的Java类型,然后自动使用与之对应的默认的Hibernate映射类型。

例如,Customer类的address属性为java.lang.String类型,与java.lang.String对应的默认的映射类型为string,因此以下两种设置方式是等价的:

<property name="address"  column="ADDRESS"/>

或者:

<property name="address"  type="string" />

对于Customer类的description属性,尽管它是java.lang.String类型,由于CUSTOMERS表的DESCRIPTION字段为text类型,因此必须显式地把映射类型设为text。

 

17用户自定义的type

1)应用的目的

开发者创建属于他们自己的值类型也是很容易的。比如说,你可能希望持久化java.lang.BigInteger类型的属性,持久化成为VARCHAR字段。Hibernate没有内置这样一种类型。

我们可以利用这种特色让我们的项目中使用自定义的诸如Address、Name这样的type,这样你就可以获得更大的便利,让你的代码更优雅。自定义type在Hibernate中是一项核心特色,它的设计者鼓励你多多使用它来创建一个灵活、优雅的项目!

2)要求

要实现一个自定义类型,可以实现org.hibernate.UserType或org.hibernate.CompositeUserType中的任一个,并且使用类型的Java全限定类名来定义属性。

<property name="twoStrings" type="org.hibernate.test.DoubleStringType">

椭圆形标注: 用户自定义的type     <column name="first_string"/>

    <column name="second_string"/>

</property>

注意:

l         自定义类型能够映射一个属性(或集合元素)到不止一个数据库表字段。比如说,你可能有这样的Java属性:getName()/setName(),这是java.lang.String类型的,对应的持久化到三个字段:FIRST_NAME, INITIAL, SURNAME。

l         使用<column>标签来把一个属性映射到多个字段的做法。

 

 

 

 

18、在EJB中使用Hibernate技术

1)在管理环境中配置Hibernate

管理环境处理特定的“cross-cutting”关系,例如应用安全(授权与验证),连接池和事务管理。J2EE应用服务器是典型的管理环境。虽然应用服务器通常是为了支持EJB而设计的,但即使你不使用EJB实体Bean,你仍然可以利用它提供的其它服务。

2)Hibernate经常与会话或消息驱动EJB一起使用

servlet、JSP和独立的应用一样,EJB调用相同的Hibernate API:Session(会话)、Transaction(事务)和Query(查询)。

Hibernate相关的代码在非管理与管理环境之间是完全可移植的。Hibernate透明地处理了不同的连接与事务策略。

3)使用应用服务器中的一些资源

应用服务器将连接池对外显示为JNDI绑定数据源,它是javax.jdbc.Datasource类的一个实例。你需要提供一个JNDI全限定名来告诉Hibernate,到哪里去查找JNDI数据源。这种情况下的一个Hibernate配置文件的例子参见下面的清单。

hibernate.connection.datasource = java:/comp/env/jdbc/AuctionDB

hibernate.transaction.factory_class = net.sf.hibernate.transaction.JTATransactionFactory

hibernate.transaction.manager_lookup_class =net.sf.hibernate.transaction.JBossTransactionManagerLookup

hibernate.dialect = net.sf.hibernate.dialect.PostgreSQLDialect

这个文件首先给出了数据源的JNDI名。数据源必须在J2EE企业应用的配置描述符中进行配置;这是一个厂商特定的设置。接着,你允许Hibernate与JTA集成。为了与容器事务完全集成, Hibernate需要定位应用服务器的事务管理器。J2EE规范没有定义标准的方法,但是Hibernate包含了对所有流行的应用服务器的支持。当然,最后还需要指定SQL方言。

 

4)Hibernate中定义了一组控制事务的API

Java早就有了一个标准的事务API:JTA,它用来在J2EE管理环境中控制事务。这被称作容器管理的事务(CMT)。如果存在JTA事务管理器,JDBC连接将被它支持并完全位于它的控制之下。

这与非管理环境不同,在非管理环境中应用(或连接池)直接管理JDBC连接和JDBC事务。因此,管理环境与非管理环境可以使用不同的事务方法。

因为Hibernate需要在这两种环境之间保证可移植性,因此它定义了一组控制事务的API。Hibernate的事务接口抽象了下层的JTA或JDBC事务(或者,甚至潜在的CORBA事务)。

5)这个下层的事务策略可以使用属性hibernate. connection.factory_class来设置,它可以取下列两值之一

net.sf.hibernate.transaction.JDBCTransactionFactory代表了直接的JDBC事务

这种策略应该与非管理环境中的连接池一起使用,并且如果没有指定任何策略时它就是缺省

值。

net.sf.hibernate.transaction.JTATransactionFactory代表了JTA

对于CMT这是正确的策略,此时连接由JTA支持。注意如果调用beginTransaction()时已经有一个JTA事务在运行,随后的工作将发生在那个事务的上下文中(否则,将会开始一个新的JTA事务)。

6)使用J2EE服务器工作时必需的两个步骤

我们只要记住使用J2EE服务器工作时必需的两个步骤:像前面描述的那样为Hibernate事务API设置工厂类以支持JTA,并且声明你的应用服务器特定的事务管理器的查找策略。只有你使用了Hibernate的二级缓存系统时查找策略才是必需的,但即使你没有使用缓存设上它也没有坏处。


Hibernate中所需要的JAR类库

1、全局类路径和上下文类路径

1)全局类路径(global classpath)

Tomcat来说全局库文件在下面的目录中(TOMCAT/common/lib

2)上下文类路径(context classpath)

Web应用程序上下文的路径(对于jar来说是webapps/XXX/WEB-INF/lib,对于class文件来说是webapps/XXX/WEB-INF/classes)能够被类装载器检索到。

注意:

尽可能不要拷贝任何其他东西到Tomcat的全局类路径下,否则你可能在使用其他一些工具上遇到麻烦,比如log4j, commons-logging等等。

一定要尽可能让每个web应用程序使用自己的上下文类路径,就是说把你自己需要的类库拷贝到WEB-INF/lib下去,把配置文件configuration/property等配置文件拷贝到WEB-INF/classes下面去。因为这两个目录都是当前程序缺省的上下文类路径。

2Hibernate中所需要的JAR类库

1Hibernate本身打包成一个JAR类库

hibernate3.jar文件拷贝到程序的上下文类路径下,和你应用程序的其他库文件放一起。

2Hibernate还需要一些第三方类库

在运行时,Hibernate还需要一些第三方类库,它们在Hibernate发行包的lib/目录下。

参见下表中的“Hibernate 第三方类库”列表和其作用。

类库

描述

antlr-2.7.5H3.jar(必需)

Hibernate使用ANTLR来产生查询分析器,这个类库在运行环境下时也是必需的。

dom4j-1.6.1.jar (必需)

jta.jar (必需)

jta.jar为事务管理的API所在的包(JTA规范,当Hibernate使用JTA的时候需要)。

dom4j是一个Java的XML API,类似于jdom,用来读写XML文件的。dom4j是一个非常非常优秀的Java XML API,具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的软件,可以在SourceForge上找到它。

它们都是必须使用的jar包,Hibernate用它来读写配置文件。

asm.jarcglib-2.1.2.jar(必需)

Hibernate在运行时使用这个代码生成库增强类(与Java反射机制联合使用)。其中的CGLIB库是Hibernate用它来实现PO字节码的动态生成,非常核心的库,必须使用的jar包。

commons-collections-2.1.1.jarcommons-logging-1.0.4.jar(必需)、commons-beanutils.jar、commons-lang.jar

Hibernat使用Apache Jakarta Commons项目提供的多个工具类库。 其中的commons-collections包含了一些Apache开发的集合类,功能比java.util.*强大。必须使用的jar包。

commons-beanutils.jar:包含了一些Bean工具类类。必须使用的jar包;

commons-lang.jar为Apache Commons包中的一个,包含了一些数据类型工具类,是java.lang.*的扩展。必须使用的jar包。

ehcache-1.1.jar(必需)

Hibernate可以使用不同cache缓存工具作为二级缓存。EHCache是缺省的cache缓存工具。

log4j-1.2.11.jar (可选)

Hibernate使用Commons Logging API,它也可以依次使用Log4j作为底层实施log的机制。如果上下文类目录中存在Log4j库,则Commons Logging使用Log4j和并它在上下文类路径中寻找的log4j.properties文件。你可以使用在Hibernate发行包中包含中的那个示例Log4j的配置文件。这样,把log4j.jar和它的配置文件(位于src/目录中)拷贝到你的上下文类路径下,就可以在后台看到底程序如何运行的。

odmg.jar

ODMG是一个ORM的规范,Hibernate实现了ODMG规范,这是一个核心的库,必须使用的jar包。

其他文件是不是必需的?

请察看Hibernate发行包中的 lib/README.txt文件,这是一个Hibernate发行包中附带的第三方类库的列表,他们总是保持最新的。你可以在那里找到所有必需或者可选的类库(注意:其中的"buildtime required"指的是编译Hibernate时所需要而非编译你自己的程序所必需的类库)。

把所需要的第三方库文件也拷贝到上下文类路径下。请参考下面的各个文件列表。

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值