Hibernate随笔

Hibernate:

  • 一个持久化框架
  • 一个ORM框架
  • 加载:根据特定的OID,把一个对象从数据库加载到内存中
    • OID(对象标识,Object-identifier):为在系统中找到所需要的对象,需要为每一个对象分配一个唯一的标识号,类似于数据库中的主键

ORM(Object/Relation Mapping):对象/关系映射

  • ORM主要解决对象-关系型映射
    Object Releationship Mapping
  • ORM思想:将关系数据库中表中的记录映射成为对象,以对象的形式扩展,程序员可以将数据库的操作转化为对对象的操作

  • ORM采用元数据来描述对象-关系映射,元数据通常采用XML格式,并且存放在专门的对象-关系文件中

  • ORM架构:
    Paste_Image.png

流行的ORM框架:

  • Hibernate:
    • 优秀、成熟的ORM框架
    • 完成对象的持久化操作
    • Hibernate允许开发者采用面向对象的方式来操作关系数据库
    • 消除那些针对特定数据库厂商的SQL代码
  • Mybatis:
    • 比Hibernate灵活,运行速度快
    • 开发速度慢,不支持纯粹的面向对象操作,需要熟悉sql语句,并且熟练使用sql语句优化功能
  • TopLink
  • OJB

Hibernate与JDBC代码的(保存)对比,如:

  • Hibernate:
public void save(Session session, Message msg){
 session.save(msg);
}
  • JDBC:
public void save(Connection conn, Message msg){
  PrepareStatement ps = null;
  String sql = "insert into msg values (?,?)";
  try{
    ps = conn.prepareStatement(sql);
    ps.setString(1, msg.getTitle());
    ps.setString(2,msg.getContent());
    ps.execute();
  }catch(Exception e){
    e.printStackTrace();
  }finally{
    if(ps != null){
      try{
        ps.close();
      }catch(Exception e){
        e.printStackTrace(); 
      }
    }
  }
}

Hibernate插件的安装:
Hibenate插件安装

Hibernate开发环境:

  • 导入Hibernate必须的jar包:
 antlr-2.7.7.jar
dom4j-1.6.1.jar
hibernate-commons-annotations-4.0.2.Final.jar
hibernate-core-4.2.4.Final.jar
hibernate-jpa-2.0-api-1.0.1.Final.jar
javassist-3.15.0-GA.jar
jboss-logging-3.1.0.GA.jar
jboss-transaction-api_1.1_spec-1.0.1.Final.jat
  • 加入数据库驱动的jar包:
    • oracle
    • mysql
    • ...

Hibernate开发步骤:

  • 创建Hibernate配置文件:hibernate.cfg.xml
  • 创建持久化类(JavaBean)
  • 创建对象-关系映射文件:*.hbm.xml
  • 通过Hibernate API编码访问数据库的代码

hibernate.cfg.xml的基本配置:

<hibernate-configuration>
  <session-factory>
    <!-- 配置连接数据库的信息 -->
    <property name="connection.username">root</property>
    <property name="connection.password">java</property>
    <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="connection.url">jdbc:mysql://localhost:3306/hibernate</property>
    <!-- 配置hibernate的基本信息,关联数据库的语法 -->
    <property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>  <!-- InnoDB标识支持事物 --> 
    <!-- 执行操作时是否在控制台打印SQL -->
    <property name="show_sql">true</property>
    <!-- 是否对SQL进行格式化 -->
    <property name="format_sql">true</property>
    <!-- 指定自动生成数据表的策略 -->
    <property name="hbm2ddl.auto">update</property>
    <!-- 指定关联的对象-关系映射文件*.hbm.xml -->
    <mapping resource="com/djh/Employee.hbm.xml" />
  </session-factory>
</hibernate-configuration>
  • JavaBean与关系-对象映射文件的对应:
    • JavaBean:
      package com.djh;
      public class Employee{
      private int id;
      private int employeeId;
      private String employeeName;
      private double employeeSalary;
      private Date birthday;
      
      //...getter and setter methods
      }
      
    • 映射文件:*.hbm.xml
      <hibernate-mapping>
        <class name="com.djh.Employee" table="EMPLOYEE">   <!-- name对象JavaBean对象的类路径(包名+类名), 指定了类和表的映射 -->
        <id name="id" type="int">
          <column name="ID" />
          <generator class="native" />   <!-- 指定主键的生成方式,native标识使用数据库本地方式 -->
        </id>
        <property name="employeeId" type="int">
          <column name="EMPLOYEEID" />
        </property>
        <property name="employeeName" type="java.lang.String">
          <column name="EMPLOYEENAME" />
        </property>
        <property name="employeeSalary" type="double">
          <column name="EMPLOYEESALARY" />
        </property>
        <property name="birthday" type="java.sql.Date">
          <column name="BIRTHDAY" />
        </property>
        </class>
      </hibernate-mapping>
      

Hibernate Demo:

  • 层次结构:
    Structure
  • JavaBean: Employee.java
package com.djh;
import java.sql.Date;
public class Employee {
  private int id;
  private int employeeId;
  private String employeeName;
  private double employeeSalary;
  private Date birthday;
  public int getEmployeeId() {
    return employeeId;
  }
  public void setEmployeeId(int employeeId) {
    this.employeeId = employeeId;
  }
  public String getEmployeeName() {
    return employeeName;
  }
  public void setEmployeeName(String employeeName) {
    this.employeeName = employeeName;
  }
  public double getEmployeeSalary() {
    return employeeSalary;
  }
  public void setEmployeeSalary(double employeeSalary) {
    this.employeeSalary = employeeSalary;
  }
  public Date getBirthday() {
    return birthday;
  }
  public void setBirthday(Date birthday) {
    this.birthday = birthday;
  }

  public Employee(int employeeId, String employeeName, double employeeSalary,
Date birthday) {
    super();
    this.employeeId = employeeId;
    this.employeeName = employeeName;
    this.employeeSalary = employeeSalary;
    this.birthday = birthday;
  }

  public Employee() {
    // TODO Auto-generated constructor stub
  }
}
  • 测试类:EmployeeTest.java
package com.djh;
import java.sql.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import junit.framework.TestCase;
public class EmployeeTest extends TestCase {
  public void test(){
    //1,定义SessionFactory
    SessionFactory sessionFactory = null;
    //2,创建configuration对象
    Configuration configuration = new Configuration().configure();
    //3.加载对应持久化类
    configuration.addClass(Employee.class);
    //创建ServiceRegistry对象
    ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
    //创建SessionFactory对象
    sessionFactory = configuration.buildSessionFactory(serviceRegistry);
    //4.获取Session对象
    Session session = sessionFactory.openSession();
    //5.开启事务
    Transaction transaction = session.beginTransaction();
    //6.创建一个持久化对象
    Employee employee = new Employee(4400, "Michael", 5000, new Date(new java.util.Date().getTime()));
    //7.保存
    session.save(employee);
    //8.提交事务
    transaction.commit();
    //关闭session与SessionFactory
    session.close();
    sessionFactory.close();
  }
}
  • 对象-关系映射文件:Employee.hbm.xml:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Feb 28, 2017 10:59:06 PM by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
 <class name="com.djh.Employee" table="EMPLOYEE">
 <id name="id" type="int" access="field">
 <column name="ID" />
 <generator class="assigned" />
 </id>
 <property name="employeeId" type="int">
 <column name="EMPLOYEEID" />
 </property>
 <property name="employeeName" type="java.lang.String">
 <column name="EMPLOYEENAME" />
 </property>
 <property name="employeeSalary" type="double">
 <column name="EMPLOYEESALARY" />
 </property>
 <property name="birthday" type="java.sql.Date">
 <column name="BIRTHDAY" />
 </property>
 </class>
</hibernate-mapping>
  • hibernate配置文件:hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
 <session-factory>

 <!-- 配置数据库的基本信息 -->
 <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
 <property name="connection.username">root</property>
 <property name="connection.password">java</property>
 <property name="connection.url">jdbc:mysql://localhost:3306/hibernate</property>

 <property name="show_sql">true</property>
 <property name="format_sql">true</property>
 <property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>

 <!-- 指定自动生成数据表的策略 -->

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

 <!-- 关联对象-关系配置文件 -->
 <mapping resource="com/djh/Employee.hbm.xml"/>
 </session-factory>
</hibernate-configuration>
  • 运行结果
    Test Result
  • DB:
    DB result.png

持久化类(JavaBean)要求:

  • 提供一个无参的构造器:使得Hibernate可以使用Constructor.newInstance()来实现持久化类
  • 提供一个标识属性:通常映射为数据库表的主键字段
  • 为类的持久化类字段声明访问方法(getter/setter)
  • 使用非final类
  • 重写equals和hashCode方法:在需要将持久化类的实例放入Set集合时,需要重写
  • Hibernate的配置文件(hibernate.cfg.xml)位于应用的classpath下

hibernate进行持久化操作的步骤:

  • 编写持久化类:POJO + 映射文件
  • 获取Configuration对象
  • Configuration类负责管理Hibernate的配置信息,包含以下内容:
    • 数据库的URL
    • 用户名
    • 密码
    • JDBC驱动类等
    • 数据库Dialect
    • 数据库连接池
  • 持久化类与数据表的映射关系(*.hbm.xml文件)
    • Configuration的创建方式:
      • 方式一:属性文件(hibernate.properties)
        Configuration config = new Configuration();
      • 方式二:XML文件(hibernate.cfg.xml)
        Configuration config = new Configuration.configure();
      • 方式三:Configuration带参:
        File file = new File("cfg.xml");
        Configuration config = new Configuration().configure(file);
        
  • 获取SessionFactory对象
    • 针对单个数据库映射关系经过编译后的内存镜像,是线程安全的
    • 一旦对象被创建,则被赋予特定的配置信息
  • 构造SessionFactory很消耗资源,一般一个应用只初始化一个SessionFactory
  • 获取Session,打开事务
    • Session是一个用于应用程序与数据库交互操作的单线程对象
    • 所有持久化对象必须在session的管理下进行操作
    • Session对象有一个一级缓存,显示执行flush之前,所有的 持久层操作的数据都缓存在session对象处
    • 持久化类与Session关联起来后才具有持久化能力
  • Session类的方法:
    • 获取持久化对象:get()、load()
    • 持久化对象保存、更新与删除:save()、update()、saveOrUpdate()、delete()
    • 开启事务:beginTransaction()
    • 管理Session的方法:isOpen()、flush()、clear()、evict()、close()
  • 用面向对象的方式操作数据库
  • 关闭事务,关闭Session
  • 关于Transaction:
    • 代表一次原子操作
    • 常用方法:
      • commit():提交相关联的session实例
      • rollback():撤销事务操作
      • wasCommitted():检查事务是否提交

Hibernate配置文件的两个配置项:

  • hbm2ddl.auto:
    • 实现自动具体实现表结构,可取的值有:create、update、create-drop、validate
    • create:根据*.hbm.xml文件来生成数据表,但每次运行都会删除上一次的表,重新生成表(即使没有任何变化)
    • create-drop:根据*.hbm.xml文件来生成数据表,但SessionFactory一关闭,表就会删除
    • update:根据*.hbm.xml文件来生成数据表,但若*.hbm.xml文件和数据库中对应数据表的结构不同,则更新表,但不会删除原有的行与列
    • validate:会与数据库中的表进行比较,若*.hbm.xml文件中的类在数据表中不存在,则抛出异常
    • format_sql:是否将SQL转化为良好的SQL,取值为true 或 false.

Session对象:

  • 提供了基本的保存、更新、删除与加载Java对象的方法
  • 具有一级缓存,位于缓存中的对象称为持久化对象,它和数据库中的相关记录对象
  • Hibernate将对象分为四种状态:
    • 持久化状态
    • 临时状态
    • 游离状态
    • 删除状态
    • 状态转换:
      Status.png
  • Session缓存(一级缓存)可以减少Hibernate程序访问数据库的频率,Session缓存的清楚操作有以下三种方式:
    • flush()
    • reflesh()
    • clear()
      缓存.png
    • 注意:执行HQL或QBC查询时,会先进行flush()操作,以得到数据表的最新记录
    • flushcommit的区别:
      • flush会执行一系列的sql语句,但不会提交事务
      • commit会先执行flush,然后再提交事务
  • 设定刷新缓存的时间点:
    • 通过Session的setFlushModel()方法显示设定flush的时间点,具体如下:
    • 数据库的隔离级别:
      • read uncommitted:读未提交数据
      • read committed:读已提交数据
      • repeatable read:可重复读(mysql默认的隔离级别)
      • serializable:串行化
  • 查看当前隔离级别:
    select @@tx_isolation;
  • 设置当前mysql连接的隔离级别:
    set transaction isolation level read committed;
  • 设置数据库的全局的隔离级别:
    select globaltransaction isolation level read committed;
  • 在Hibernate中设置隔离级别:
    • JDBC数据库连接使用数据库系统默认的隔离级别,在Hibernate的配置文件中可以显示的设置隔离级别,每一个隔离级别都对应一个整数:
    • 1 - read committed
    • 2 - read committed
    • 4 - repeatable read
    • 8 - serializeable
  • Hibernate通过为Hibernate映射文件来指定:
    • hibernate.connection.isolation属性来设置事务的隔离级别

Hibernate核心方法:

  • 查询
    • get():会立即加载对象,若数据不存在对应的记录,返回null
    • load():不会立即执行查询操作,而返回一个代理对象,若数据不存在对应的记录,则抛出异常
  • 插入:
    • save():允许在save之前设置OID,但OID不起作用
    • persist():不允许在persist之前设置OID
  • 更新:
    • update():对于非游离的对象,不需要显示的执行update方法,对于游离的对象需要显示的执行update方法
    • saveOrUpdate():包含了save和update方法,执行前会判断对象状态,若为临时对象,执行save(),若为游离对象,执行update().
      • 判断对象为临时对象的标准:
        • Java对象的OID为null
        • 映射文件中为<id>设置了unsaved-value属性,并且Java对象的OID取值与这个unsaved-value属性匹配
        • 示意图:
  • 删除:delete()
    • 可以删除一个游离对象,也可以一个持久化对象
    • Session的delete方法处理过程:
      • 计划执行一条delete语句,在flush或事物提交的时才执行delete动作
      • 把对象从session缓存中删除,该对象进入删除状态
  • Hibernate的*.cfg.xml配置文件中有一个hibernate.use_identifer_rollback属性,默认值为false,若设置为true,将改变delete方法的运行行为(delete方法会将持久化对象或游离对象的OID设置为null),避免在真正执行delete操作之前对该条记录进行其他操作,设置如下:
  • 注意:同一个session中不能包含两个OID相同的对象,否则会抛异常
  • 通过Hibernate调用存储过程:
    • Work接口:直接通过JDBC API来访问数据库的操作
    • Session的doWork(Word)方法用于执行Work对象指定的操作,即调用Work对象的execute()方法,Session会把当前使用的数据库连接传递给execute()方法,如:
      session.doWork(new Work(){
        @Override
        public void execute(Connection connection) throws SQLException{
          String procedure = "{call testProcedure()}";
          CallableStatement cstmt = connection.prepareCall(procedure);
        cstmt.executeUpdate();
        }
      });
      
  • 为了确保session缓存中的记录是最新的,可在对session缓存中的对象进行操作之前执行reflesh()方法,确保session缓存中的对象是最新的

Hibernate配置文件:

  • C3P0数据库连接池属性:
  • hibernate.c3p0.max_size:数据库连接池的最大连接数
  • hibernate.c3p0.min_size:数据库连接池的最小连接数
  • hibernate.c3p0.timeout:数据库连接池中连接对象在多长时间没有使用过后,就应该被销毁
  • hibernate.c3p0.max_statements:缓存Statement对象的数量
  • hibernate.c3p0.idle_test_period:标识连接池检测线程多长时间检测一次池内的所有链接对象是否超时
  • hibernate.c3p0.accquire_icrement:当数据库连接池中的连接耗尽时,同一时刻获取多少个数据库连接
  • 其他的常见应用配置:
    • show_sql:取值为true或者false,是否将运行期生成的SQL输出到日志
    • format_sql:取值true或false,是否格式化SQL语句为良好的形式
    • hbm2ddl.auto:取值为create|update|create-drop|validate,创建、更新和删除数据库模式
    • hibernate.jdbc.fetch_size:设定JDBC的Statement读取数据的时候每次从数据库中取出的记录条数,Oracle数据库fetchSize=100比较合适
    • hibernate.jdbc.batch_size:设定对数据库进行批量删除、批量更新和批量插入的时候的批次大小,Oracle数据库batchSize=30的时候比较合适

Hibernate映射文件:

  • hibernate-mapping:
  • class:
  • generator:
  • Property:
  • Java类型、Hibernate类型及SQL类型之间的对应关系
  • Java时间和日期类型的Hibernate映射:
    • 在Java中,代表时间和日期的类型包括:java.util.Datejava.util.Calendar,另外,在JDBC的API中还提供了三个扩展子类:
      • java.sql.Date:对应SQL中的DATE类型,表示日期
      • java.sql.Time:对应SQL中的TIME类型,表示时间
      • java.sql.TimeStamp:对应SQL中的TIMESTAMP,表示时间戳(日期 + 时间)
      • 具体对应关系如下:
  • 映射组成关系:
    • hibernate将持久化类的属性分为两种:
      • 值型:没有OID,不能被单独持久化,生命周期依赖于所属的持久化类的对象的生命周期,如下面的Pay
      • 实体型:有OID,可以被单独持久化,有独立的生命周期,如下的Worker
      • 使用component元素来关联值型与实体型
      • 如:
        • 结构:
        • Worker.java:
        • Pay.java:
        • 持久化类(JavaBean)映射文件:
        • 测试类:
        • 测试DB result:

一对一关联:

  • 使用主键关联:映射文件如下:
    • JavaBean:
      Department{int:deptId, String: deptName, Manager mgr}
      Manager{int:mgrId; String:mgrName}
      
    • 有外键的一方:
      <id name="deptId" type="java.lang.Integer">
        <column name="DEPT_ID" />
        <!-- 使用外键的方式来生成当前的主键 -->
        <generator name="foreign">
          <!-- 指定使用当前持久化类的哪一个属性的主键作为外键 -->
          <param name="property">mgr</param>
        <generator>
      </id>
      <one-to-one name="mgr" class="Manager(Manager所在类)" constrained="true" />
      
    • 域模型:

映射多对多的关系

  • 多对多的关系,需要使用第三个表连接
  • 必须为set集合元素添加key元素,同时需要使用<many-to-many>元素,如:
    <set name="items" table="CATEGORY_ITEM(第三个连接表)">
      <key>
        <column name="C_ID" />
      </key>
      <many-to-many class="Item" column="I_ID" />
    </set>
    

映射继承关系

  • Hibernate的继承映射可以理解持久化类之间的继承关系
  • Hibernate继承映射的三种策略:
    • 使用subclass进行映射:
      • 可以实现对于继承关系中父类和子类使用同一张表
      • 所有字类定义的字段都不能有非空约束,如下图
      • 使用subclass来映射子类,使用class或subclass的discriminator-value属性指定辨别者列的值
      • 如:(person 与 student)
      • 配置映射文件如下:Person.hbm.xml
      <hibernate-mapping package="com.djh">
       <class name="Person" table="PERSON" discriminator-value="PERSON">
           <id name="id" type="int" access="field">
             <column name="ID" />
             <generator class="native" />
           </id>
           <!-- 辨别者列 -->
          <discriminator column="TYPE" type="String" />
          <property name="personName" type="java.lang.String">
            <column name="PERSON_NAME" />
           </property>
           <property name="personAge" type="int">
             <column name="PERSON_AGE" />
           </property>
          <!-- 映射类Student,使用subclass映射 -->
          <subclass name="Student" discriminator-value="STUDENT">
            <property name="school" type="string" column="SCHOOL" />
          </subclass>
       </class>
      </hibernate-mapping>
      
  • 使用joined-subclass进行映射
    • 可以实现每个子类一张表
    • 使用该策略时,父类实例保存在父类表中,子类实例由父类表和子类表共同存储
    • 需要为每个子类使用key元素映射共有主键
    • 子类增加的属性可以添加非空约束
    • 使用joined-subclass元素,如:
     <class name="Person" table="PERSON">
       <id name="id" type="int" access="field">
         <column name="ID" />
         <generator class="native" />
       </id>
      <property name="personName" type="java.lang.String">
         <column name="PERSON_NAME" />
       </property>
       <property name="personAge" type="int">
         <column name="PERSON_AGE" />
       </property>
       <joined-subclass name="Student">
        <property name="school" type="string" column="SCHOOL" />
        <!-- 指定父类主键 -->
        <key column="ID" not-null="true"></key>
      </joined-subclass>
     </class>
    
  • 使用union-subclass进行映射
    • 可以实现将每一个实体对象映射到一个独立的表中
    • 子类增加的属性有非空约束
    • 子类实例的数据仅保存在子类中
    • 使用union-subclass映射策略是不可使用identity(即: <generator class="native" />不能使用native)的主键生成策略,如:
    <union-subclass name="Student" table="STUDENT">
      <property name="school" type="string" column="SCHOOL" />
    </union-subclass>
    ```![](http://upload-images.jianshu.io/upload_images/3894760-213cd28483be26ae.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    

Hibernate检索策略(lazy、fetch、batch-size、...)

  • class的lazy属性可以设置检索方式:(仅对load方法有效,get方法一直都是使用立即检索)
    • true:延迟检索
    • false:立即检索
  • 调用Hibernate.initialize()方法可以直接初始化实例,而避免懒加载

HQL查询

  • Hibernate的检索方式:
    • 导航对象图检索:根据已经加载的对象导航到其他的对象
    • OID检索:按照对象的OID来检索
    • HQL检索:使用面向对象的HQL查询语言
    • QBC检索:使用QBC(Query By Criteria) API来检索对象
    • 本地SQL检索
  • HQL(Hibernate Query Language)有如下功能:
    • 在查询语句中设定各种查询条件
    • 支持投影查询,即仅检索出对象的部分属性
    • 支持分页查询
    • 支持连接查询
    • 支持分组查询,允许使用Having和group by关键字
    • 提供内置聚集函数,如:sum(),min()与max()
    • 支持子查询
    • 支持动态绑定参数
    • 能够调用用户定义的SQL函数或标准的SQL函数
  • HQL检索包含以下步骤:
    • 通过Session的createQuery()方法创建一个Query对象,它包括一个HQL查询语句,HQL查询语句中包含命名参数
    • 动态绑定参数
      • Hibernate的参数绑定机制依赖于JDBC API中的PreparedStatement的预定义SQL语句
      • HQL的参数绑定有以下两种方式:
        • 按参数名字绑定(bind variable):在HQL查询语句中定义命名参数,命名参数以":"开头,如:
        • 按参数位置绑定:在HQL查询语句中用"?"来定义参数位置,如:
  • 相关方法:
    • setEntity():把参数与一个持久化类绑定
    • setParameter():绑定任意类型的参数,该方法的第三个参数显式指定Hibernate映射类型
  • HQL采用order by关键字对查询结果排序
  • 调用Query相关方法执行查询语句
    • Query接口支持setXXX()方法链编程风格,它的setXxx()方法返回自身实例
  • HQL与SQL:
    • HQL查询语句是面向对象的,Hibernate负责解析HQL查询语句
    • SQL查询语句是与关系数据库绑定在一起的
  • HQL分页查询:
    • setFirstResult(int firstResult):设定从哪一个对象开始检索,参数firstResult表示这个对象在查询结果中的索引位置,索引位置的起始值为0,默认情况下,Query从查询结果中的第一个对象开始检索
    • setMaxResult(int maxResult):设定一次最多检索出的对象的数目,默认情况下,Query与Criteria接口检索出查询结果中所有的对象
  • HQL在映射文件中定义命名查询语句:
    • Hibernate允许在映射文件中定义字符串形式的查询语句
    • <query>元素用于定义一个HQL查询语句,它和<class>元素并列,如:
     <query name="findEmployeeById">
     <![CDATA[
       from Employee where ID=:employeeId
     ]]>
     </query>
    
  • 在程序中通过Session的getNamedQuery()方法获取查询语句对应得Query对象,如:
    Query query = session.getNamedQuery("findEemployeeById");

Hibernate二级缓存:

  • 一级缓存为Session级别的缓存,属于事务范围的缓存,该级别的缓存由hibernate管理
  • 二级缓存是SessionFactory级别的缓存,是属于进程范围的缓存
  • SessionFactory的缓存可以分为两类:
    • 内置缓存: Hibernate自带的,不可卸载,通常在Hibernate的初始化阶段,Hibernate会把映射元素据和预定义的SQL语句放到SessionFactory的缓存中,映射元素据是映射文件(.hbm.xml)中数据的复制,该内置缓存是只读的。
    • 外置缓存(二级缓存):可配置的缓存插件,在默认情况下,SessionFactory不会启用这个缓存插件,外置缓存中的数据是数据库数据的复制,外置缓存的物理介质可以是内存或硬盘
  • 二级缓存的适用数据:
    • 很少被修改
    • 不是很重要的数据,允许出现偶尔的并发问题
  • 二级缓存不适用的数据:
    • 经常被修改
    • 财务数据,且不允许出现并发问题
    • 与其他应用程序共享的数据
  • 二级缓存的并发访问策略,对应每一种事务隔离级别:
    • 非严格读写:不保证缓存与数据库中数据的一致性
    • 读写型(Read committed):适用于经常读但是很少被修改的数据
    • 事务型:仅在受管理环境下使用
    • 只读型:适用于从不会被修改的数据
  • 使用EHCache插件进行二级缓存
    • 启用二级缓存,需要在配置文件中配置:
    <!-- 启用二级缓存 -->
    <property name="cache.use_second_level_cache">true</property>
    <!-- 使用二级缓存的类 -->
    <class-cache usage="read-write" class="com.djh.Employee" />
    

管理Session与批量操作

  • Hibernate自身提供了三种管理Session对象的方法:
    • Session对象的生命周期与本地线程绑定
    • Session对象的生命周期与JTA事务绑定
    • Hibernate委托程序管理Session对象的生命周期
  • 在Hibernate的配置文件中,hibernate.current_session_context_class属性用于指定Session管理方式,其值有如下:
    • thread:Session对象的生命周期与本地线程绑定
    • jta*:Session对象的生命周期与JTA事务绑定
    • managed:Hibernate委托程序管理
  • 批量数据处理的方式:
    • 通过Session
      Session的save()及update()方法都会把处理的对象存放在自己的缓存中,如果通过一个Session对象来处理大量持久化对象,应该及时缓存中清空已经处理完毕并且不会再访问的对象,即调用如下方法:

      • session.flush(); //刷新缓存
      • session.clear(); //清空缓存
    • 通过Session来进行处理会受以下约束:

      • 需要在Hibernate配置文件中设置JDBC单次批量处理的数目,应保证每次向数据库发送的批量的SQL语句数目与batch_size属性一致
      • 若对象采用"identity"标识符生成器,则Hibernate无法在JDBC层进行批量插入操作
  • 进行批量操作时,建议关闭Hibernate的二级缓存
  • 通过HQL
    • HQL只支持insert into ... select形式的插入语句,不支持insert into ... values形式.
  • 通过StatelessSession
  • 通过JDBC API

推荐阅读更多精彩内容