Hibernate第一次课(2)---Hibernate原理简介

时间:2022-10-18 14:21:44

学员要求:熟悉Java、SQL、JDBC,掌握面向对象的开发方法,并有实际的项目开发经验。

培训目标:让学员了解O/R Mapping原理,掌握Hibernate开发的相关知识,并能使用Hibernate进行实际项目开发。

 

(让学员理解典型的三层架构,如何用O/R Mapping框架来实现我们的数据层。这里主要介绍现在非常流程的Hibernate框架,希望通过培训之后,(学员了解Hibernate的架构,掌握Hibernate相关的概念;并教学员如何做对象和关系的映射,如何在应用中使用Hibernate)

 


 

数据源层-O/R Mapping

主要介绍三层架构,如何分层?(逻辑上的分层,二个原则)

数据层技术的选择:直接使用

SQL/JDBC

优点:很多开发者熟悉关系数据库管理系统,理解SQL,也知道如何使用表和外键进行工作。此外,他们可以始终使用众所周知并广泛使用的DAO设计模式对业务逻辑隐藏复杂的JDBC代码和不可移植的SQL。

缺点:为域中的每个类手工编写持续性代码的工作是非常可观的,特别是需要支持多种SQL方言时。这项工作通常会消耗很大一部分的开发努力。此外,当需求改变时,一个手工编码的解决方案总是需要更多的注意和维护努力。

 

序列化:Java有一个内建的持久化机制:序列化提供了将对象图(应用状态)写到字节流中的能力,然后它可能被持久化到文件或数据库中。持久化也被Java的远程方法调用(RMI)使用来为复杂对象传递值语义。持久化的另一种用法是在机器集群中跨节点复制应用状态。

缺点:很不幸,一个相互连接的对象图在序列化之后只能被当作一个整体访问,如果不反序列化整个流就不可能从流中取出任何数据。这样,结果字节流肯定会被认为不适合进行任意的检索或聚合。甚至不可能独立地访问或更新一个单独的对象或子图。

非常明显,因为当前特定的技术,序列化不适合于作为高并发性的Web和企业应用的持久化机制。在特定的环境中它被作为桌面应用的适当的持久化机制。

 

EJB entity beans

EJB1.1实体Bean在实践中彻底地失败了。EJB规范的设计缺陷阻碍了Bean管理的持续性(BMP)实体Bean有效地执行。在EJB1.1许多明显的缺陷被纠正之后,一个边缘的稍微可接受的解决方案是容器管理的持续性(CMP)。然而,CMP并不能表示一种对象-关系不匹配的解决方案。

CMP缺点:

¨  CMP实体Bean的粒度既太粗又太细:CMP Bean与关系模型中的表是按照一对一的方式定义的。这样,它们的粒度过粗,不能够完全利用Java丰富的类型。

¨  虽然EJB可以利用继承实现,但实体Bean并不支持多态的关联和查询

¨  不管EJB规范所宣称的目标,实体Bean实际上是不可移植的。CMP引擎的性能因厂商而异,并且映射元数据也是高度特定于厂商的。

¨  实体Bean不可序列化。我们发现当我们需要将数据传输到远程客户层时,我们必须定

义额外的数据传输对象(DTO,也被称作值对象)

¨  实体Bean必须依赖于EJB容器测试困难。

 

JDO、Object-oriented database systems

大多数面向对象的数据库系统对ODMG标准都提供了许多程度的支持,但据我们所知,还没有完全的实现。此外,在规范发布以后的很多年,甚至到了3.0版,还是感觉不太成熟,并且缺乏很多有用的特征,特别是基于Java环境的。ODMG也不再活跃。最近,Java数据对象(JDO)规范(发表于2002年4月)揭开了新的可能性。JDO由面向对象数据库团体的成员驱动,除了对现有的ODMG的支持之外,面向对象的数据库产品现在还经常将其作为主要的API采用。

JDO 的优点在于它很简单。开发人员使用 Java 语言持久存储对象实例并从存储器检索实例。处理逻辑、同步和故障转移等均被透明地处理。开发人员无需使用 SQL 或 Java 语言提供的不便的序列化机制,只使用 POJO(无格式普通 Java 对象)即可,利用 JDO 接口将对象引用传递到存储器中并从存储器检索对象引用。

 

O/R Mapping

 

什么是O/R Mapping?它有什么优点?

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

提高生产率(Productivity

与持久性有关的代码可能是Java应用中最乏味的代码。Hibernate去掉了很多让人心烦的工作(多于你的期望),让你可以集中更多的精力到业务问题上。不论你喜欢哪种应用开发策略——自顶向下,从域模型开始;或者自底向上,从一个现有的数据库模式开始——使用Hibernate和适当的工具将会减少大量的开发时间。

 

可维护性(Maintainability

   减少了代码,重构更方便,提高了可维护性。ORM是对象和关系数据库之间的缓冲区,用来很好的将他们隔离。

 

更好性能(Performance

ORM软件的实现人员可能有比你更多的时间来研究性能优化问题。你知道吗,例如,缓存PreparedStatement的实例对DB2的JDBC驱动导致了一个明显的性能增长但却破坏了InterBase的JDBC驱动?你了解吗,对某些数据库只更新一个表中被改变的字段可能会非常快但潜在地对其它的却很慢?在你手工编写的解决方案中,对这些不同策略之间的冲突进行试验是多么不容易呀?

 

厂商独立性(Vendor independence

ORM抽象了你的应用使用下层SQL数据库和SQL方言的方式。如果工具支持许多不同的数据库(dialect),那么这会给你的应用带来一定程度的可移植性。你不必期望可以达到“一次编写,到处运行”,因为数据库的性能不同并且达到完全的可移植性需要牺牲更强大的平台的更多的力气。然而,使用ORM开发跨平台的应用通常更容易。即使你不需要跨平台操作,ORM依然可以帮你减小被厂商锁定的风险。另外,数据库独立性对这种开发情景也有帮助:开发者使用一个轻量级的本地数据库进行开发但实际产品需要配置在一台不同的数据库上。

 

如何做对象-关系数据库映射?(最后引入Hibernate)

public class User {

       private Long id;

       private String name;

       private List address;

………

}

 

create table tbl_user (

       id bigint not null auto_increment,

       name varchar(255),

       primary key (id)

)

 

Java

数据库

类的属性(基本类型)

表的列

1:n/n:1

外键

n:m

关联表

继承

单表继承、具体表继承、类表继承

 

1、  Java基本类型-表的

 

2、  Java类的映射

 

3、  关联的映射:例如一个User有多个Address,User和Address管理,User删除时,相应的Address也应该删除。

 

对象-关系的不匹配范式(paradigm)

1、  粒度(granularity)的问题。

  

增加一种新的数据类型,将Java地址对象在我们的数据库中保存为单独的一列,听起来好像是最好的方法。毕竟,Java中的一个新的地址类与SQL数据类型中的一个新的地址类型可以保证互用性。然而,如果你检查现在的数据库管理系统对用户定义列类型(UDT)的支持,你将会发现各种各样的问题。

 

2、  子类型(subtypes)的问题。

   子类型不匹配是指Java模型中的继承结构必须被持续化到SQL数据库中,而SQL数

据库并没有提供一个支持继承的策略。如何解决多态?

 

3、  同一性(identity)的问题

Java对象定义了两种不同的相等性的概念:

■ 对象同一性(粗略的等同于内存位置的相等,使用a==b检查)

■ 通过equals()方法的实现来决定的相等性(也被称作值相等)

另一方面,数据库行的同一性使用主键值表示。主键既不必然地等同于“equals()”也不等同于“==”。它通常是指几个对象(不相同的)同时表示了数据库中相同的行。而且,为一个持续类正确地实现equals()方法包含许多微妙的难点。

 

4、  与关联(associations)有关的问题

面向对象的语言使用对象引用和对象引用的集合表示关联。在关系世界里,关联被表示为外键列,外键是几个表的键值的拷贝。这两种表示之间有些微妙的不同。

5、  对象结构导航的问题

在Java中访问对象的方式与在关系数据库中有根本的不同。在Java中,访问用户的账单信息时,你调用aUser.getBillingDetails().getAccountNumber()。这是最自然的面向对

象数据的访问方式,通常被形容为遍历对象图。根据实例间的关联,你从一个对象导航到另

一个对象。不幸地是,这不是从SQL数据库中取出数据的有效方式。

为了提高数据访问代码的性能,唯一重要的事是最小化数据库请求的次数。最明显的方

式是最小化SQL查询的数量(其它方式包括使用存储过程或者JDBC批处理API)。

 

使用SQL有效地访问关系数据通常需要在有关的表之间使用连接。在连接中包含的

表的数量决定了你可以导航的对象图的深度。

性能:N+1的问题

   

 

范式不匹配的代价:

1、花费很多时间和精力来手工解决对象和关系的不匹配。

2、为了解决不匹配,甚至要扭曲对象模型直到它与下层的关系技术匹配为止

4、  JDBC API本身的问题。JDBC和SQL提供了一个面向语句(即命令)的方法从SQL数据库中来回移动数据。至少在三个时刻(Insert,Update,Select)必须指定一个结构化关系,这增加了设计和实现所需要的时间。

 

主流持久层框架纵览

目前众多厂商和开源社区都提供了持久层框架实现,常见的有:

Apache OJB(http://db.apache.org/ojb/ )

Cayenne(http://objectstyle.org/cayenne/ )

Jaxor(http://jaxor.sourceforge.net )

Hibernate(http://www.hibernage.org)

iBATIS(http://www.ibatis.com )

jRelationalFramework(http://jrf.sourceforge.net)

mirage(http://itor.cq2.org/en/oss/mirage/toon)

SMYLE(http://www.drjava.de/smyle/)

TopLink(http://otn.oracle.com/products/ias/toplink/index.html )

(其中TopLink 是Oracle 的商业产品。其他均为开源项目)

 

Apache OJB 的优势在于对各种标准的全面支持(不过事实上,我们的系统研发中并

不需要同时支持这么多标准,追求多种标准的并行支持本身也成为Apache OJB 项目发

展的沉重包袱),且其从属于Apache 基金组织,有着可靠的质量保证和稳定的发展平台。

 

Hibernate 在2003 年末被JBoss 组织收纳,成为从属于JBoss 组织的子项目之一,

从而赢得了良好的发展前景(同时荣获Jolt 2004 大奖)。

Hibernate 与OJB 设计思想类似,具备相近的功能和特色,但由于其更加灵活快速

的发展策略,得到了广大技术人员的热情参与,因此也得到了更广泛的推崇。相对Apache

OJB 迟钝的项目开发进度表,Hibernate 活跃的开发团队以及各社区内对其热烈的关注为

其带来了极大的活力,并逐渐发展成Java 持久层事实上的标准。

 

iBATIS 相对Apache OJB 和Hibernate 项目则另具特色,iBATIS 采取了更加开放式

的设计,通过iBATIS,我们可以控制更多的数据库操作细节。相对而言,Hibernate、

Apache OJB 对持久层的设计则较为封闭,封闭化的设计对持久层进行了较为彻底的封

装,从而将底层细节与上层架构完全分离,大多数情况下,特别是对于新系统,新产品

的研发而言,封闭化的设计带来了更高的开发效率和更好的封装机制,但是在某些情况

下,却又为一些必须的底层调整带来了阻力,如在对遗留系统的改造和对既有数据库的

复用上,表现出灵活性不足的弱点。此时作为OJB,Hibernate 的一个有益补充,iBATIS

的出现显得别具意义。

Hibernate入门

 

Hibernate概述

Hibernate是非常优秀、成熟的O/R Mapping框架。它提供了强大、高性能的Java对象和关系数据的持久化和查询功能。

 

(O/R Mapping是一项实用的工程技术,把数据库的E/R模型用java的OO语法描述出来,Hibernate是其中的当之无愧的最耀眼的明星,cglib动态增强,多种灵活的class继承树映射机制,广泛的社团支援,掩盖了其他项目的光辉。)

 

Hibernate的优势

¨  开源(LGPL)

¨  成熟

¨  流行(约13 000 downloads/month)

¨  自定义API

JBoss 将用Hibernate3实现Entity Beans

使用Hibernate的开发步骤

1、  设计

一般首先进行领域对象的设计。因为在Hibernate中,我们的领域对象可以直接充当持久化类。

2、  映射

定义Hibernate的映射文件,实现持久化类和数据库之间映射。

3、  应用

使用Hibernate提供的API,实现具体的持久化业务。

 

Hibernate的映射

Entity-hbm-ddl(数据库)(hbm(hibernate mapping)和ddl(Data Definition Language)的全称)

『之间的互相转换』

 

 

User.java User.hbm.xml

 

XDoclet:它通过在Java源代码中加入特定的JavaDoc tag,从而为其添加特定的附加语义,之后通过XDoclet工具对代码中JavaDoc Tag进行分析,自动生成与代码对应的配置文件(http://xdoclet.sourceforge.net/)。XDoclet提供了对Hibernate的支持,这样我们可以直接由Java代码生成Hibernate映射文件。

 

Middlegen: 用来从数据库中已有的表结构中生成Hibernate映射文件。当前版本是2.1可以去http://boss.bekk.no/boss/middlegen下载。

 

 

Hibernate核心接口

 

Configuration

正如其名,Configuration 类负责管理Hibernate 的配置信息。Hibernate 运行时需要

获取一些底层实现的基本信息,其中几个关键属性包括:

1、数据库URL

2、数据库用户

3、数据库用户密码

4、数据库JDBC驱动类

5、  数据库dialect,用于对特定数据库提供支持,其中包含了针对特定数据库特性的实现,如Hibernate数据类型到特定数据库数据类型的映射等。

当然,还有指定Hibernate映射文件的位置。(*.hbm.xml)。

 

Hibernate配置有两种方法:

一、属性文件配置。默认文件名是hibernate.properties。调用代码:

    Configuration config = new Configuration();

二、XML文件配置。默认文件名是hibernate.cfg.xml。

Configuration config = new Configuration().configure();

 

SessionFactory:应用程序从SessionFactory(会话工厂)里获得Session(会话)实例。它打算在多个应用线程间进行共享。通常情况下,整个应用只有唯一的一个会话工厂——例如在应用初始化时被创建。然而,如果你使用Hibernate访问多个数据库,你需要对每一个数据库使用一个会话工厂。

会话工厂缓存了生成的SQL语句和Hibernate在运行时使用的映射元数据。它也保存了在一个工作单元中读入的数据并且可能在以后的工作单元中被重用(只有类和集合映射指定了使用这种二级缓存时才会如此)。

SessionFactory sessionFactory = config.buildSessionFactory();

 

Session(会话):该接口是Hibernate使用最多的接口。Session不是线程安全的,它代表与数据库之间的一次操作。Session通过SessionFactory打开,在所有的工作完成后,需要关闭:它的概念介于Connection和Transaction之间。我们可以简单的认为它是已经装载对象的缓存或集合的一个独立工作单元。

我们有时也称Session为持久化管理器,因为它是与持久化有关的操作的接口。

Hibernate会话并不是线程安全的因此应该被设计为每次只能在一个线程中使用。Hibernate会话与Web层的HttpSession没有任何关系。

Session session = sessionFactory.openSession();

 

Transaction事务将应用代码从底层的事务实现中抽象出来——这可能是一个JDBC事务,一个JTA用户事务或者甚至是一个公共对象请求代理结构(CORBA)——允许应用通过一组一致的API控制事务边界。这有助于保持Hibernate应用在不同类型的执行环境或容器中的可移植性。

Transaction trans = session.beginTransaction ();

 

Query: Query(查询)接口允许你在数据库上执行查询并控制查询如何执行。查询语句使用HQL或者本地数据库的SQL方言编写。

Query query = session.createQuery(“from User”);

 

Lifecycle:Lifecycle接口提供了一些回调方法,可以让持久化对象在save或load之后,或者在delete或update之前进行必要的初始化与清除步骤。

public interface Lifecycle {

        public boolean onSave(Session s) throws CallbackException;   (1)

        public boolean onUpdate(Session s) throws CallbackException; (2)

        public boolean onDelete(Session s) throws CallbackException; (3)

        public void onLoad(Session s, Serializable id);              (4)

}

(1) onSave - 在对象即将被save或者insert的时候回调

 (2) onUpdate - 在对象即将被update的时候回调(也就是对象被传递给Session.update()的时候)

 (3) onDelete - 在对象即将被delete(删除)的时候回调

 (4) onLoad - 在对象刚刚被load(装载)后的时候回调

Validatable: 该接口是合法性检查的回调。如果持久化类需要在保存其持久化状态前进行合法性检查,它可以实现下面的接口:

public interface Validatable {

        public void validate() throws ValidationFailure;

}

如果发现对象违反了某条规则,应该抛出一个ValidationFailure异常。在Validatable实例的validate()方法内部不应该改变它的状态。

和Lifecycle接口的回调方法不同,validate()可能在任何时间被调用。应用程序不应该把validate()调用和商业功能联系起来。

Interceptor: Interceptor接口提供从session到你的应用程序的回调方法,让你的程序可以观察和在持久化对象保存/更改/删除或者装载的时候操作它的属性。一种可能的用途是用来监视统计信息。比如,下面的Interceptor会自动在一个Auditable创建的时候设置其createTimestamp,并且当它被更改的时候,设置其lastUpdateTimestamp属性。

 

UserType: 开发者创建属于他们自己的值类型也是很容易的。比如说,你可能希望持久化java.lang.BigInteger类型的属性,持久化成为VARCHAR字段。Hibernate没有内置这样一种类型。自定义类型能够映射一个属性(或集合元素)到不止一个数据库表字段。比如说,你可能有这样的Java属性:getName()/setName(),这是java.lang.String类型的,对应的持久化到三个字段:FIRST_NAME, INITIAL, SURNAME。 要实现一个自定义类型,可以实现net.sf.hibernate.UserType或net.sf.hibernate.CompositeUserType中的任一个,并且使用类型的Java全限定类名来声明属性。请查看net.sf.hibernate.test.DoubleStringType这个例子,看看它是怎么做的。

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

    <column name="first_string"/>

    <column name="second_string"/>

</property>

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

 

用户的例子

设计:用户,id name

映射:User.java User.hbm.xml

一、安装

二、持久化类(Persistent Class)

持久化类不需要实现什么特别的接口,也不需要从一个特别的持久化根类继承下来。Hibernate也不需要使用任何编译期处理,比如字节码增强操作,它独立的使用Java反射机制和运行时类增强(通过CGLIB)。所以,在Hibernate中,POJO的类不需要任何前提条件,我们就可以把它映射成为数据库表。

 

持久化类必须遵循的原则:

1、  为类的持久化类字段申明访问方法(Get/set)。Hibernate对JavaBeans风格的属性实行持久化。

2、  实现一个默认的构造方法(constructor)。这样的话Hibernate就可以使用Constructor.newInstance()来实例化它们。

3、  如果是集合类型的属性,它的类型必须定义为集合的接口。例如:List、Set

4、  提供一个标识属性(identifier property)。如果没有该属性,一些功能不起作用,比如:级联更新(Cascaded updates)Session.saveOrUpdate()。

 

三、hibernate映射文件

 

 

四、应用:TestUser.java

之后做个总结,特别是CRUD操作。

Hibernate映射声明(Mapping declaration)

 

一、             DOCTYPE声明。

一个XML document应该在文档的起始位置有一个XML的声明,可能跟随着一个DOCTYPE的声明。一个DOCTYPE声明告诉一个XML parser这个XML文档遵循了哪一个DTD(Document Type Declaration)。Parser可以用此信息来确认这个XML文档包含的仅是这个DTD声明的XML element。

例如:

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC

        "-//Hibernate/Hibernate Mapping DTD 2.0//EN"

        "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

DTD可以从上述URL中获取,或者在hibernate-x.x.x/src/net/sf/hibernate目录中,或hibernate.jar文件中找到。Hibernate总是会在它的classptah中首先搜索DTD文件。

 

二、             hibernate-mapping

它是文档的根(root),可以包含多个类的映射,但一般只包含一个类。

<hibernate-mapping

         schema="schemaName"                    (1)

         default-cascade="none|save-update"           (2)

         auto-import="true|false"                    (3)

         package="package.name"                   (4)

 />

(1)、schema(可选):数据库Schema Name

(2)、default-cascade(可选,默认为none):默认的级联风格

(3)、auto-import(可选,默认为true):是否允许在查询语言中使用非完全限定的类名即只用类的名称,不用加入包名(仅限本映射文件中定义的类)。

(4)、package(可选),如果该映射文件中定义的类名不包含package,则使用这里定义的package作为类名的前缀。

 

注:(3)默认的值是“true”,如果有多个类的名字相同,则必须将该值设为false。

 

三、class

用class元素来定义一个持久化类。

<class

        name="ClassName"                        (1)

        table="tableName"                        (2)

        discriminator-value="discriminator_value"     (3)

        mutable="true|false"                       (4)

        schema="owner"                          (5)

        proxy="ProxyInterface"                     (6)

        dynamic-update="true|false"                 (7)

        dynamic-insert="true|false"                  (8)

        select-before-update="true|false"             (9)

        polymorphism="implicit|explicit"             (10)

        where="arbitrary sql where condition"         (11)

        persister="PersisterClass"                   (12)

        batch-size="N"                           (13)

        optimistic-lock="none|version|dirty|all"        (14)

        lazy="true|false"                         (15)

/>

1、  name:持久化类(或Java接口)的全名。

2、  table:对应的数据库表名。

3、  discriminator-value(鉴别值)(可选,默认和类名一样):一个用于区分不同子类的值,在多态行为中使用。

4、  mutable(可选,默认值为true):表明该类是否可以改变。如果将它设为false,则应用程序不能对此类对应的数据进行修改和删除。

5、  schema(可选):覆盖在根<hibernate-mapping>元素中指定的schema名字。

6、  proxy(可选):指定一个接口,在延迟装载时作为代理使用。你可以在这里使用该类自己的名字。

7、  dynamic-update(动态更新) (可选,默认为false): 指定用于UPDATE 的SQL将会在运行时动态生成,并且只更新那些改变过的字段。

8、  dynamic-insert(动态插入) (可选, 默认为false): 指定用于INSERT的 SQL 将会在运行时动态生成,并且只包含那些非空值字段。

9、  select-before-update (可选,默认值为false): 指定Hibernate除非确定对象的确被修改了,不会执行SQL UPDATE操作。在特定场合(实际上,只会发生在一个临时对象关联到一个新的session中去,执行update()的时候),这说明Hibernate会在UPDATE之前执行一次额外的SQL SELECT操作,来决定是否应该进行UPDATE。

10、              polymorphism(多形,多态) (可选, 默认值为 implicit (隐式)): 界定是隐式还是显式的使用查询多态。

11、              where (可选) 指定一个附加的SQLWHERE 条件,在抓取这个类的对象时会一直增加这个条件。

12、              persister (可选): 指定一个定制的ClassPersister。

13、              batch-size (可选,默认是1) 指定一个用于根据标识符抓取实例时使用的"batch size"(批次抓取数量)。

14、              optimistic-lock(乐观锁定) (可选,默认是version): 决定乐观锁定的策略。

15、              lazy(延迟) (可选): 假若设置 lazy="true",就是设置这个类自己的名字作为proxy接口的一种等价快捷形式。

四、id

持久化类必须要声明一个字段对应数据库表的主键。

<id

        name="propertyName"                      (1)

        type="typename"                          (2)

        column="column_name"                     (3)

        unsaved-value="any|none|null|id_value"   (4)

        access="field|property|ClassName">       (5)

 

        <generator class="generatorClass"/>

</id>

(1)、name(可选):标识属性的名称。

(2)、type(可选):标识Hibernate类型的名字。

(3)、column(可选-默认为属性名):对应数据库表的主键字段的名字。

(4)、unsaved-value(可选-默认为null):这个值用来判断对象是否要保存。如果一个对象id值与该值相等时,Hibernate则会认为该对象是一个新的对象,并没有持据化到数据库中。举例:假如一个新建对象的属性id的类型为int,我们知道如果不给id赋值,它默认的值就应该是“0”,如果这时unsaved-value是默认的null。则当保存这个新建对象,调用session. SaveOrUpdate()方法时会抛出异常。因为id的值不等于null,所以Hibernate会认为该对象已经保存,它会去执行update操作。

 

Generator

主键生成器,每个主键都必须定义相应的主键生成策略。它用来为持久化类实例生成唯一的标识。例如:

<id name="id" type="long" column="uid" unsaved-value="0">

        <generator class="net.sf.hibernate.id.TableHiLoGenerator">

                <param name="table">uid_table</param>

                <param name="column">next_hi_value_column</param>

        </generator>

</id>

所有的生成器都实现net.sf.hibernate.id.IdentifierGenerator接口。这是一个非常简单的接口;某些应用程序可以选择提供他们自己特定的实现。当然,Hibernate提供了很多内置的实现。

 

下面是一些内置生成器的快捷名字:

1、  数据库提供的主键生成机制。identity、sequence、

2、  外部程序提供的主键生成机制。increment ,hilo,seqhilo,uuid.hex,uuid.string

3、  其它。native,assigned,foreign

increment(递增):主键按数值顺序递增。此方式的实现机制为在当前应用实例中维持

一个变量,以保存着当前的最大值,之后每次需要生成主键的时候将此值加1作为主键。用于为long, short或者int类型生成唯一标识。只有在没有其他进程往同一张表中插入数据时才能使用。 在集群下不要使用。

identity

采用数据库提供的主键生成机制(数据库内部支持标识字段)。如DB2、SQL Server、MySQL中的主键生成机制。返回的标识符是long, short 或者int类型的。

 

sequence (序列):采用数据库提供的sequence 机制生成主键。如Oralce 中的Sequence。

hilo (高低位): 通过hi/lo算法实现的主键生成机制,需要额外的数据库表保存主键生成历史状态。高/低位算法生成的标识符只在一个特定的数据库中是唯一的。在使用JTA获得的连接或者用户自行提供的连接中,不要使用这种生成器。

seqhilo(使用序列的高低位):与hilo 类似,通过hi/lo 算法实现的主键生成机制,只是主键历史状态保存在Sequence中,适用于支持Sequence的数据库,如Oracle。

uuid.hex

用一个128-bit的UUID算法生成字符串类型的标识符。在一个网络中唯一(使用了IP地址,JVM的启动时间(精确到1/4秒),系统时间和一个计数器值(在JVM中唯一)。)。UUID被编码为一个32位16进制数字的字符串。

 

uuid.string

使用同样的UUID算法。UUID被编码为一个16个字符长的任意ASCII字符组成的字符串

 

native(本地)

根据底层数据库的能力选择identity, sequence 或者hilo中的一个

 

assigned(程序设置)

让应用程序在save()之前为对象分配一个标示符。

 

foreign(外部引用)

使用另外一个相关联的对象的标识符。和<one-to-one>联合一起使用。

 

五:property

<property>元素为类声明了一个持久化的,JavaBean风格的属性。

 

<property

        name="propertyName"                 (1)

        column="column_name"                (2)

        type="typename"                     (3)

        update="true|false"                 (4)

        insert="true|false"                 (4)

        formula="arbitrary SQL expression"  (5)

        access="field|property|ClassName"   (6)

/>

(1) name: 属性的名字,以小写字母开头。

(2) column (可选 - 默认为属性名字): 对应的数据库字段名。

(3) type (可选): 一个Hibernate类型的名字。

(4) update, insert (可选 - 默认为 true) :表明在用于UPDATE 和/或 INSERT的SQL语句中是否包含这个字段。这二者如果都设置为false则表明这是一个“外源性(derived)”的属性,它的值来源于映射到同一个(或多个)字段的某些其他属性,或者通过一个trigger(触发器),或者其他程序。

 

(5) formula (可选): 一个SQL表达式,定义了这个计算(computed) 属性的值。计算属性没有和它对应的数据库字段。

(6) access (可选 - 默认值为 property): Hibernate用来访问属性值的策略。

 

六、多对一个(many-to-one)

<many-to-one

        name="propertyName"                                (1)

        column="column_name"                               (2)

        class="ClassName"                                  (3)

        cascade="all|none|save-update|delete"              (4)

        outer-join="true|false|auto"                       (5)

        update="true|false"                                (6)

        insert="true|false"                                (6)

        property-ref="propertyNameFromAssociatedClass"     (7)

        access="field|property|ClassName"                  (8)

/>

(1) name: 属性名。

(2) column (可选): 字段名。

(3) class (可选 - 默认是通过反射得到属性类型): 关联的类的名字。

(4) cascade(级联) (可选): 指明哪些操作会从父对象级联到关联的对象。

(5) outer-join(外连接) (可选 - 默认为 自动): 当设置hibernate.use_outer_join的时候,对这个关联允许外连接抓取。

(6) update, insert (可选 - defaults to true) 指定对应的字段是否在用于UPDATE 和/或 INSERT的SQL语句中包含。如果二者都是false,则这是一个纯粹的“外源性(derived)”关联,它的值是通过映射到同一个(或多个)字段的某些其他属性得到的,或者通过trigger(触发器),或者是其他程序。

(7) property-ref: (可选) 指定关联类的一个属性,这个属性将会和本外键相对应。如果没有指定,会使用对方关联类的主键。 该属性只应该用来对付老旧的数据库系统,可能出现外键指向对方关联表的是个非主键字段(但是应该是一个惟一关键字)的情况。

(8) access (可选 - 默认是 property): Hibernate用来访问属性的策略。

 

七、一对多(one-to-many)

 

 

<set

    name="propertyName"                                         (1)

    table="table_name"                                          (2)

    lazy="true|false"                                           (3)

    inverse="true|false"                                        (4)

    cascade="all|none|save-update|delete|all-delete-orphan"     (5)

    sort="unsorted|natural|comparatorClass"                     (6)

    order-by="column_name asc|desc"                             (7)

    where="arbitrary sql where condition"                       (8)

    outer-join="true|false|auto"                                (9)

(1) name 集合属性的名称

(2) table (可选)目标关联数据库表

(3) lazy (可选——默认为false)允许延迟加载(lazy initialization )

(4) inverse (可选——默认为false) 标记这个集合作为双向关联关系中的方向一端。

(5) cascade (可选——默认为none) 让操作级联到子实体

(6) sort(可选-默认为unsorted)指定集合的排序顺序, 其可以为自然的(natural)或者给定一个用来比较的类。

(7) order-by (可选, 仅用于jdk1.4) 指定表的字段(一个或几个)再加上asc或者desc(可选), 定义Map,Set和Bag的迭代顺序

(8) where (可选) 指定任意的SQL where条件。该条件将在重新载入或者删除这个集合时使用(当集合中的数据仅仅是所有可用数据的一个子集时这个条件非常有用)

(9) outer-join(可选-默认为auto)是否使用外联接

 

八、多对多

 

<many-to-many

        column="column_name"                               (1)

        class="ClassName"                                  (2)

        outer-join="true|false|auto"                       (3)

/>

(1) column(必需): 中间映射表中,关联目标表的关联字段

 

(2) class (必需): 类名,关联目标类

 

(3) outer-join (可选 - 默认为auto): 在Hibernate系统参数中hibernate.use_outer_join被打开的情况下,该参数用来允许使用outer join来载入此集合的数据。

 

持久化对象的状态

¨  瞬时(Transient)对象:使用new 操作符初始化的对象不是立刻就持久的。它们的状态是瞬时的,也就是说它们没有任何跟数据库表相关联的行为,只要应用不再引用这些对象(不再被任何其它对象所引用),它们的状态将会丢失,并由垃圾回收机制回收。

¨  持久化(Persist)对象:持久实例是任何具有数据库标识的实例。它有持久化管理器Session统一管理,持久实例是在事务中进行操作的——它们的状态在事务结束时同数据库进行同步。当事务提交时,通过执行SQL的INSERT、UPDATE和DELETE语句把内存中的状态同步到数据库中。

¨  离线(Detached)对象:Session关闭之后,持久化对象就变为离线对象。离线表示这个对象不能再与数据库保持同步,它们不再受Hibernate管理。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


Save() saveorupdate() update()

 

Automatic dirty object checking

 

 

 

 

 

 

 

 

 

Hibernate查询

数据查询与检索是Hibernate中的一个亮点。相对其他ORM实现而言,Hibernate

提供了灵活多样的查询机制。

Hibernate Query Language (HQL)

HQL是完全面向对象的查询语句,具备继承、多态和关联等特性。HQL(Hibernate Query Language)提供了非常强大的查询功能,在官方开发手册中,也将HQL作为推荐的查询模式。

 

HQL 子句本身大小写无关,但是其中出现的类名和属性名必须注意大小写区分

Criteria Queries

 

Criteria Query(标准化对象查询)通过面向对象化的设计,将数据查询条件封装为一个对象。简单来讲,Criteria Query可以看作是传统SQL的对象化表示。

优点:可读性好,符合Java 程序员的编码习惯。缺点:不够成熟,不支持投影(projection)或统计函数(aggregation)。

 

 

这种方式的特点是比较符合Java 程序员的编码习惯,并且具备清晰的可读性。正因为此,不少ORM实现中都提供了类似的实现机制(如Apache OJB)。

Native SQL Queries

原生SQL查询:直接使用数据库提供的SQL进行查询。

 

安装配置

下载最新发布的Hibernate代码包,拷贝需要的.jar文件。

 

Hibernate配置有两中方法:

一、XML格式的配置文件,文件名默认为“hibernate.cfg.xml“。

二、传统的properties文件配置方式,文件名为“hibernate.properties”。

第一种方式,提供了易读的结构,和更强的配置能力,可以直接对映射文件加以配置,使用起来更方便。第二种方式比较简单。

 

User例子

实体类:必需有一个默认的构造函数,equal() HashCode() Serializable

 

 

Session.flush()方法强制数据库同步,这里即强制Hibernate将user实例立即同步到数据库中。如果在事务中则不需要flush方法,在事务提交的时候,hibernate自动会执行flush方法,另外当Session关闭时,也会自动执行flush方法。

 

session.close()

session.flush():刷新,迫使Session执行一些必需的SQL语句,把内存中的对象和JDBC连接中的状态进行同步更新。

session.clear():要把所有的对象从session缓存中完全清除

 

在sessionFactory.openSession()中,hibernate会初始化

数据库连接,与此同时,将其AutoCommit 设为关闭状态(false)。而其后,在

Session.beginTransaction 方法中,Hibernate 会再次确认Connection 的

AutoCommit 属性被设为关闭状态( 为了防止用户代码对session 的

Connection.AutoCommit属性进行修改)。

 

 

Set和List的区别:

Query.list();

Query.iterate();

对于list方法而言,实际上Hibernate是通过一条Select SQL获取所有的记录。

并将其读出,填入到POJO中返回。

而iterate 方法,则是首先通过一条Select SQL 获取所有符合查询条件的记录的

id,再对这个id 集合进行循环操作,通过单独的Select SQL 取出每个id 所对应的记

录,之后填入POJO中返回。

也就是说,对于list 操作,需要一条SQL 完成。而对于iterate 操作,需要n+1

条SQL。

看上去iterate方法似乎有些多余,但在不同的情况下确依然有其独特的功效,如对

海量数据的查询,如果用list方法将结果集一次取出,内存的开销可能无法承受。

另一方面,对于我们现在的Cache机制而言,list方法将不会从Cache中读取数据,

它总是一次性从数据库中直接读出所有符合条件的记录。而iterate 方法因为每次根据

id获取数据,这样的实现机制也就为从Cache读取数据提供了可能,hibernate首先会

根据这个id 在本地Cache 内寻找对应的数据,如果没找到,再去数据库中检索。如果系

统设计中对Cache比较倚重,则请注意编码中这两种不同方法的应用组合,有针对性的改

善代码,最大程度提升系统的整体性能表现。

 

 

Hibernate3发布beta版本 支持EJB3风格对象持久化

(2004.12.21)   来自:CSDN   熊节 

 

昨天(12月20日)Hibernate框架发布了3.0版本的第一个beta版本。据作者Gavin King表示,Hibernate 3.0将于明年(2005年)第一季度正式发布。Hibernate是一个基于POJO(Plain-Old Java Object,普通Java对象)的O/R mapping框架,也是目前J2EE社群最流行的对象持久化工具。正在制订中的EJB3规范就大量借鉴了Hibernate的经验。

 

在beta1版本中,Hibernate3并未提供对J2SE 5.0的支持,这主要是因为出于兼容性的考虑。Gavin King表示,将在2005年逐步引入J2SE 5.0提供的新语言特性,例如泛型、元数据标注等。

 

Hibernate3主要的新特性包括:

 

实现了EJB3风格的持久化操作。在原有的saveOrUpdate()和saveOrUpdateCopy()两个方法之外,又提供了EJB3风格的create()和merge()两个操作。

提供更强的映射灵活性。允许将一个类映射到多张表,允许混合使用“每个继承体系一张表”和“每个子类一张表”的映射策略,等等。

支持存储过程和手写SQL,并且可以用手写SQL替代Hibernate自动生成的SQL语句。

基于AST(抽象语法树)的HQL解析。

字段级的懒加载。每个属性都可以在映射描述符中声明“lazy=true”,这样声明的属性会到真正使用时才从数据库加载。不过,实现这项功能需要首先在编译期对字节码进行增强。

Hibernate最佳实践(Best Practices)

1、  使用Configuration装载映射文件时,不要使用绝对路径装载。最好的方式是通过getResourceAsStream()装载映射文件,这样Hibernate会从classpath中寻找已配置的映射文件。

2、  SessionFactory的创建非常消耗资源,整个应用一般只要一个SessionFactory就够了,只有多个数据库的时候才会使用多个SessionFactory。

3、  在整个应用中,Session和事务应该能够统一管理。(Spring为Hibernate提供了非常好的支持)

4、  将所有的集合属性配置设置为懒加载(lazy=”true”)。在hibernate2.x版本中,lazy默认值是“false”,但hibernate3.x已经将lazy的默认改为“true”了。

5、  在定义关联关系时,集合首选Set,如果集合中的实体存在重复,则选择List(在定义配置文件时,可以将List定义为bag),数组的性能最差。

6、  HQL子句本身大小写无关,但是其中出现的类名和属性名必须注意大小写区分。

7、  在一对多的双向关联中,一般将集合的inverse属性设为true,让集合的对方维护关联关系。例如:Group-User,由User来维护Group和User的关联关系。

8、  在非分布式架构中,不需要使用DTO来向上层传输数据。直接使用POJO的Entity就可以了。

在<many-to-one>中,将outer-join 设置为false。If the SQL statements use join operations that are too complex and

slow, set outer-join to false for <many-to-one> associations (this is

enabled by default). Also try to tune with the global hibernate.

max_fetch_depth configuration option, but keep in mind that this

is best left at a value between 1 and 4.

9、  如果要精通Hibernate,熟练掌握关系数据库理论和SQL是前提。

10、               

If the SQL statements use join operations that are too complex and

slow, set outer-join to false for <many-to-one> associations (this is

enabled by default). Also try to tune with the global hibernate.

max_fetch_depth configuration option, but keep in mind that this

is best left at a value between 1 and 4.