※※※ Hibernate不适合的场景:不适合批量的查询和更新 ※※※

a.不适合OLAPOn-Line Analytical Processiong 联机分析处理),以查询分析数据为主的系统

适合OLTP(On-Line transaction processing 联机事务处理)

b. 对于些关系模型设计不合理的老系统,也不能发挥hibernate优势

c 数据量巨大,性能要求苛刻的系统,hibernate也很难达到要求,批量操作数据效率也不高

 

 

Configuration:用于解析hibernate.cfg.xml文件和XXXXX.hbm.xml文件,并创建SessionFactory对象。

Session:是非线程安全的,生命周期较短,代表一个和数据库的连接,在B/S系统中一般不会超过一个请求;内部维护一级缓存和数据库连接,如果session长时间打开,会长时间占用内存和数据库连接。

SessionFactory:持久化管理器,对象级数据库操作;是线程安全的,一个数据库对应一个SessionFactory,生命周期长,一般在整个系统生命周期内有效;SessionFactory保存着和数据库连接的相关信息(userpasswordurl)和映射信息,以及Hibernate运行时要用到的一些信息。

Query:对对象作持久化操作或查询操作

Transaction :用于管理操作事务。

 

实体对象的生命周期

 

了解sessionCURD操作

 

了解session.get()session.load()方法的区别

    * get不支持lazyload支持lazy

    * 采用get加载数据,如果数据库中不存在相应的数据,那么返回null

    * 采用load加载数据,如果数据库中不存在相应的数据,那么抛出ObjectNotFoundException

   

Transient(瞬时)状态

    * 不存在 session缓存中,不和任何session实例有关联

    * 在数据库中没有相应的记录

   

Persistent(持久)状态

    * 位于session缓存中,Persistent状态的对象总是和session实例相关联

    * Persistent状态的对象和数据库表中的记录有对应

    * Persistent状态的对象发生改变会自动和数据库同步

   

Detached(分离)状态

    * 不处于session缓存中,不和任何session实例有关联

    * Detached状态的对象在数据库中有与之对应的记录

 

Hibernate内置的主键生成策略

1,序列sequence 只适用于Oracle  

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

    <generator class="sequence">

        <param name="sequence">person_seq</param><!--指定sequence-->

    </generator>

</id>

2,自增列,适用于SQLServerMySql

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

    <generator class="identity"/>

</id>

3,取最大值加一

<id name="id" column="id" type="integer">

    <generator class="increment"/>

</id>

4,根据底层数据库指定生成方法

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

        <generator class="native"/>

    </id>

使用缺省策略   

针对Oracle数据库的生成方式还是sequence,只不过需要一个特定名字的sequence"hibernate_sequence"

5,高低位算法

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

        <generator class="hilo">

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

            <!--设置高位值取值的表-->

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

            <!--设置高位值取值的字段-->

            <param name="max_lo">50</param>

            <!--指定低位最大值,当取道最大值是会再取一个高位值再运算-->

        </generator>

</id>

以上是hilo算法的普通形式,不适合用于squenece

 

其它。assigned(手工指定),foreign(外部引用)

uuid (使用了IP地址+JVM的启动时间(精确到1/4秒)+系统时间+一个计数器值(在JVM中唯一))

 

 

Hibernate基本映射

 

实体类à数据库表

 

普通属性à表字段

 

    通过<class>标签映射成数据库表, name属性表示这个类的全路径

    通过<property>标签将普通属性映射成数据库表的字段

    所谓普通属性指不包含自定义类,集合,数组等等

   

    实体类中的String会映射成数据库中的varchar类型

   

实体类的设计原则

    * 实现一个无参的构造方法

    * 提供一个标识属性  (可选)

    * 使用非final(可选)(如果使用的话,lazy属性就会失效)

    * 为持久化字段声明访问器(get,set方法)

   

 

主键生成策略

    * uuid (字符串作为主键)

    * native (数字作为主键,效率低,并发不太好)

    * assigned (手动分配)

 

注意:类的名称或类中属性名称,如果和SQL中的关键字重复,必须用tablecolumn属性重命名

 

 

Hibernate【多对一】关联映射

 

关联映射的本质:

    将关联关系映射到关系表,关联关系在对象模型中体现为一个或多个引用

   

<many-to-one>会在的一端添加一个外键,指向的一端。

    这个外键是由<many-to-one>中的column属性定义的,如果忽略这个属性,默认外键与实体类的属性一致

   

    注意: 如果实体类的名称和属性与sql关键字重复,必须重新命名

   

<many-to-one>标签示例:

    * <many-to-one name="Group" column="groupid"/>

   

理解级联的含义

    对象之间的连锁操作(只对【增**改】起作用)

    <many-to-one name="group" column="groupid" cascade="save-update"/>

 

Persistent状态的对象不能引用Transient状态的对象

 

 

Hibernate一对一【主键】关联映射

(单向关联Person--->IdCard

 

一对一主键关联映射:让两个实体对象的id保持相同,这样可以避免多余的字段被创建  

具体映射方式:

    <class name="com.bin.hibernate.Person" table="t_person">

       <id name="id">

           <!-- Person主键来源于IdCard,共享IdCard的主键  -->

           <generator class="foreign">

              <param name="property">idCard</param>

           </generator>

       </id>

       <property name="name"/> 

      

       <!-- one-to-one标签只是hibernate如何加载其引用对象,默认根据主键加载,

       constrained="true":表明当前主键上存在一个约束,Person的主键作为外键参照了IdCard -->

       <one-to-one name="idCard" constrained="true"/>

    </class>

 

在一对一关联映射中,存储person对象,其关联的IdCard也同时被存储

而不会抛出TransientObjectException异常,因为它默认了级联属性

 

one-to-one标签不在数据库表里加外键的字段

(双向关联Person <---> IdCard)

 

需要在IdCard中加入<one-to-one>标签指向person,指示hibernate如何加载Person,默认根据主键加载

 

 

hibernate一对一【唯一外键】关联映射

 

(单向关联Person--->IdCard

 

一对一唯一外键关联映射实际上就是多对一关联映射的特例

 

可以采用<many-to-one>标签,指定的一端的unique=true,即限制了的一端的多重性为

通过这种手段来映射一对一唯一外键关联

 

(双向关联Person<--->IdCard

 

一对一唯一外键双向关联映射,需要在另一端(idCard)添加<one-to-one>标签,指示hibernate如何加载其引用对象。

默认情况下根据主键加载Person,因为外键关联映射中两个实体的关系是通过person中的idCard维护的,所以不能根据person的主键来加载,

而是根据person的外键来加载person对象,如:

    <one-to-one name="person" property-ref="idCard"/>

 

session.flush测试

 

session.flush主要做两件事:

  * 清理缓存(脏数据对比)

  * 执行SQL(不代表提交事务)

 

hibernateSQL的执行顺序

  hibernate按照save(insert)updatedelete顺序提交相关操作

 

(1)、如果user的主键生成策略是uuid,所以调用完save后,只是将user纳入了session管理,不会发出SQL,但userid已经生成,session中的existsDatabase状态为false

(2)、调用flushhibernate会清理缓存,执行SQL

    如果将数据库的隔离级别设置为未提交读,此时可以看到flush过的数据,并且session中的existsDatabase状态为true

(3)、默认情况下commit会首先执行flush来清理缓存,所以不用显式的调用flush

    commit后无法回滚事务

hibernate【一对多】关联映射(单向)

 

这个映射的本质:采用多对一映射原理

 

多对一关联映射:在的一端加入一个外键,指向的一端,它维护的是多到一的关系

一对多关联映射:在的一端加入一个外键,指向的一端,它维护的是一到多的关系

    <set name="students">

           <!-加外键,在的一端加一个外键,名字叫classesid->

           <key column="classesid"/>

           <one-to-many class="com.bin.hibernate.Student"/>

    </set>

   

    也就是说一对多和多对一映射策略是一致的,只是站的角度不同

   

一对多关联映射让hibernate的一端维护关系存在缺点

    * 会发出多余的update语句,建立班级和学生之间的关系,影响性能

    * 如果student表中的classesid设置为非空,将无法保存数据

 

 

Hibernate【一对多】关联映射(双向)

 

一对多双向关联映射:

    * 的一端的集合上使用<key>标签,在对方表中加入一个外键指向的一端

       <set name="students" inverse="true">

           <key column="classesid"/>

           <one-to-many class="com.bin.hibernate.Student"/>

       </set>

      

    * 的一端采用<many-to-one>

       <many-to-one name="classes" column="classesid"/>

      

    注意<key>标签所指定的外键字段名需要与<many-to-one>标签定义的外键字段名一致,否则便会造成引用数据的丢失!

   

-----------------------------------------------------------------------

如果从一端来维护一对多双向关联的关系,hibernate会发出多余的update语句,所以

一般地情况下,我们便会从多一端来维护其关联关系!

------------------------------------------

 

 

Hibernate【多对多】关联映射(双向)

    <set name="roles" table="t_user_role">

           <key column="userid"/>

           <many-to-many class="com.bin.hibernate.Role" column="roleid"/>

    </set>

   

    table属性必须和单向关联中table的名称相同

    <key>中的column属性值必须等于单向关联中<many-to-many>标签指向的column的属性值

    <many-to-many>column属性值必须等于单向关联中<key>column的属性值