hibernate

 

HIBERNATE

hibernate常用类

sessionFactory(会话工厂)

是一个线程安全,终态的,代理对象,表示持久化对象和数据库的映射。作为建立session

(会话实例)的工厂。会话工厂建立的代价很大(内存,cpu占用大)所以一个程序只能

有一个会话工厂。会话工厂维护所以的 session,二级缓存,连接池,事务。

Session(会话)

单线程,短生命周期的对象,封装了JDBC连接对象java.sql.Connection

作为实例事务的对象,维护持久化对象可复读的持久化内容(一级缓存)。

Transaction(事务)

单线程,短生命周期的对象,用于界定物理事务的具体范围。

context session(上下文会话)

需要一个特定的session(会话)会影响整体特定的上下文范围。

Hibernate3以前使用session有两种方式:

  1. 利用TheadLocal(本地线程)加辅助类HibernateUtil建立session会话。
  2. 使用第三方框架如spring,框架提供上下文的session的代理或拦截。

从3版本开始通过sessionFactory.getCurrentSession()方法进行JTA事务处理。

跟踪当前会话的上下文

JTASessionContext:由JTA 事务界定当前会话范围与跟踪当前会话。

ThreadLocalSessionContext:由执行的线程跟踪当前会话。

ManagedSessionContext:由执行的线程跟踪当前会话。自己负责绑定与解绑

会话实例,通常在静态方法中处理,这时session不能打开,关闭,刷新。

前两种提供一次会话,一次事务。

持久化对象(域模型)

实现无参构造

提供标识(identifier)属性:在持久化对象中声明唯一标识列

使用非final类:运行时可以懒加载实体对象数据,这个功能依赖于实体类是非final类

为持久化属性声明get,set方法:遵守JavaBean实体规范

实现equals()与hashCode():数据库有实例相同的值,通过对象比较得到唯一的实例。

session和持久化实体对象关系

通过org.hibernate.Session API和javax.peristence.EntityManager API 处理持久化数据

环境,这个概念称为持久化上下文。

manged(托管态)原来叫Persistent 持久态

实体已经有了ID 并且与持久化上下文关联。在物理数据库中可能存在也可能不存在。

transient(瞬时态、临时态)

实体刚刚被实例化并且没有与持久化上下文关联。

 

detached(脱管态、游离态)

实体已经有了关联的ID,但是不再与持久化上下文关联。

 

removed(删除态)

实体已有了ID 并且与持久化上下文有了关联,然而数据库已经计划删除数据。

 

关系图

hibernate

 

 

 

 

 

 

 

 

 

hibernate配置

hibernate-cfg.xml

<!DOCTYPE hibernate-configuration PUBLIC
           "-//Hibernate/Hibernate Configuration DTD 3.0//EN"

        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<!--Hibernate的配置信息 -->

<hibernate-configuration>

    <!--配置工厂信息 -->

    <session-factory>

        <!--数据库连接配置-->

        <property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>

        <property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:orcl</property>

       <property name="hibernate.connection.username">user</property>

        <property name="hibernate.connection.password">pwd</property>

        <!--c3p0连接池-->

        <property name="hibernate.c3p0.min_size">5</property>

        <property name="hibernate.c3p0.max_size">10</property>

        <!--最小连接数超出取3个连接-->

        <property name="hibernate.c3p0.acquire_increment">3</property>

        <!--2秒超时-->

        <property name="hibernate.c3p0.timeout">2000</property>

        <!--活跃连接测试2秒检测一次当大于超时时间清空-->

        <property name="hibernate.c3p0.idle_test_period">2000</property>

        <!--hibernate配置-->

        <!--设置方言 指定为Oracle其它数据库执行sql无效例:mysql limit分页-->

        <property name="dialect">org.hibernate.dialect.OracleDialect</property>

        <!--hibernate mapper DDL 自动 -->

        <!--create执行SQL每次创建表,update有就刷新表数据,没有先创建表在执行SQL,其它省略:不会使用-->

        <property name="hbm2ddl.auto">update</property>

        <!--控制台输出执行SQL-->

        <property name="show_sql">true</property>

        <!--格式化SQL输出换行-->

        <property name="format_sql">true</property>

        <!--批量增删改100条提交一次(100最佳性能)-->

       <property name="hibernate.jdbc.batch_size">100</property>

       <!--批量查询读取记录50条查一次(50以上,性能提升的非常微弱)-->

       <property name="hibernate.jdbc.fetch_size">50</property>

        <!--数据库和持久化对象映射-->

        <mapping resource="MyTest.hbm.xml"/>

    </session-factory>

</hibernate-configuration>
 

myTest.hbm.xml

<!DOCTYPE hibernate-mapping PUBLIC
       "-//Hibernate/Hibernate Configuration DTD 3.0//EN"

        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<!--表和对象的映射-->

<!--对象所在entity-->

<hibernate-mapping package="com.cn.hibernate4.entity">

    <!--name为对象名 table数据库表名-->

    <!--动态处理数据有的数据处理NULL不进行操作-->

    <class name="MyTest" table="MY_TEST" dynamic-update="true" dynamic-insert="true">

        <!--id 主键 name对象字段 column为数据库列 数据类型长度 默认字符类型-->

        <id name="id" column="ID" length="32">

          <!--generator:主键生成策略

          1native:自动增长,会根据当前的数据库自动切换

          2identityDB2,MySQL, MS SQL Server, Sybase的自增

          3sequenceOracle的自增序列

          4uuid:32位字符串

          5assigned:自定义字符串

          6foreign:外键

          7increment:自增 多线程会出现异常-->

            <generator class="assigned"/>

        </id>

        <property name="name" column="NAME"/>

    </class>

</hibernate-mapping>

Test

import com.cn.hibernate5.entity.MyTest;
import com.cn.hibernate5.entity.MyTest;

import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.hibernate.Transaction;

import org.hibernate.cfg.Configuration;



public class Test {



    public static void main(String[] args) {

        //hibernate3.xhibernate5.x使用方式

        // 1、加载配置文件(在根目录下自动获取配置文件)

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

        Configuration config = new Configuration().configure("hibernate.cfg.xml");

        // 2、创建Session工厂

        SessionFactory sessionFactory = config.buildSessionFactory();

        // 3、创建Session对象

        Session session = sessionFactory.openSession();

        // 4、开启事务`

        Transaction transaction = session.beginTransaction();

        MyTest test = new MyTest("123", "失了智");

        // 5、添加

//        session.save(test);

//       //更新 通过MyTest.hbm.xml识别 id 进行name更新

//        session.update(test);

//       //删除 通过MyTest.hbm.xml识别 id 进行删除

//        session.delete(test);

//       // 查询 不需要事务

        session.load(MyTest.class, "123");

        // 6、提交事务

        transaction.commit();

        // 7、关闭会

        session.close();

        // 8、关闭session工厂

        sessionFactory.close();

    }

    //hibernate4获取session对象

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

//        ServiceRegistry service = new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry();

//        SessionFactory sessionFactory = config.buildSessionFactory(service);

//        final Session session = sessionFactory.openSession();

 

对象和对象的关系

多对一

多个学生对一个班级

<!DOCTYPE hibernate-mapping PUBLIC

   "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"
>
<hibernate-mapping
package="com.cn.hibernate5.entity">

<!--动态处理数据对象属性为null不进行赋值为空字符操作-->
    <class name="Student" table="my_student" dynamic-update="true" dynamic-insert="true">
        <id
name="stuId" column="stu_id" length="32">
            <generator
class="assigned"/>
        </id>
        <property
name="stuName" column="stu_name" not-null="true"/>
       
<!--设置外键-->
       
<many-to-one name="grade" column="g_id" class="Grade"/>
    </class>
</hibernate-mapping>

 

 

<!DOCTYPE hibernate-mapping PUBLIC

  "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"
>
<hibernate-mapping
package="com.cn.hibernate5.entity">
    <class
name="Grade" table="my_grade" dynamic-insert="true" dynamic-update="true">
        <id
name="gradeId" column="grade_id" length="32">
            <generator
class="assigned"/>
        </id>
        <property
name="gradeName" column="grade_name"/>
       
<!--一对多 -->
        <!--inverse
指由学生表去维护关系(有set的一方不去维护关系)-->
        <!--cascade
级联操作主表进行插入更新影响子表-->
       
<set name="students" table="my_student" inverse="true" cascade="save-update">
            <key
column="g_id"/>
            <one-to-many
class="Student"/>
        </set>
    </class>
</hibernate-mapping>

 

 

一对一

新增列设置外键

一个人对应一个身份证

<!DOCTYPE hibernate-mapping PUBLIC

  "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"
>
<hibernate-mapping
package="com.cn.hibernate5.entity">
    <class
name="Person" table="my_person" dynamic-insert="true" dynamic-update="true">
        <id
name="pId" column="person_id" length="32">
            <generator
class="assigned"/>
        </id>
        <property
name="pName" column="person_name"/>
       
<!--生成外键(并不是多对一通过unique指定关联的外键唯一不容许重复)-->
        <!--
使用many-to-one一定会设置数据库的对应的列-->
        <!--unique-key
多列设置才起效多列中不容许重复-->
       
<many-to-one name="Card" column="p_card" cascade="save-update" class="Card" unique="true"/>
    </class>
</hibernate-mapping>

 

 

<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"

        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.cn.hibernate5.entity">

    <class name="Card" table="my_card" dynamic-insert="true" dynamic-update="true">

        <id name="iId" column="card_id" length="32">

            <generator class="assigned"/>

        </id>

        <property name="iName" column="card_name"/>

        <!--配置人的身份证一对一的参考(关系参考[property-ref="Card"] 
可以不进行配置,不建议使用)自动识别 -->

        <one-to-one name="person" cascade="save-update" class="Person" property-ref="Card"/>

    </class>

</hibernate-mapping>
 

主键关联外键

<!DOCTYPE hibernate-mapping PUBLIC

    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"
>
<hibernate-mapping
package="com.cn.hibernate4.entity">
    <class
name="Person" table="my_person" dynamic-insert="true" dynamic-update="true">
        <id
name="pId" column="person_id" length="32">
           
<!—声明主键作为外键进行关联-->
           
<generator class="foreign">
               
<!—声明当前表外键值参考card表主键-->
               
<param name="property">card</param>
            </generator>
        </id>
        <property
name="pName" column="person_name"/>
       
<!--配置人的身份证一对一的参考-->
        <!--constrained="true"
添加当前表外键的外键约束关联card-->
       
<one-to-one name="card"  class="Card" constrained="true"/>
 
    </class>
</hibernate-mapping>

 

<!DOCTYPE hibernate-mapping PUBLIC

        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"
>
<hibernate-mapping
package="com.cn.hibernate4.entity">
    <class
name="IDCard" table="my_card" dynamic-insert="true" dynamic-update="true">
        <id
name="iId" column="card_id" length="32">
            <generator
class="assigned"/>
        </id>
        <property
name="iName" column="card_name"/>


             <one-to-one name="person" cascade="save-update" class="Person"/>
    </class>
</hibernate-mapping>

多对多

多对多是将多对多拆分为2个多对一

3张表

hibernate

 

<!DOCTYPE hibernate-mapping PUBLIC

     "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"
>
<hibernate-mapping
package="com.cn.hibernate4.entity">
   
<!--动态处理数据对象属性为null不进行赋值为空字符操作-->
   
<class name="Stu" table="my_stu" dynamic-update="true" dynamic-insert="true">
        <id
name="stuId" column="stu_id" length="32">
            <generator
class="uuid"/>
        </id>
        <property
name="stuName" column="stu_name" not-null="true"/>
       
<!--新建关系表(inverse="true"不可使用双方关系都需要维护)-->
       
<set name="courseSet" table="stu_course" >
           
<!--建立当前表外键关联当前表IDstu s_idstu_course-->
           
<key column="s_id"/>
           
<!--多对多关联关系表课程表id(通过关系表c_id关联课程表)-->
           
<many-to-many class="Course" column="c_id"/>
        </set>
    </class>
</hibernate-mapping>

 

 

<!DOCTYPE hibernate-mapping PUBLIC

<hibernate-mapping package="com.cn.hibernate4.entity">
   
<!--动态处理数据对象属性为null不进行赋值为空字符操作-->
   
<class name="Course" table="my_course" dynamic-update="true" dynamic-insert="true">
        <id
name="cId" column="c_id" length="32">
            <generator
class="uuid"/>
        </id>
        <property
name="cName" column="c_name" not-null="true"/>
       
<!--将多对多拆分为2个多对一-->
       
<set name="stuSet" table="stu_course">
           
<!--设置外键关联学生表-->
           
<key column="c_id"/>
           
<!--多对多关联课程表-->
           
<many-to-many class="Stu" column="s_id"/>
        </set>
    </class>
</hibernate-mapping>

对象和对象的关系

多对一

多个学生对一个班级

<!DOCTYPE hibernate-mapping PUBLIC

   "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"
>
<hibernate-mapping
package="com.cn.hibernate5.entity">

<!--动态处理数据对象属性为null不进行赋值为空字符操作-->
    <class name="Student" table="my_student" dynamic-update="true" dynamic-insert="true">
        <id
name="stuId" column="stu_id" length="32">
            <generator
class="assigned"/>
        </id>
        <property
name="stuName" column="stu_name" not-null="true"/>
       
<!--设置外键-->
       
<many-to-one name="grade" column="g_id" class="Grade"/>
    </class>
</hibernate-mapping>

 

 

<!DOCTYPE hibernate-mapping PUBLIC

  "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"
>
<hibernate-mapping
package="com.cn.hibernate5.entity">
    <class
name="Grade" table="my_grade" dynamic-insert="true" dynamic-update="true">
        <id
name="gradeId" column="grade_id" length="32">
            <generator
class="assigned"/>
        </id>
        <property
name="gradeName" column="grade_name"/>
       
<!--一对多 -->
        <!--inverse
指由学生表去维护关系(有set的一方不去维护关系)-->
        <!--cascade
级联操作主表进行插入更新影响子表-->
       
<set name="students" table="my_student" inverse="true" cascade="save-update">
            <key
column="g_id"/>
            <one-to-many
class="Student"/>
        </set>
    </class>
</hibernate-mapping>

 

 

一对一

新增列设置外键

一个人对应一个身份证

<!DOCTYPE hibernate-mapping PUBLIC

  "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"
>
<hibernate-mapping
package="com.cn.hibernate5.entity">
    <class
name="Person" table="my_person" dynamic-insert="true" dynamic-update="true">
        <id
name="pId" column="person_id" length="32">
            <generator
class="assigned"/>
        </id>
        <property
name="pName" column="person_name"/>
       
<!--生成外键(并不是多对一通过unique指定关联的外键唯一不容许重复)-->
        <!--
使用many-to-one一定会设置数据库的对应的列-->
        <!--unique-key
多列设置才起效多列中不容许重复-->
       
<many-to-one name="Card" column="p_card" cascade="save-update" class="Card" unique="true"/>
    </class>
</hibernate-mapping>

 

 

<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"

        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.cn.hibernate5.entity">

    <class name="Card" table="my_card" dynamic-insert="true" dynamic-update="true">

        <id name="iId" column="card_id" length="32">

            <generator class="assigned"/>

        </id>

        <property name="iName" column="card_name"/>

        <!--配置人的身份证一对一的参考(关系参考[property-ref="Card"] 
可以不进行配置,不建议使用)自动识别 -->

        <one-to-one name="person" cascade="save-update" class="Person" property-ref="Card"/>

    </class>

</hibernate-mapping>
 

主键关联外键

<!DOCTYPE hibernate-mapping PUBLIC

    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"
>
<hibernate-mapping
package="com.cn.hibernate4.entity">
    <class
name="Person" table="my_person" dynamic-insert="true" dynamic-update="true">
        <id
name="pId" column="person_id" length="32">
           
<!—声明主键作为外键进行关联-->
           
<generator class="foreign">
               
<!—声明当前表外键值参考card表主键-->
               
<param name="property">card</param>
            </generator>
        </id>
        <property
name="pName" column="person_name"/>
       
<!--配置人的身份证一对一的参考-->
        <!--constrained="true"
添加当前表外键的外键约束关联card-->
       
<one-to-one name="card"  class="Card" constrained="true"/>
 
    </class>
</hibernate-mapping>

 

<!DOCTYPE hibernate-mapping PUBLIC

        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"
>
<hibernate-mapping
package="com.cn.hibernate4.entity">
    <class
name="IDCard" table="my_card" dynamic-insert="true" dynamic-update="true">
        <id
name="iId" column="card_id" length="32">
            <generator
class="assigned"/>
        </id>
        <property
name="iName" column="card_name"/>


             <one-to-one name="person" cascade="save-update" class="Person"/>
    </class>
</hibernate-mapping>

多对多

多对多是将多对多拆分为2个多对一

3张表

<!DOCTYPE hibernate-mapping PUBLIC

     "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"
>
<hibernate-mapping
package="com.cn.hibernate4.entity">
   
<!--动态处理数据对象属性为null不进行赋值为空字符操作-->
   
<class name="Stu" table="my_stu" dynamic-update="true" dynamic-insert="true">
        <id
name="stuId" column="stu_id" length="32">
            <generator
class="uuid"/>
        </id>
        <property
name="stuName" column="stu_name" not-null="true"/>
       
<!--新建关系表(inverse="true"不可使用双方关系都需要维护)-->
       
<set name="courseSet" table="stu_course" >
           
<!--建立当前表外键关联当前表IDstu s_idstu_course-->
           
<key column="s_id"/>
           
<!--多对多关联关系表课程表id(通过关系表c_id关联课程表)-->
           
<many-to-many class="Course" column="c_id"/>
        </set>
    </class>
</hibernate-mapping>

 

 

<!DOCTYPE hibernate-mapping PUBLIC

<hibernate-mapping package="com.cn.hibernate4.entity">
   
<!--动态处理数据对象属性为null不进行赋值为空字符操作-->
   
<class name="Course" table="my_course" dynamic-update="true" dynamic-insert="true">
        <id
name="cId" column="c_id" length="32">
            <generator
class="uuid"/>
        </id>
        <property
name="cName" column="c_name" not-null="true"/>
       
<!--将多对多拆分为2个多对一-->
       
<set name="stuSet" table="stu_course">
           
<!--设置外键关联学生表-->
           
<key column="c_id"/>
           
<!--多对多关联课程表-->
           
<many-to-many class="Stu" column="s_id"/>
        </set>
    </class>
</hibernate-mapping>

检索策

类级别

立即检索

get()

延时检索

load()

get()和load()区别

Get:hibernate会确认该对象id对应的数据是否存在,先去缓存中查询没有查询数据库,数据库没有返回为null。(get查询的结果直接赋值给对象,session关闭对象不为空)。

Load:hibernate认为该id有对用的数据库记录,先去缓存中查询没有创建代理,所以可以放心使用使用代理延时加载该对象。没有对应数据库记录抛出ObjectNotFound异常。(使用的代理对象,session关闭,对象再获取值为null)。

级联级别

 默认:fetch=”select”

另外发送一条select语句抓取当前对象关联实体或集合。(两条SQL

fetch=”join”

hibernate会通过select语句使用外连接来加载其关联实体或集合(一条SQLSQL关键字left outer join)

此时lazy会失效

 

fetch=”subselect”

嵌套子查询 SQL关键字in