ORM和Hibernate的配置方式

分层体系结构: 
逻辑上一般分为三层:表述层(提供与用户交互的界面)、业务逻辑层(实现各种业务的逻辑)、数据库层(负责存放和管理应用的持久性业务数据)。 
物理上一般分为两层:物理层(每一层都运行在网络上的单独的机器节点上)和逻辑层(每一层由一个相对独立的软件模块来实现。) 
软件层必须符合以下特征: 
(1)每个层由一组相关的类或组件构成,完成特定的功能。 
(2)层与层之间存在自上而下的依赖关系,即上层组件可以访问下层组件的API(application programming interface 应用程序接口),而下层组件不应该依赖上层组件。 
(3)每个层对上层公开API,但具体的实现细节对外透明。

概念模型描述了每个实体的概念和属性,以及实体之间的关系,但并不描述实体的行为。实体和实体之间存在着一对一、一对多和多对多的关系。

关系模型是在概念模型的基础上建立起来的,用于描述这些关系数据库的静态结构,它由以下内容组成:一个或多个表、表的所有索引、视图、触发器和表与表之间的参照完整性。

域模型是面向对象的,也可称为设计模型。由域对象(具有状态和行为的域对象)和域对象之间的关系组成。

域对象(Domain Object)是对真实世界的实体的软件抽象。还可叫做业务对象(Business Object)。分为一下几种:实体域对象(业务领域中的名次,像订单、商品、客户等)、过程域对象(代表业务逻辑或流程,通常依赖于实体域对象)和事件域对象(代表应用中的一些事件,像警告、异常或超时等,这些事件通常由系统中的某种行为触发)。

域对象之间的关系:关联(association)、依赖(dependency)、聚集(aggregation)和一般化(generalization)。 
关联指的是类之间的引用关系,可分为一对一、一对多和多对多关联。关联还是有方向的,可以分为单向关联和双向关联。 
依赖指的是类之间的访问关系。如果类A访问类B的属性或方法,或类A负责实例化类B,则可以说类A依赖类B。 
聚集指的是整体与部分的关系。 
一般化指的是类之间的继承关系。 
业务数据有两种表现形式:在内存中表现为实体域对象以及实体域对象之间的各种关系。在关系数据库中表现为表,以及表之间的参照关系。

ORM(object-relation mapping,对象-关系映射)模式指的是在单个组件中负责所有实体域对象的持久化,封装数据访问细节。ORM采用映射元数据(mapping meta data)来描述对象-关系映射细节,使ORM中间件能在任何一个Java应用的业务逻辑层和数据库层之间充当桥梁。元数据通常使用XML格式,并且存放在专门的对象-关系映射文件中。只要提供了持久化类与表的映射关系,ORM中间件在运行期间就能参照映射文件的信息,把域对象持久化到数据库中。

主动域对象模式:在它的实现中封装了关系数据模型和数据访问细节。主动域对象模式有以下有点:在实体域对象中封装自身的数据访问细节,过程域对象完全负责业务逻辑,使程序结构更加清晰;如果关系数据模型发生改变,只需修改主动域对象的代码,不需要修改过程域对象的业务方法。但也存在一下缺点:在实体域对象的实现中仍然包含SQL语句;每个实体域对象都负责自身的数据访问实现,会造成一定的代码冗余。

在J2EE框架中,EJB组件分为会话EJB和实体EJB。会话EJB通常实现业务逻辑,而实体EJB表示业务实体。实体EJB又分为两种:由EJB本身管理持久化,即BMP(bean-managed persistence)和由EJB容器管理持久化,即CMP(container-managed persistence)。

JDO(java data object)是SUN公司指定的描述对象持久化语义的标准API。它并不是单纯的对象-关系映射接口,它支持把对象持久化到任意一种存储系统中。

Hibernate的API中的接口可以分为一下几个类:提供访问数据库的操作的接口(Session、Transaction和Query);用于配置Hibernate的接口(Configuration);使应用程序拦截Hibernate内部发生的事件,并做成相关的回应的接口(Interceptor、localEventListener、SaveEventListener等);用于扩展Hibernate的功能接口(UserType、CompositeUserType等)。

所有的Hibernate应用中都会访问Hibernate的5个核心接口:Configuration接口:配置Hibernate,根启动Hibernate,创建SessionFactory对象;SessionFactory接口:初始化Hibernate,充当数据存储源的代理,创建Session对象;Session接口:负责保存、更新、删除、加载和查询对象;Transaction接口:管理事务;Query和Criteria接口:执行数据库查询。 
Configuration接口:Hibernate应用通过Configuration实例来获得对象-关系映射文件中的元数据,以及动态配置Hibernate属性,然后创建SessionFactory实例。 
SessionFactory接口:一个SessionFactory对应一个数据存储源,应用从SessionFactory中获得Session实例。它有以下特点:它是线程安全的,这意味着它的同一个实例可以被应用的多个线程共享。它是重量级的(它需要很大的缓存用来存放预定义的SQL语句及映射元数据等),这意味着不能随意创建或销毁它的实例。如果应用只访问一个数据库,则只需要创建一个SessionFactory。用户可以为SessionFactory配置一个缓存插件,被称为Hibernate第二级缓存,用来存放被工作单元读过的数据。 
Session接口:它提供了和持久化相关的工作。有以下特点:不是线程安全的、是轻量级的(它的创建或销毁Session对象不需要消耗太多的资源)。Session有一个缓存,被称为Hibernate的第一级缓存,它存放当前工作单元加载的对象。 
Transaction接口:它是Hibernate的数据库事务接口,底层事务接口包括:JDBC API、JTA、CORBA。 
Query和Criteria接口:它是Hibernate的查询接口,用于向数据库查询对象,以及控制执行查询的过程。Query实例包装了以HQL查询语句,Criteria接口完全封装了基于字符串形式的查询语句,比Query接口更加面向对象,擅长动态查询。 
事件及事件监听接口:在Hibernate API,针对每一种事件都有相应的事件监听器。 
org.hibernate.Interceptor接口:应用程序可以定义实现Interceptor接口的类,Interceptor实现类负责响应持久化类的实例被加载、保存、更新或删除事件。 
org.hibernate.type.Type接口表示Hibernate映射类型,用于把域对象映射为数据库的关系数据。Hibernate为Type接口提供了各种实现类,他们代表具体的Hibernate映射。Primitive Type类:映射java基本类型,包括:ByteType、ShortType、IntegerType、LongType、FloatType、DoubleType、CharrcterType和BooleanType。DateType和BinaryType。 
可扩展接口:当Hibernate内置的策略不能满足需求时,Hibernate允许用户以实现接口或扩展特定类的方式,定义客户化的策略。Hibernate的扩展点包括一下几点内容:定制主键的生成策略IdentifierGernerator接口;定制本地SQL方言的Dialect抽象类;定制缓存机制的Cache和CacheProvider接口;定制JDBC连接管理的ConnectionProvider接口;定制事务管理的TransactionFactory、Transaction和TransactionManagerLookup接口;定制属性访问策略的PropertyAccessor接口;创建代理的ProxyFactory接口和定制客户化映射类型的UserType和CompositeUserType接口。

Hibernate的配置文件有两种形式:一种是XML格式的文件,还有一种是Java属性文件(键=值)。 
以java属性文件的格式来创建Hibernate的配置文件。默认文件名为hibernate.properties。 
hibernate.dialect = org.hibernate.dialect.MySQLDialect 
hibernate.connection.driver_class = com.mysql.jdbc.Driver 
hibernate.connection.url = jdbc:mysql://localhost:3306/databaseName 
hibernate.connection.username = root 
hibernate.connection.password = tiger 
hibernate.show_sql = true

Hibernate并不要求持久化类必须实现java.io.Serializable接口,但对于采用RMI或JavaEE分布式结构的java应用,当Java对象在不同的进程节点之间传输时,这个对象所属的类必须实现Serializable接口,此外,在Java Web应用中,若希望HttpSession中存放的Java对象进行持久化,那么这个Java对象所属的类也必须实现Serializable接口。 
Hibernate要求持久化类必须提供一个不带参数的默认构造方法,因为在程序运行时,Hibernate会运用Java反射机制,调用java.lang.reflect.Constructor.newInstance()方法来构造持久化类的实例。这个默认的构造方法可以采用任意的访问级别。若对这个持久化类使用延迟检索策略,则要求持久化类的默认构造方法的访问级别不可以是private。

Hibernate采用XML格式的文件来指定对象和关系数据之间的映射。在运行时,Hibernate将根据这个映射文件来生成各种SQL,通常这个文件(xxx.hbm.xml)应该和.class放在同一个目录下。

映射文件的文档类型定义(DTD):它对XML文件的语法和格式做了定义。Hibernate的XML解析器将根据DTD来核对XML文件的语法。DTD中特殊符号的作用:无符号:该子元素在父元素内必须存在且只能存在一次;+:该元素在父元素内必须存在,可以存在一次或多次;*:该子元素在父元素内可以不存在,或者存在一次或多次;?:该子元素在父元素内可以不存在或只存在一次。

Hibernate采用XML文件来配置对象-关系映射,有以下优点:Hibernate既不会渗透到上层域模型中,也不会渗透到下层关系数据模型中。域模型和关系数据模型相互独立。对象-关系映射不依赖与任何程序代码。

Hibernate提供的实用工具: 
hbm2java:根据映射文件自动生成Java源文件 
hbm2ddl:根据映射文件自动生成数据库Schema 
XDoclet:根据带有XDoclet标记的Java源文件生成映射文件 
Middlegen:根据数据库Schema自动生成映射文件

定制持久化类:若把<meta>元素放在最上边,则所有类全部继承,可以设置inherit="false"来指定只有第一个类继承,或者使用作用域。
指定描述类的JavaDoc 
<class name="xx"> 
  <meta attribute="class-description"> 
   Represent a singgle xx 
  </meta> 
  ... 
</class> 
表示在xx类中添加描述类的JavaDoc,hbm2java工具生成的Java源代码如下 
/** 
*   Represent a singgle xx 
*/ 
public class xx implements Serialize

指定类所继承的类 
<class name="xx"> 
  <meta attribute="extends">xxFather</meta> 
  ... 
</class> 
public class xx extends xxFather inplements Serializable

指定描述类的属性JavaDoc 
<property name="xx" type="boolean" column="isXX"> 
   <meta attributes="field-description">Is xx?</meta> 
</property> 
/** 
*  *Is xx? 
*/ 
public Boolean getXx(){ 
   return this.xx; 
}

指定类、类的属性及类属性的getXXX()方法或setXXX()方法的修饰符。可选值包括static、final、abstract、public、protect和private。 
<id name="id" type="long"> 
  <meta attribute="scope-set">private</meta> 
  <generate class="native"  /> 
</id"> 
private void setId(long id){ 
  this.id = id; 
}

指定在类的toString()方法返回的字符串中是否包含特定的属性 
<property name="name" type="string" not-null="true"> 
  <meta attribute="use-in-tostring">true</meta> 
</property> 
public String toString(){ 
   StringBuffer buffer = new StringBuffer(); 
   buffer.append(getClass().getName()) 
         .append("@") 
         .append(Integer.toHexString(hashCode())).append("["); 
   buffer.append("name").append("='") 
         .append(getName()).append("'"); 
   ... 
}

<meta>元素的所有属性的 
class-description    指定描述类的JavaDoc 
field-description    指定描述类的属性的JavaDoc 
interface            如果为true,表示生成接口而非类,默认为false 
implements           指定类所实现的接口 
extends              指定类所继承的父类名 
generated-class      重新制定生成的类名 
scope-class          指定类的修饰符,默认为public 
scope-set            指定set方法的修饰符,默认为public 
scope-get            指定get方法的修饰符,默认为public 
scope-field          指定类的属性的修饰符,默认为private 
use-in-tostring      如果为true,表示在toString()方法中包含此属性 
gen-property         如果是false,不会在java类中生成此属性,默认为true

<property>元素的<column>子元素用于精粒度的控指表的定义。 
<column>元素的主要用法: 
设定字段名、字段长度及唯一性。 name length unique 
设定字段不允许为空,并且为这个字段设立检查约束  not-null  check 
设置索引 index="" 
设置字段的SQL类型 sql_type=""

利用ANT运行项目。build.xml 
<?xml version="1.0" ?> 
<project name="ANT" default="prepare" basedir="."> 
   <!-- set up properties containing important project directories --> 
   <property name="source.root" value="src" /> 
   <property name="class.root" value="classes" /> 
   <property name="lib.dir" value="lib" /> 
   <property name="schema.dir" value="schema" />

<!-- set uo the class path for compilation and execute --> 
   <path id="project.class.path"> 
      <!-- include our own classes , of course --> 
      <pathelement location="${class.root}" /> 
      <!-- include jars in the project library directory --> 
      <fileset dir="${lib.dir}"> 
         <include name="*.jar"  /> 
      </fileset> 
   </path>

<!-- create our runtime subdirectories and copy resources into them --> 
   <target name="prepare" description="sets uo build structures"> 
      <delete dir="${class.root}"  /> 
      <mkdir dir="${class.root}"   /> 
      
      <!-- copy our property files and O/R mappings for use at runtime --> 
      <copy todir="${class.root}"> 
           <fileset dir="${source.root}"> 
                <include name="**/*.properties"  /> 
                <include name="**/*.hbm.xml"  /> 
                <include name="**/*.cfg.xml"  /> 
           </fileset> 
      </copy> 
   </target>

<target name="codegen" depends="prepare"> 
      <taskdef name="hbm2javaTask" 
       classname="org.hibernate.tool.ant.HibernateToolTask" 
       classpathref="project.class.path" /> 
      <hbm2javaTask destdir="${source.root}"> 
         <configuration 
             configirationfile="${class.root}/hibernate.cfg.xml" /> 
         <hbm2java /> 
      </hbm2javaTasl> 
   </target> 
  
   <!-- compile the java source of the project --> 
   <target name="compile" depends="codegen" 
           description="compiles all java classes" > 
       <javac srcdir="${source.root}" destdir="${class.root}" 
              debug="on"  optimize="off"  deprecation="on"  > 
           <classpath refid="project.class.path"  /> 
       </javac> 
    </target> 
   
   <target name="schema" depends="compile"> 
       <taskdef name="hbm2ddlTask" 
                classname="org.hibernate.tool.ant.HibernateToolTask" 
                classpathref="project.class.path" /> 
       <hbm2ddlTask destdir="${schema.dir}"> 
           <configuration 
                configirationfile="${class.root}/hibernate.cfg.xml" /> 
           <hm2ddl export="true" console="true" create="true" 
                   drop="true" outputfilename="dbName.slq" /> 
        </hbm2ddlTask> 
   </target>

<target name="run"  description="run a Hibernate sample"  
           depends="schema"> 
       <java classname="xxx" fork="true"> 
           <classpath refid="project.class.path"  /> 
       </java> 
   </target> 
</project> 
</xml> 
perpare target:如存在classes目录,先将它删除,接着重新创建classes子目录。然后把src子目录下所有扩展名为properties、hbm.xml、cfg.xml的文件复制到classes目录下。 
codegen target:利用hbm2java工具生成java源码,并将这些源码存放到src子目录下。 
compile target:编译src子目录下的所有Java源文件。编译生成的类文件存放在classes子目录下。 
schema target:利用hbm2ddl工具生成数据库schema,数据量schema的脚本文件存放在schema子目录下,文件名为dbName.sql。 
run target:运行类。

上一篇:thinkphp 独立分组配置


下一篇:JPA、ORM