hibernate学习——hibernate配置与关联总结

来源:互联网 发布:js 发布者订阅者模式 编辑:程序博客网 时间:2024/05/24 07:30

hibernate的概述

        Hibernate是一个免费的开源Java包,是目前最流行的ORM框架,它是一个面向Java环境的对象/关系数据库映射工具。也是一个轻量级的O/R Mapping框架,它使得程序与数据库的交互变得十分容易,更符合面向对象的设计思想,像数据库中包含普通Java对象一样,而不必考虑如何把它们从数据库表中取出。使开发者可以专注于应用程序的对象和功能,而不必关心如何保存它们或查找这些对象。甚至在对SQL语句完全不了解的情况下,使用hibernate仍然可以开发出优秀的包含数据库访问的应用程序。

       首先,学习任何一门新的框架首先要理解它所解决的问题域。Hibernate是一个解决对象关系映射的框架ORM,这说明ORM必须遵循一定的规则,否则就不可能形成框架。ORM遵循的基本规则是什么呢?用这样四句话进行总结:

        1. 类型(class)对应表(table);

        2. 属性(property)对应列(column), 必须有特殊属性对象标识符(id)对应主键(primary key);

        3. 类型的关联(association)关系对应外键(foreign key);

        4.类型的实例即对象(object)对应记录(record)或行(row)。

       前三项描述的是静态特性,映射文件主要描述的就是这三项静态特性。ORM技术O在前,当然映射文件应以其对应的类型(class)为中心进行描述。Gavin King在使用XML时喜欢用元素的属性来描述不具扩展前景的数据, 其中name属性描述java程序中JavaBean的属性(属性值大小写敏感)。

 

 持久化层含义

      基于B/S的典型三层架构

      访问数据库代码(Dao)与业务逻辑(Service)混杂在一起带来了很多问题,这样的程序设计严重限制了程序的可扩展性和适应性,所以有必要要把涉及数据库操作的代码分离出来与业务逻辑分离。就形成了所谓“持久化层”的概念。持久化(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的数据存储在关系型的数据库中,当然也可以存储在磁盘文件中、XML数据文件中等等。

 

hibernate的工作原理

     1. 读取并解析配置文件

     2. 读取并解析映射信息,创建SessionFactory

     3. 打开Sesssion

     4. 创建事务Transation

     5. 持久化操作

     6. 提交事务

     7. 关闭Session

     8. 关闭SesstionFactory

如下所示:

             启动Hibernate 

             构建Configuration实例,初始化该实例中的所有变量               Configuration cfg = new Configuration().configure(); 

             加载hibernate.cfg.xml文件至该实例内存 

             通过hibernate.xfg.xml文件中的mapping节点配置,加载hbm.xml文件至该实例内存利用上面创建的Configuration实例构建一个SessionFactory实 例          SessionFactory sf = cfg.buildSessionFactory(); 

             由上面得到的SessionFactory实例创建连接 Session s = sf.openSession()

             由上面得到的Session实例创建事务操作接口Transaction的一个实例  tx Transaction tx = s.beginTransaction(); 

             通过Session接口提供的各种方法操作数据库的访问 提交数据库的操作结果 tx.commit(); 

             关闭Session链接 s.close(); 

 

 

关联映射

       Hibernate配置文件 

       • Hibernate配置文件主要用于配置数据库连接和 Hibernate 运行时所需的各种属性

       • 每个 Hibernate 配置文件对应一个 Configuration 对象。

       • Hibernate配置文件可以有两种格式:

          –hibernate.properties

          –hibernate.cfg.xml 

       hibernate.cfg.xml的常用属性

       • connection.url:数据库URL 

       • connection.username:数据库用户名

       • connection.password:数据库用户密码 

       • connection.driver_class:数据库JDBC驱动 

       • show_sql:是否将运行期生成的SQL输出到日志以供调试。取值 true | false 

       • dialect:配置数据库的方言,根据底层的数据库不同产生不同的sql语句,Hibernate 会针对数据库的特性在访问时进行优化。 

       • hbm2ddl.auto:在启动和停止时自动地创建,更新或删除数据库模式。取值 create | update | create-drop

       • mapping resource:映射文件配置,配置文件名必须包含其相对于根的全路径

       • connection.datasource :JNDI数据源的名称  Prepared by TongGang Prepared by TongGang

     

      jdbc.fetch_size 和 jdbc.batch_size

      • jdbc.fetch_size:实质是调用 Statement.setFetchSize() 方法设定JDBC的Statement读取数据的时候每次从数据库中取出的记录条数。当然Fetch Size设的越大,读数据库的次数越少,速度越快;Fetch Size越小,读数据库的次数越多,速度越慢。

      • hibernate.jdbc.batch_size:设定对数据库进行批量删除,批量更新和批量插入的时候的批次大小,有点相当于设置Buffer缓冲区大小的意思。Batch Size越大,批量操作的向数据库发送sql的次数越少,速度就越快。这两个选项非常重要,将严重影响Hibernate CRUD(create,read,update,delete)性能!

 

配置 c3p0数据库连接池 

      • c3p0连接池是Hibernate推荐使用的连接池,若需要使用该连接池时,需要将c3p0的jar包拷贝到 WEB-INF 的 lib 目录下 。POJO 类和数据库的映射文件*.hbm.xml

      • POJO 类和关系数据库之间的映射可以用一个XML文档(XML document)来定义。映射按照POJO的定义来创

建,而非表的定义。

      • 通过 POJO 类的数据库映射文件,Hibernate可以理解持久化类和数据表之间的对应关系,也可以理解持

久化类属性与数据库表列之间的对应关系

      • hibernate-mapping

      –类层次:Class

      • 主键。id

      • 基本类型:property

      • 自定义类:many-to-one  |  one-to-one

      • 集合:set | list | map | array

       –one-to-many

       –many-to-many

      • 子类:subclass | joined-subclass

      • 其它:component | any等

       –查询语句:query(用来放置查询语句,便于对数据库查询的统一管理和优化)

     注意:一个Hibernate-mapping中可以同时定义多个类。

         

<hibernate-mapping

         schema="schemaName" 

  catalog="catalogName"

         default-cascade="cascade_style" 

    default-access="field|property|ClassName"    

         default-lazy="true|false"                    

         auto-import="true|false"                     

         package="package.name"   />  

                  

• hibernate-mapping 是 hibernate 映射文件的根元素

• schema (可选): 数据库schema的名称。

• catalog (可选): 数据库catalog的名称。  

• default-cascade (可选 - 默认为 none): 默认的级联风格。  

• default-access (可选 - 默认为 property): Hibernate用来访问属性的策略。可以通过实现PropertyAccessor接口自定义。  

• default-lazy (可选 - 默认为 true): 指定了未明确注明lazy属性的Java属性和集合类, Hibernate会采取什么样的默认加载风格。 

• auto-import (可选 - 默认为 true): 指定我们是否可以在查询语言中使用非全限定的类名(仅限于本映射文件中的类)。 

• package (可选): 指定一个包前缀,如果在映射文档中没有指定全限定的类名, 就使用这个作为包名。 

<class 

    name="ClassName" 

    table="tableName" 

    discriminator-value="discriminator_value" 

    mutable="true|false" 

    schema="owner" 

    catalog="catalog" 

    proxy="ProxyInterface" 

    dynamic-update="true|false" 

    dynamic-insert="true|false" 

    select-before-update="true|false" 

    polymorphism="implicit|explicit" 

    where="arbitrary sql where condition" 

    persister="PersisterClass" 

    batch-size="N" 

    optimistic-lock="none|version|dirty|all" 

    lazy="true|false" 

    entity-name="EntityName" 

    check="arbitrary sql check condition" 

    rowid="rowid" 

    subselect="SQL expression" 

    abstract="true|false" 

    node="element-name" 

/> 

• Class:定义一个持久化类 

• name (可选): 持久化类(或者接口)的类名

• table (可选 - 默认是类的非全限定名): 对应的数据库表名

• discriminator-value (可选 - 默认和类名一样): 一个用于区分不同的子类的值,在多态行为时使用。它可以接受的值包括 null 和 not null。 

主键-id

<id 

       name="propertyName" 

       type="typename" 

       column="column_name" 

       unsaved-value="null|any|none|undefined|id_value"   

       access="field|property|ClassName" 

       node="element-name|@attribute- name|element/@attribute|.">

           <generator class="generatorClass"/> 

</id> 

• Id:被映射的类必须定义对应数据库表主键字段。大多数类有一个

JavaBean风格的属性, 为每一个实例包含唯一的标识。<id> 元素定义了该属性到数据库表主键字段的映射。 

• name (可选): 标识持久化类属性的名字。  

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

• column (可选 - 默认为属性名): 主键字段的名字。

Prepared by TongGang Prepared by TongGang

主键生成策略generator 

• 可选的<generator>子元素是一个Java类的名字, 用来为该持久化类的实例生成唯一的标识。如果这个生成器实例需要某些配置值或者初始化参数, 用<param>元素来传递。 

• 所有的生成器都实现org.hibernate.id.IdentifierGenerator接口。某些应用程序可以选择提供他们自己特定的实现。当然, Hibernate提供了很多内置的实现。

基本类型-property

<property 

    name="propertyName" 

    column="column_name" 

    type="typename" 

    lazy="true|false" 

    unique="true|false" 

    not-null="true|false" 

    optimistic-lock="true|false" /> 

• property:为类定义了一个持久化的,JavaBean风格的属性 

• name: 属性的名字,以小写字母开头。  

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

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

• lazy (可选 - 默认为 false): 指定实例变量第一次被访问时,这个属性

是否延迟抓取(fetched lazily)。  

• unique (可选): 为该字段添加唯一的约束。

• not-null (可选):为该字段添加非空约束。  

• optimistic-lock (可选 - 默认为 true): 指定这个属性在做更新时是否需要获得乐观锁定(optimistic lock)。

映射集合属性

• 集合属性大致有两种:

–单纯的集合属性,如像List、Set或数组等集合属性

–Map结构的集合属性,每个属性值都有对应的Key映射 

• 集合映射的元素大致有如下几种: 

–list:用于映射List集合属性 

–set:用于映射Set集合属性 

–map:用于映射Map集合性 

–array:用于映射数组集合属性 

–bag:用于映射无序集合 

–idbag:用于映射无序集合,但为集合增加逻辑次序 

List集合映射

• List是有序集合,因此持久化到数据库时也必须增加一列来表示集合元素的次序。看下面的持久化类,该News类有个集合属性:schools,该属性对应学校。而集合属性只能以接口声明,因此下面代码中,schools的类型能是List,不能是ArrayList,但该集合属性必须使用实现类完成初始化。 

List集合映射

• 在作相应映射时,list元素要求用list-index的子元素来映射有序集合的次序列。集合的属性的值会存放有另外的表中,不可能与持久化类存储在同一个表内。因此须以外键关联,用Key元素来映射该外键列。 

Set集合映射

• Set集合属性映射与List非常相似,但因为Set是无序的,不可重复的集合。因此set元素无须使用index元素来指定集合元素次序。映射文件与List相似,区别在于使用set元素时,无须增加index列来保存集合的次序 

注:映射 Set 集合属性时,如果 element 元素包括 not-null = “true” 属性,则集合属性表以关联持久化类的外键和元素列作为联合主键,否则该表没有主键。但 List 集合属性不会,List 集合属性总是以外键列和元素此序列作为联合主键。

bag元素映射 

• bag元素既可以为List集合属性映射,也可以为Collection集合属性映射。不管是哪种集合属性,使用bag元素都将被映射成无序集合,而集合属性对应的表没有主键。Bag 元素只需要 key 元素来映射外键列,使用 element 元素来映射集合属性的每个元素。 

Map集合属性 

• Map不仅需要映射属性值,还需要映射属性Key。映射Map集合属性时,同样需要指定外键列,同时还必须指定Map的Key列。系统将以外键列和Key列作为联合主键。 Map集合属性使用map元素映射时,该map元素需要key和map-key两个子元素。其中key子元素用于映射外键列,而map-key子元素则用于映射Map集合的Key。而map-key和element元素都必须确定type属性  

集合属性的性能的分析 

• 对于集合属性,通常推荐使用延迟加载策略。所谓延迟加载就是当系统需要使用集合属性时才从数据库装载关联的数据。

Hibernate对集合属性默认采用延迟加载,在某些特殊的情况下为set,,list,map等元素设置lazy=“false”属性来取消

延迟加载。

• 可将集合分成如下两类:

–有序集合:集合里的元素可以根据Key或Index访问 

–无序集合:集合里的元素中只能遍历 

–有序集合拥有由 key 和 index 组成的联合主键,集合的属性在增加、删除及修改中拥有较好的性能表现 ---- 主键已经被有效的索引,因此 Hibernate 可以迅速的找到该行数据。

–映射Set集合属性时,如果element元素包括not-null=“true”属性,则集合属性表以关联持久化类的外键和元素列作为联合主键,否则该表没有主键,因此性能较差。

–在设计较好的Hiberate domain Object中,集合属性通常都会增加inverse=“true”的属性,此时集合端不再控制关联关系。因此无需考虑集合的更新性能。 

映射组件属性

• 组件属性的意思是持久化类的属性既不是基本数据类型,也不是 String 字符串,而是某个组件变量,该组件属性的类型可以是自定义类。

映射组件属性

• 显然无法直接用 property 映射 name 属性。为了映射组件属性, Hibernate 提供了 component 元素。每个 component 元素映射一个组件属性,组件属性必须指定该属性的类型,component 元素中的 class 属性用于确定组件的类型。 

集合组件属性映射

• 集合除了存放 String 字符串以外,还可以存放组件类型。实际上,更多情况下,集合组件存放的都是组件类型。

• 对于有集合属性 POJO, 需要使用 set, list, bag 等集合元素来映射集合属性。如果集合里的元素是普通字符串,则使用 element映射集合元素即可。如果集合元素也是定义类,则需使用 composite-element 子元素来映射集合元素,      composite-element 元素映射一个组件类型,因此需要 class 元素确定元素的类型,该元素还支持 property 的子元素来定义组件类型的子属性

Hibernate 的关联关系映射

• 客观世界中的对象很少有孤立存在的。关联关系是面

向对象分析,面向对象设计最重要的知识。关联关系

大致有如下两个分类:

–单向关系:只需要单向访问关联端

• 单向 1-1

• 单向 1-N(不推荐使用)

• 单向 N-1

• 单向 N-N

–双向关系:关联的两端可以相互访问

• 双向 1-1

• 双向 1-N

• 双向 N-N

单向 N-1

• 单向 N-1 关联只需从 N 的一端可以访问 1 的一端。模型:多个人(Person)对应同一个地址(Address)。只需要从人实体端找到相应的地址实体。无须关心从某个地址找到全部住户。 

• 单向 1-1,POJO 与 N-1 没有丝毫区别。

• 基于外键的单向 1-1 映射文件:只需要在原有的 many-to-one 元素添加 unique=“true”,用以表示 N 的一端必须唯一即可,N的一端增加了唯一约束, 即成为单向 1-1.

基于主键的单向 1-1

• 基于主键关联的持久化类不能拥有自己的主键生成器,它的主键由关联类负责生成。增加one-to-one元素来映射关联属性,必须为one-to-one元素增加constrained="true"属性,表明该类的主键由关联类生成。

单向的 1-N

• 单向 1-N 关联的 POJO 需要使用集合属性。因为一的一端需要访问 N 的一端,而 N 的一端将以集合的形式表现。

• 不推荐使用单向的 1-N 关联:

–使用 1 的一端控制关联关系时,会额外多出 update 语句。

–插入数据时无法同时插入外键列,因而无法为外键列添加非空约束

单向的 N-N

• 单向 N-N,POJO 与 1-N 没有丝毫区别。

• 与映射集合属性类似,必须为set,list等集合元素添加 key 子元素,用以映射关联的外键列。与集合映射不同的是,建立 N-N 关联时,集合中的元素使用 many-to-many,而不是使用 element 子元素

• N-N 的关联必须使用连接表。

双向 1-N

• 对于 1-N 的关联,Hibernate 推荐使用双向关联,而且不要让 1 的一端控制关联关系,而是使用 N 的一端控制关联关系。

• 双向 1-N 与 N-1 是完全相同的两种情形

双向 1-N

• 1 的一端需要使用集合属性元素来映射关联关系。集合属性元素同样需要增加 key 元素,还需要使用 one-to-many 元素来映射关联属性

双向 1-N

• N 的一端需要增加 many-to-one 元素来映射关联属性。

 注意:在上面的配置文件中,两个持久化类的配置文件都需要指定外键列的列名,此时不可以省略。因为不使用连接表的1-N关联的外键,而外键只保存在N一端的表中,如果两边指定的外键列名不同,将导致关联映射出错。如果不指定外键列的列名,该列名由系统自动生成,而系统很难保存自动生成的两个列名相同。

双向1-1关联 

• 单向的1-1关联有三种映射策略:基于主键,基于外键和使用连接表。双向的1-1关联同样有这三种映射策略。

• 双向的1-1关联需要修改POJO类,让两边都增加对关联类的访问基于外键的双向1-1关联 

• 对于基于外键的1-1关联,其外键可以存放在任意一边,在需要存放外键一端,增加many-to-one元素。为many-to-one元素增加unique=“true” 属性来表示为1-1关联,并用name属性来指定关联属性的属性名。

• 另一端需要使用one-to-one元素,则该元素使用name属性指定关联的属性名。为了让系统懂得不再为本表增加一列,因此使用外键关联,用property-ref属性来引用关联类的主键。

• property-ref:指定目标实体的表中外键引用的列。如果引用表的外键不引用关系的”多”端的主键,可以使用p该属性指定它应用的列。这应该只用于已有数据库的数据库设计 ---- 在创建新的数据库模式时,外键总是应该引用相关表的主键。  

基于主键的双向1-1关联 

• 基于主键的映射策略:指一端的主键生成器使用foreign略,表明根据对方的主键来生成自己的主键,自己并不能独立生成主键。

• 任意一边都可以采用foreign主键生成器,表明根据对方主键生成自己的主键。

• 采用foreign主键生成器策略的一端增加one-to-one元素映射关联属性,其one-to-one属性还应增加constrained=“true”属性;另一端增加one-to-one元素映射关联属性。

• constrained(约束) :表明该类对应的表对应的数据库表,和被关联的对象所对应的数据库表之间,通过一个外键引用对

主键进行约束。

继承映射

• 对于面向对象的程序设计语言而言,继承和多态是两个最基本的概念。Hibernate 的继承映射可以理解持久化类之间的

继承关系。例如:人和学生之间的关系。学生继承了人,可以认为学生是一个特殊的人,如果对人进行查询,学生的实例也将被得到。

继承映射

• Hibernate支持三种继承映射策略:

–每个具体类一张表(table per concrete class) 将域模型中的每一个实体对象映射到一个独立的表中,也就是说

不用在关系开数据模型中考虑域模型中的继承关系和多态。 

–每个类分层结构一张表(table per class hierarchy) 对于继承关系中的子类使用同一个表,这就需要在数据库表中增加额外的区分子类类型的字段。 

–每个子类一张表(table per subclass) 域模型中的每个类映射到一个表,通过关系数据模型中的外键来描述表之间的继承关系。这也就相当于按照域模型的结构来建立数据库中的表,并通过外键来建立表之间的继承关系。

采用 subclass 元素的继承映射

• 采用 subclass 元素的继承映射可以实现对于继承关系中的子类使用同一个表

• 在这种映射策略下,整个继承树的所有实例都保保存在同一个表内。因为父类和子类的实例全部保存在同一个表中,因

此需要在该表内增加一列,使用该列来区分每行记录到低是哪个类的实例----这个列被称为辨别者列(discriminator).

• 在这种映射策略下,使用 subclass 来映射子类,使用 discriminator-value 指定辨别者列的值

注:所有子类定义的字段都不能有非空约束。如果为那些字段添加非空约束,那么父类的实例在那些列根本没有值,这将引起数据库完整性冲突,导致父类的实例无法保存到数据库中

采用 joined-subclass 元素的继承映射

• 采用 joined-subclass 元素的继承映射可以实现每个子类一张表

• 采用这种映射策略时,父类实例保存在父类表中,子类实例由父类表和子类表共同存储。因为子类实例也是一个特殊的父类实例,因此必然也包含了父类实例的属性。于是将子类和父类共有的属性保存在父类表中,子类增加的属性,则保存在子类表中。

• 在这种映射策略下,无须使用鉴别者列,但需要为每个子类使用 key 元素映射共有主键,该主键必须与父类标识属性的列名相同。但如果继承树的深度很深,可能查询一个子类实例时,需要跨越多个表,因为子类的数据一次保存在多个父类中。

• 子类增加的属性可以添加非空约束。因为子类的属性和父类的属性没有保存在同一个表中采用 union-subclass 元素的继承映射

• 采用 union-subclass 元素可以实现将每一个实体对象映射到一个独立的表中。

• union-subclass 与 joined-subclass 映射策略类似:子类增加的属性也可以有非空约束 --- 即父类实例的数据保存在父表中,而子类实例的数据保存在子类表中。

• 与 joined-subclass 不同的是,子类实例的数据仅保存在子类表中,而在父类表中没有任何记录。

• 在这种映射策略下,子类表的字段会比父类表的映射字段要多,因为子类表的字段等于父类表的字段加子类增加属性的总和

• 在这种映射策略下,既不需要使用鉴别者列,也无须使用 key 元素来映射共有主键.

 

          HIBERNATE学习(未完待续)

 

 

 

        

    

        

原创粉丝点击