JavaEE

JavaWeb开发之Hibernate

2018-05-06  本文已影响29人  平安喜乐698
目录

Hibernate 
    由 Gavin King 于 2001 年创建
    高性能持久化存储和查询数据库(对象关系型)的开源框架
    通过配置文件实现
      1、Java类到数据库表的映射
      2、Java数据类型到SQL数据类型的映射
      3、数据查询和检索服务
    遵循开源的 GNU Lesser General Public License (LGPL) 可以免费下载

Hibernate 优势
    Hibernate 使用 XML 文件来处理映射 Java 类别到数据库表格中,并且不用编写任何代码。
    为在数据库中直接储存和检索 Java 对象提供简单的 APIs。
    如果在数据库中或任何其它表格中出现变化,那么仅需要改变 XML 文件属性。
    抽象不熟悉的 SQL 类型,并为我们提供工作中所熟悉的 Java 对象。
    Hibernate 不需要应用程序服务器来操作。
    操控你数据库中对象复杂的关联。
    最小化与访问数据库的智能提取策略。
    提供简单的数据询问。

Hibernate 支持几乎所有的主要 RDBMS
    HSQL Database Engine
    DB2/NT
    MySQL
    PostgreSQL
    FrontBase
    Oracle
    Microsoft SQL Server Database
    Sybase SQL Server
    Informix Dynamic Server
JDBC(Java Database Connectivity),提供了一组跨平台 Java API 来访问关系数据库

JDBC 的优点    
    干净整洁的 SQL 处理
    大数据下有良好的性能
    对于小应用非常好
    易学的简易语法
JDBC 的缺点
    大项目中使用很复杂   
    很大的编程成本
    没有封装
    难以实现 MVC 的概念
    查询需要指定 DBMS
对象关系映射Object-Relational Mapping (ORM) 

    解决一个对象模型和一个关系数据库表不匹配(五个不匹配的情况):
    1、粒度    
    模型类的数量比数据库中关联的表的数量更多
    2、继承    
    RDBMSs 不会定义任何在面向对象编程语言中的继承
    3、身份    
    RDBMS 明确定义一个 'sameness' 的概念:主键。然而,Java 同时定义了对象判等(a==b)和 对象值判等(a.equals(b))
    4、关联    
    面向对象的编程语言使用对象引用来表示关联,而一个 RDBMS 使用外键来表示对象关联
    5、导航
    在 Java 中和在 RDBMS 中访问对象的方式完全不相同

ORM 系统相比于JDBC 有以下的优点:
    使用业务代码访问对象而不是数据库中的表
    从面向对象逻辑中隐藏 SQL 查询的细节
    基于 JDBC 的 'under the hood'
    没有必要去处理数据库实现
    实体是基于业务的概念而不是数据库的结构
    事务管理和键的自动生成
    应用程序的快速开发

一个 ORM 解决方案由以下四个实体组成:
    一个 API 来在持久类的对象上实现基本的 CRUD 操作
    一个语言或 API 来指定引用类和属性的查询
    一个可配置的服务用来指定映射元数据
    一个技术和事务对象交互来执行 dirty checking, lazy association fetching 和其它优化的功能


Java ORM 框架
    Enterprise JavaBeans Entity Beans
    Java Data Objects
    Castor
    TopLink
    Spring DAO
    Hibernate
    And many more

Hibernate 架构

配置对象
   只在应用程序初始化期间创造。它代表了 Hibernate 所需一个配置或属性文件。
    配置对象提供了两种基础组件。
        数据库连接:由 Hibernate 支持的一个或多个配置文件处理。这些文件是 hibernate.properties 和 hibernate.cfg.xml。
        类映射设置:这个组件创造了 Java 类和数据库表格之间的联系。

SessionFactory 对象
    配置对象被用于创造一个 SessionFactory 对象,使用提供的配置文件为应用程序依次配置 Hibernate,并允许实例化一个会话对象。SessionFactory 是一个线程安全对象并由应用程序所有的线程所使用。
    SessionFactory 是一个重量级对象所以通常它都是在应用程序启动时创造然后留存为以后使用。每个数据库需要一个 SessionFactory 对象使用一个单独的配置文件。所以如果你使用多种数据库那么你要创造多种 SessionFactory 对象。

Session 对象
    一个会话被用于与数据库的物理连接。Session 对象是轻量级的,并被设计为每次实例化都需要与数据库的交互。持久对象通过 Session 对象保存和检索。
Session 对象不应该长时间保持开启状态因为它们通常情况下并非线程安全,并且它们应该按照所需创造和销毁。

Transaction 对象
    一个事务代表了与数据库工作的一个单元并且大部分 RDBMS 支持事务功能。在 Hibernate 中事务由底层事务管理器和事务(来自 JDBC 或者 JTA)处理。
这是一个选择性对象,Hibernate 应用程序可能不选择使用这个接口,而是在自己应用程序代码中管理事务。

Query 对象 
    Query 对象使用 SQL 或者 Hibernate 查询语言(HQL)字符串在数据库中来检索数据并创造对象。一个查询的实例被用于连结查询参数,限制由查询返回的结果数量,并最终执行查询。

Criteria 对象
    Criteria 对象被用于创造和执行面向规则查询的对象来检索对象。
Hibernate 架构 Hibernate 架构-详细
下载Hibernate 
    http://www.hibernate.org/downloads
  1. 配置文件 hibernate.cfg.xml
hibernate.properties 或 hibernate.cfg.xml
    该映射文件定义了
        Java类怎样关联到数据库表
        相关数据库参数的配置

hibernate.cfg.xml示例(mysql)

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM 
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
   <session-factory>
   <property name="hibernate.dialect">
      org.hibernate.dialect.MySQLDialect
   </property>
   <property name="hibernate.connection.driver_class">
      com.mysql.jdbc.Driver
   </property>

   <!-- Assume test is the database name -->
   <property name="hibernate.connection.url">
      jdbc:mysql://localhost/数据库名
   </property>
   <property name="hibernate.connection.username">
      root
   </property>
   <property name="hibernate.connection.password">
      密码
   </property>

   <!-- List of XML mapping files -->
   <mapping resource="Employee.hbm.xml"/>

</session-factory>
</hibernate-configuration> 

Hibernate的属性(property)有:

hibernate.dialect 
    数据库类型(见下方)
hibernate.connection.driver_class
    JDBC驱动程序类(固定的,网上能找到)
hibernate.connection.url 
    JDBC URL(固定的,网上能找到)
hibernate.connection.username
    要连接数据库的用户名
hibernate.connection.password 
    要连接数据库的密码
hibernate.connection.pool_size 
    限制数据库连接池中连接的数量
hibernate.connection.autocommit 
    允许在 JDBC 连接中使用自动提交模式

使用JNDI时的Hibernate 属性

hibernate.connection.datasource 
    在应用程序服务器环境中您正在使用的应用程序 JNDI 名。
hibernate.jndi.class 
    JNDI 的 InitialContext 类。
hibernate.jndi.<JNDIpropertyname> 
    在 JNDI的 InitialContext 类中通过任何你想要的 Java 命名和目录接口属性。
hibernate.jndi.url 
    为 JNDI 提供 URL。
hibernate.connection.username 
    数据库用户名。
hibernate.connection.password 
    数据库密码。

hibernate.dialect有如下值:

DB2 
    org.hibernate.dialect.DB2Dialect
HSQLDB  
    org.hibernate.dialect.HSQLDialect
HypersonicSQL   
    org.hibernate.dialect.HSQLDialect
Informix    
    org.hibernate.dialect.InformixDialect
Ingres  
    org.hibernate.dialect.IngresDialect
Interbase   
    org.hibernate.dialect.InterbaseDialect
Microsoft SQL Server 2000   
    org.hibernate.dialect.SQLServerDialect
Microsoft SQL Server 2005   
    org.hibernate.dialect.SQLServer2005Dialect
Microsoft SQL Server 2008   
    org.hibernate.dialect.SQLServer2008Dialect
MySQL
    org.hibernate.dialect.MySQLDialect
Oracle (any version)
    org.hibernate.dialect.OracleDialect
Oracle 11g
    org.hibernate.dialect.Oracle10gDialect
Oracle 10g
    org.hibernate.dialect.Oracle10gDialect
Oracle 9i
    org.hibernate.dialect.Oracle9iDialect
PostgreSQL
    org.hibernate.dialect.PostgreSQLDialect
Progress    
    org.hibernate.dialect.ProgressDialect
SAP DB
    org.hibernate.dialect.SAPDBDialect
Sybase
    org.hibernate.dialect.SybaseDialect
Sybase Anywhere
    org.hibernate.dialect.SybaseAnywhereDialec
  1. 持久化类
持久化类
    其实例存储在数据库表中的Java模型类。

POJO(Plain Old Java Object)规范如下(非强制,最好遵循):
        1、一个默认的构造函数
        2、一个 ID(映射到数据库表的主键)
        3、属性声明为private,并具有 getXXX 和 setXXX 方法。
        4、Hibernate 的一个重要特征为代理,它取决于该持久化类是处于非 final 的,还是处于一个所有方法都声明为 public 的接口。
        5、所有的类是不可扩展或按 EJB 要求实现的一些特殊的类和接口。

示例(遵循POJO)

public class Employee {
   private int id;
   private String firstName; 
   private String lastName;   
   private int salary;  

   public Employee() {}
   public Employee(String fname, String lname, int salary) {
      this.firstName = fname;
      this.lastName = lname;
      this.salary = salary;
   }
   public int getId() {
      return id;
   }
   public void setId( int id ) {
      this.id = id;
   }
   public String getFirstName() {
      return firstName;
   }
   public void setFirstName( String first_name ) {
      this.firstName = first_name;
   }
   public String getLastName() {
      return lastName;
   }
   public void setLastName( String last_name ) {
      this.lastName = last_name;
   }
   public int getSalary() {
      return salary;
   }
   public void setSalary( int salary ) {
      this.salary = salary;
   }
}
  1. 映射文件
将持久类与数据库中的表相对应(一般定义在 XML 文件中)。

方式一
  手写
方式二
  自动生成(XDoclet, Middlegen 和 AndroMDA工具)

示例:

持久化类如上

数据库建表sql如下
create table EMPLOYEE (
    id INT NOT NULL auto_increment,
    first_name VARCHAR(20) default NULL,
    last_name  VARCHAR(20) default NULL,
    salary     INT  default NULL,
    PRIMARY KEY (id)
);
Employee.hbm.xml 映射文件

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD//EN"
 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 

<hibernate-mapping>
  <!-- 映射一个Java类到数据库表,name:类名,table:表名 -->
   <class name="Employee" table="EMPLOYEE">
      <!-- 可选(类描述) -->
      <meta attribute="class-description">
         This class contains the employee detail. 
      </meta>
      <!-- 主键,name:类属性id,type:id数据类型,column:表中主键子段名 -->
      <id name="id" type="int" column="id">
         <generator class="native"/>  <!--自动生成主键-->
      </id>
      <!--联系类属性和表字段,映射类型(如下)-->
      <property name="firstName" column="first_name" type="string"/>
      <property name="lastName" column="last_name" type="string"/>
      <property name="salary" column="salary" type="int"/>
   </class>
</hibernate-mapping>

映射类型

原始类型

映射类型        Java 类型                      ANSI SQL 类型
integer       int 或 java.lang.Integer       INTEGER
long          long 或 java.lang.Long         BIGINT
short         short 或 java.lang.Short       SMALLINT
float         float 或 java.lang.Float       FLOAT
double        double 或 java.lang.Double     DOUBLE
big_decimal   java.math.BigDecimal           NUMERIC
character     java.lang.String               CHAR(1)
string        java.lang.String               VARCHAR
byte          byte 或 java.lang.Byte         TINYINT
boolean       boolean 或 java.lang.Boolean   BIT
yes/no        boolean 或 java.lang.Boolean   CHAR(1) ('Y' or 'N')
true/false    boolean 或 java.lang.Boolean   CHAR(1) ('T' or 'F')
日期和时间类型

映射类型       Java 类型                              ANSI SQL 类型
date          java.util.Date 或 java.sql.Date        DATE
time          java.util.Date 或 java.sql.Time        TIME
timestamp     java.util.Date 或 java.sql.Timestamp   TIMESTAMP
calendar      java.util.Calendar                     TIMESTAMP
calendar_date java.util.Calendar                     DATE
二进制和大型数据对象

映射类型       Java 类型              ANSI SQL 类型
binary        byte[]                VARBINARY (or BLOB)
text          java.lang.String      CLOB
serializable  any Java class that implements java.io.Serializable   VARBINARY (or BLOB)
clob          java.sql.Clob         CLOB
blob          java.sql.Blob         BLOB
JDK 相关类型

映射类型       Java 类型              ANSI SQL 类型
class       java.lang.Class           VARCHAR
locale      java.util.Locale          VARCHAR
timezone    java.util.TimeZone        VARCHAR
currency    java.util.Currency        VARCHAR
  1. 会话Session
    用于获取与数据库的物理连接,然后增删改查。不能保证线程安全,使用完后应及时关闭。

持久化类实例的3个状态
    临时态(Transient)(瞬时状态)
        从对象通过new语句创建到被持久化之前的状态。
        此时对象不在Session的缓存中,不在数据库中。
    持久态(Persistent)
        从对象被持久化到Session对象被销毁之前的状态,
        此时对象在Session的缓存中,在数据库中(前提是没删除)。
        Session在清理缓存的时候会更新数据库(根据对象属性是否发生变化)
    游离态(Detached)(脱管状态)
       从 Session对象被销毁到该对象销毁之前的状态。
       此时对象不在Session的缓存中。在数据库中(前提是没删除)。
3种状态的切换
进入临时状态
    1通过new语句创建新对象。
    2执行delete()方法。对于游离状态的对象,delete()方法会将其与数据库中对应的记录删除;而对于持久化状态的对象,delete()方法会将其与数据库中对应的记录删除,并将其在Session缓存中删除。

进入持久化状态
    1执行save()或saveOrUpdate()方法,使临时对象转变为持久化对象。
    2执行update()或saveOrUpdate()方法,使游离对象转变为持久化对象。
    3执行load()或get()方法,返回的对象都是持久化对象。
    4执行find()方法,返回List集合中存放的都是持久化对象。
    5在允许级联保存的情况下,Session在清理缓存时会把与持久化对象关联的临时对象转变为持久化对象。

进入游离状态
    1执行close()方法,将Session缓存清空,缓存中的所有持久化对象将转变成游离对象。
    2执行evict()方法,能从缓存中删除一个持久化对象,使之转变成游离对象。
1当一个对象被new了以后此对象处于临时态(Transient)。
    Object object = new Object();
2然后对此对象执行session的save() 或者saveOrUpdate()方法后,此对象被放入session的一级缓存进入持久态。
    Session session = factory.openSession(); 
    Transaction tx = session.beginTransaction();
    session.save(object);
    tx.commit();
3当再对此对象执行evict()/close()/clear()的操作后此对象进入游离态(Detached)。
    session.close();
    object = null;
4游离态(Detached)和临时态(Transient)的对象由于没有被session管理会在适当的时机被java的垃圾回收站(garbage)回收。
5执行session的get()/load()/find()/iternte()等方法从数据库里查询的到的对象,处于持久态(Persistent)。
6当对数据库中的纪录进行update()/saveOrUpdate()/lock()操作后游离态的对象就过渡到持久态。
7处于持久态(Persistent)与游离态(Detached)的对象在数据库中都有对应的记录。
8临时态(Transient)与游离态(Detached)的对象都可以被回收可是临时态的对象在数据库中没有对应的纪录,而游离态的对象在数据库中有对用的纪录。

示例

// 创建数据库连接
Session session = factory.openSession();
// 用于批处理
Transaction tx = null;
try {
   // 批处理-开始
   tx = session.beginTransaction();
   // 数据库操作
   ...
   // 批处理-提交
   tx.commit();
}
catch (Exception e) {
   // 批处理回滚
   if (tx!=null) tx.rollback();
   e.printStackTrace(); 
}finally {
   // 关闭数据库连接
   session.close();
}

Session实例方法

Transaction beginTransaction()
    开启批处理事务,返回关联事务对象。
void cancelQuery()
    取消当前的查询执行。
void clear()
    完全清除该会话。
Connection close()
    关闭与数据库的连接(结束会话,释放和清理 JDBC 连接)
Criteria createCriteria(Class persistentClass)
    为给定的实体类或实体类的超类创建一个新的 Criteria 实例。
Criteria createCriteria(String entityName)
    为给定的实体名称创建一个新的 Criteria 实例。
Serializable getIdentifier(Object object)
    返回与给定实体相关联的会话的标识符值。
Query createFilter(Object collection, String queryString)
    为给定的集合和过滤字符创建查询的新实例。
Query createQuery(String queryString)
    查(为给定的 HQL 查询字符创建查询的新实例)
SQLQuery createSQLQuery(String queryString)
    查(为给定的 SQL 查询字符串创建 SQLQuery 的新实例)
void delete(Object object)
    删(从数据存储中删除持久化实例)
void delete(String entityName, Object object)
    删(从数据存储中删除持久化实例)
Session get(String entityName, Serializable id)
    返回给定命名的且带有给定标识符或 null 的持久化实例(若无该种持久化实例)。
SessionFactory getSessionFactory()
    获取创建该会话的 session 工厂。
void refresh(Object object)
    从基本数据库中重新读取给定实例的状态。
Transaction getTransaction()
    获取与该 session 关联的事务实例。
boolean isConnected()
    该会话是否连接。
boolean isDirty()
    该 session 中是否包含必须与数据库同步的变化?
boolean isOpen()
    该会话是否开启。
Serializable save(Object object)
    增(先分配一个生成的标识,以保持给定的瞬时状态实例)
void saveOrUpdate(Object object)
    增/改(保存或更新实例)
void update(Object object)
    改(更新带有标识符且是给定的处于脱管状态的实例的持久化实例)
void update(String entityName, Object object)
    改(更新带有标识符且是给定的处于脱管状态的实例的持久化实例)
  1. 示例
数据库执行(启动mysql,在可视化工具Navicat Premium中连接测试数据库,执行如下语句)

create table EMPLOYEE (
   id INT NOT NULL auto_increment,
   first_name VARCHAR(20) default NULL,
   last_name  VARCHAR(20) default NULL,
   salary     INT  default NULL,
   PRIMARY KEY (id)
);
创建Java程序

Configure BuildPath | 添加Hibernate文件夹下lib中的jar、mysql-connector-java-8.0.11.jar

src下创建com.sst.cx包 
hibernate.cfg.xml
    说明见上

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM 
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
   <session-factory>
   <property name="hibernate.dialect">
      org.hibernate.dialect.MySQLDialect
   </property>
   <property name="hibernate.connection.driver_class">
      com.mysql.cj.jdbc.Driver
   </property>

   <!-- Assume test is the database name -->
   <property name="hibernate.connection.url">
      jdbc:mysql://localhost/Test
   </property>
   <property name="hibernate.connection.username">
      root
   </property>
   <property name="hibernate.connection.password">
      密码
   </property>

   <!-- List of XML mapping files -->
   <mapping resource="Employee.hbm.xml"/>

</session-factory>
</hibernate-configuration> 
Employee.java

package com.sst.cx;

public class Employee {
       private int id;
       private String firstName; 
       private String lastName;   
       private int salary;  

       public Employee() {}
       public Employee(String fname, String lname, int salary) {
          this.firstName = fname;
          this.lastName = lname;
          this.salary = salary;
       }
       public int getId() {
          return id;
       }
       public void setId( int id ) {
          this.id = id;
       }
       public String getFirstName() {
          return firstName;
       }
       public void setFirstName( String first_name ) {
          this.firstName = first_name;
       }
       public String getLastName() {
          return lastName;
       }
       public void setLastName( String last_name ) {
          this.lastName = last_name;
       }
       public int getSalary() {
          return salary;
       }
       public void setSalary( int salary ) {
          this.salary = salary;
       }
}
Employee.hbm.xml(src下)
    映射文件(映射持久化类和数据库中的表)

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD//EN"
 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 

<hibernate-mapping>
   <class name="com.sst.cx.Employee" table="EMPLOYEE">
      <meta attribute="class-description">
         This class contains the employee detail. 
      </meta>
      <id name="id" type="int" column="id">
         <generator class="native"/>
      </id>
      <property name="firstName" column="first_name" type="string"/>
      <property name="lastName" column="last_name" type="string"/>
      <property name="salary" column="salary" type="int"/>
   </class>
</hibernate-mapping>
ManageEmployee.java


package com.sst.cx;
import java.util.List; 
import java.util.Iterator; 

import org.hibernate.HibernateException; 
import org.hibernate.Session; 
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;


public class ManageEmployee {
       private static SessionFactory factory;   // SessionFactory  
       public static void main(String[] args) {
          try{
             // 创建SessionFactory  
             factory = new Configuration().configure().buildSessionFactory();
/*
Configuration
    是Hibernate的入口,负责将配置文件信息加载到内存,并创建一个SessionFactory对象,把读入的配置信息加载到SessionFactory对象的内存里。
    配置文件为属性文件时(hibernate.properties):
        Configuration cfg = new Configuration();
    配置文件为Xml文件时(hibernate.cfg.xml):
        Configuration cfg = new Configuration().configure();


SessionFactory
    负责创建Session实例,每个SessionFactory实例对应一个数据库。
    特点:
      1线程安全,同一个实例可以被应用的多个线程共享
      2重量级,占用缓存较大,不能随意创建和销毁他的实例。所以每个数据库只需创建一个SessionFactory实例,当需要操作多个数据库时,再为每一个数据库指定一个SessionFactory实例。
      3以后对Configuration对象势力作出的修改都不会影响已经创建好的SessionFactory实例,如果需要使用基于改动后的Configuration实例的SessionFactory,需要从Configuration对象中重新创建新的SessionFactory实例。
*/
          }catch (Throwable ex) { 
             System.err.println("Failed to create sessionFactory object." + ex);
             throw new ExceptionInInitializerError(ex); 
          }

          // 创建操作实例(本类实例)
          ManageEmployee ME = new ManageEmployee();

          /* 增 Add few employee records in database */
          Integer empID1 = ME.addEmployee("Zara", "Ali", 1000);
          Integer empID2 = ME.addEmployee("Daisy", "Das", 5000);
          Integer empID3 = ME.addEmployee("John", "Paul", 10000);

          /* 查 List down all the employees */
          ME.listEmployees();

          /* 改 Update employee's records */
          ME.updateEmployee(empID1, 5000);

          /* 删 Delete an employee from the database */
          ME.deleteEmployee(empID2);

          /* List down new list of the employees */
          ME.listEmployees();
       }

       /* 增 Method to CREATE an employee in the database */
       public Integer addEmployee(String fname, String lname, int salary){
          // 创建数据库连接(打开session)
          Session session = factory.openSession();
/*
Session
    是Hibernate持久化操作的基础,负责管理所有与持久化有关的操作。
    
    特点:
      1、不是线程安全的,应该避免多个线程共享同一个Session实例。
      2、Session实例是轻量级的。创建和销毁不会消耗太多资源,可以为每一个请求分配一个Session。
      3、Session对象内部有一个缓存,被称为Hibernate第一缓存,他存放被当前工作单元中加载的对象,每个Session实例都有自己的缓存。
*/
          // 用于批处理
          Transaction tx = null;  
/*
Transaction
    负责Hibernate的数据库事务,其实Hibernate本身并不具备事务管理的能力,只是对底层事务接口进行了封装,这样有利于在不同环境或容器中移植,也可以直接访问底层的事务接口。
*/
          Integer employeeID = null;
          try{
             // 批处理开始
             tx = session.beginTransaction();
             // 创建对象
             Employee employee = new Employee(fname, lname, salary);
             // 保存对象到数据库,返回id(自动生成sql)
             employeeID = (Integer) session.save(employee); 
/*
session.save
    1系统根据指定的ID生成策略,为临时对象生成一个唯一的OID;
    2将临时对象加载到缓存中;
    3提交事务时,清理缓存,利用持久化对象包含的信息生成insert语句,将持久化对象保存到数据库。
*/
             // 批处理提交
             tx.commit();
          }catch (HibernateException e) {
             // 批处理回滚
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             // 关闭数据库连接
             session.close(); 
          }
          return employeeID;
       }

       /* 查 Method to  READ all the employees */
       public void listEmployees( ){
          Session session = factory.openSession();
          Transaction tx = null;
          try{
             tx = session.beginTransaction();
             List employees = session.createQuery("FROM Employee").list(); 
             for (Iterator iterator = 
                               employees.iterator(); iterator.hasNext();){
                Employee employee = (Employee) iterator.next(); 
                System.out.print("First Name: " + employee.getFirstName()); 
                System.out.print("  Last Name: " + employee.getLastName()); 
                System.out.println("  Salary: " + employee.getSalary()); 
             }
             tx.commit();
          }catch (HibernateException e) {
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             session.close(); 
          }
       }
       /* 改 Method to UPDATE salary for an employee */
       public void updateEmployee(Integer EmployeeID, int salary ){
          Session session = factory.openSession();
          Transaction tx = null;
          try{
             tx = session.beginTransaction();
             Employee employee = 
                        (Employee)session.get(Employee.class, EmployeeID); 
             employee.setSalary( salary );
             session.update(employee); 
             tx.commit();
          }catch (HibernateException e) {
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             session.close(); 
          }
       }
       /* 删 Method to DELETE an employee from the records */
       public void deleteEmployee(Integer EmployeeID){
          Session session = factory.openSession();
          Transaction tx = null;
          try{
             tx = session.beginTransaction();
             Employee employee = 
                       (Employee)session.get(Employee.class, EmployeeID); 
             session.delete(employee); 
             tx.commit();
          }catch (HibernateException e) {
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             session.close(); 
          }
       }
    }

/*
Query和Criteria
    负责Hibernate的查询操作。
    Query实例封装了一个HQL(Hibernate Query Language)查询语句,HQL与SQL有些类似,只是HQL是面向对象的,它操作的是持久化类的类名和属性名,而SQL操作的是表名和字段名。
    Criteria实例完全封装了字符串形式的查询语句,它比Query实例更加面向对象,更适合执行动态查询
*/
注意:
    1. 如果映射文件中为对象的ID指定了生成策略,那么在程序中为其ID赋值是无效的。会被系统自动生成的值覆盖。
    <id name="id" type="string">  
        <generator class="increment">  
    </id> 
    2. 在提交事务的时候,会将之前对对象做的操作一并提交
        user.setUserName("old");  
        session.save(user);  
        user.setUserName("new");  
        tx.commit();

O/R 映射

除了基础映射外,还有
    集合的映射
    实体类之间的关联映射
    组件映射

集合映射

java.util.Set   
    它和 \<set> 元素匹配并且用 java.util.HashSet 初始化。
java.util.SortedSet 
    它和 \<set> 元素匹配并且用 java.util.TreeSet 初始化。sort 属性可以设置成比较器或者自然排序。
java.util.List  
    它和 \<list> 元素匹配并且用 java.util.ArrayList 初始化。
java.util.Collection    它和
     \<bag> 或者 \<ibag> 元素匹配以及用 java.util.ArrayList 初始化。
java.util.Map   
    它和 \<map> 元素匹配并且用 java.util.HashMap 初始化。
java.util.SortedMap")   
    它和 \<map> 元素匹配并且用 java.util.TreeMap 初始化。sort 属性可以设置成比较器或者 自然排序。

关联映射

关联映射可以是单向的也可以是双向的

Many-to-One 
    使用 Hibernate 映射多对一关系
One-to-One
    使用 Hibernate 映射一对一关系
One-to-Many
    使用 Hibernate 映射一对多关系
Many-to-Many
    使用 Hibernate 映射多对多关系

组件映射

作为变量的一员实体类很可能和其它类具有相关关系。如果引用的类没有自己的生命周期并且完全依靠于拥有它的那个实体类的生命周期的话,那么这个引用类因此就可以叫做组件类。

Component Mappings  
    类的映射对于作为变量的一员的另外的类具有参考作用。

Hibernate 注释

无需使用 XML 文件来定义映射
hibernate.cfg.xml 中 去掉  <mapping resource="Employee.hbm.xml"/>
Employee.java


package com.sst.cx;
import javax.persistence.*;

@Entity
@Table(name = "EMPLOYEE")
public class Employee {
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "id")
   private int id;

   /*
   name 属性允许显式地指定列的名称。
    length 属性为用于映射一个值,特别为一个字符串值的列的大小。
    nullable 属性允许当生成模式时,一个列可以被标记为非空。
    unique 属性允许列中只能含有唯一的内容
   * */
   @Column(name = "first_name")
   private String firstName;

   @Column(name = "last_name")
   private String lastName;

   @Column(name = "salary")
   private int salary;  

   public Employee() {}
   public int getId() {
      return id;
   }
   public void setId( int id ) {
      this.id = id;
   }
   public String getFirstName() {
      return firstName;
   }
   public void setFirstName( String first_name ) {
      this.firstName = first_name;
   }
   public String getLastName() {
      return lastName;
   }
   public void setLastName( String last_name ) {
      this.lastName = last_name;
   }
   public int getSalary() {
      return salary;
   }
   public void setSalary( int salary ) {
      this.salary = salary;
   }
}
ManageEmployee.java


package com.sst.cx;
import java.util.List; 
import java.util.Date;
import java.util.Iterator; 

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;



public class ManageEmployee {
       private static SessionFactory factory; 
       public static void main(String[] args) {
          try{
             Configuration con = new Configuration();
             factory = con.configure().addPackage("com.sst.cx").addAnnotatedClass(Employee.class).buildSessionFactory();
          }catch (Throwable ex) { 
             System.err.println("Failed to create sessionFactory object." + ex);
             throw new ExceptionInInitializerError(ex); 
          }
          ManageEmployee ME = new ManageEmployee();

          /* Add few employee records in database */
          Integer empID1 = ME.addEmployee("Zara", "Ali", 1000);
          Integer empID2 = ME.addEmployee("Daisy", "Das", 5000);
          Integer empID3 = ME.addEmployee("John", "Paul", 10000);

          /* List down all the employees */
          ME.listEmployees();

          /* Update employee's records */
          ME.updateEmployee(empID1, 5000);

          /* Delete an employee from the database */
          ME.deleteEmployee(empID2);

          /* List down new list of the employees */
          ME.listEmployees();
       }
       /* Method to CREATE an employee in the database */
       public Integer addEmployee(String fname, String lname, int salary){
          Session session = factory.openSession();
          Transaction tx = null;
          Integer employeeID = null;
          try{
             tx = session.beginTransaction();
             Employee employee = new Employee();
             employee.setFirstName(fname);
             employee.setLastName(lname);
             employee.setSalary(salary);
             employeeID = (Integer) session.save(employee); 
             tx.commit();
          }catch (HibernateException e) {
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             session.close(); 
          }
          return employeeID;
       }
       /* Method to  READ all the employees */
       public void listEmployees( ){
          Session session = factory.openSession();
          Transaction tx = null;
          try{
             tx = session.beginTransaction();
             List employees = session.createQuery("FROM Employee").list(); 
             for (Iterator iterator = 
                               employees.iterator(); iterator.hasNext();){
                Employee employee = (Employee) iterator.next(); 
                System.out.print("First Name: " + employee.getFirstName()); 
                System.out.print("  Last Name: " + employee.getLastName()); 
                System.out.println("  Salary: " + employee.getSalary()); 
             }
             tx.commit();
          }catch (HibernateException e) {
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             session.close(); 
          }
       }
       /* Method to UPDATE salary for an employee */
       public void updateEmployee(Integer EmployeeID, int salary ){
          Session session = factory.openSession();
          Transaction tx = null;
          try{
             tx = session.beginTransaction();
             Employee employee = 
                        (Employee)session.get(Employee.class, EmployeeID); 
             employee.setSalary( salary );
             session.update(employee); 
             tx.commit();
          }catch (HibernateException e) {
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             session.close(); 
          }
       }
       /* Method to DELETE an employee from the records */
       public void deleteEmployee(Integer EmployeeID){
          Session session = factory.openSession();
          Transaction tx = null;
          try{
             tx = session.beginTransaction();
             Employee employee = 
                       (Employee)session.get(Employee.class, EmployeeID); 
             session.delete(employee); 
             tx.commit();
          }catch (HibernateException e) {
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             session.close(); 
          }
       }
    }

Hibernate 查询语言

Hibernate 查询语言(HQL)是一种面向对象的查询语言,类似于 SQL,但不是去对表和列进行操作,而是面向对象和它们的属性。 HQL 查询被 Hibernate 翻译为传统的 SQL 查询从而对数据库进行操作。

在 HQL 中一些关键字比如 SELECT ,FROM 和 WHERE 等,是不区分大小写的,但是一些属性比如表名和列名是区分大小写的。

FROM 语句

// 所有
String hql = "FROM Employee";
// 带包路径
String hql = "FROM com.sst.cx.Employee";
Query query = session.createQuery(hql);
List results = query.list();

AS 语句

用来给类分配别名
// 
String hql = "FROM Employee AS E";
// 简写
String hql = "FROM Employee E";
Query query = session.createQuery(hql);
List results = query.list();

SELECT 语句

// 相比FROM,可以只获取指定属性
String hql = "SELECT E.firstName FROM Employee E";
Query query = session.createQuery(hql);
List results = query.list();

WHERE 语句

String hql = "FROM Employee E WHERE E.id = 10";
Query query = session.createQuery(hql);
List results = query.list();

ORDER BY 语句

String hql = "FROM Employee E WHERE E.id > 10 ORDER BY E.salary DESC";
String hql = "FROM Employee E WHERE E.id > 10 " +
             "ORDER BY E.firstName DESC, E.salary DESC ";
Query query = session.createQuery(hql);
List results = query.list();

GROUP BY 语句

String hql = "SELECT SUM(E.salary), E.firtName FROM Employee E " +
             "GROUP BY E.firstName";
Query query = session.createQuery(hql);
List results = query.list();

占位符

String hql = "FROM Employee E WHERE E.id = :employee_id";
Query query = session.createQuery(hql);
query.setParameter("employee_id",10);
List results = query.list();

UPDATE 语句

String hql = "UPDATE Employee set salary = :salary "  + 
             "WHERE id = :employee_id";
Query query = session.createQuery(hql);
query.setParameter("salary", 1000);
query.setParameter("employee_id", 10);
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);

DELETE 语句

String hql = "DELETE FROM Employee "  + 
             "WHERE id = :employee_id";
Query query = session.createQuery(hql);
query.setParameter("employee_id", 10);
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);

INSERT 语句

String hql = "INSERT INTO Employee(firstName, lastName, salary)"  + 
             "SELECT firstName, lastName, salary FROM old_employee";
Query query = session.createQuery(hql);
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);

聚合方法

    avg(property name)          属性的平均值
    count(property name or *)   属性在结果中出现的次数
    max(property name)          属性值的最大值
    min(property name)          属性值的最小值
    sum(property name)          属性值的总和

String hql = "SELECT count(distinct E.firstName) FROM Employee E";
Query query = session.createQuery(hql);
List results = query.list();

使用分页查询

String hql = "FROM Employee";
Query query = session.createQuery(hql);
query.setFirstResult(0);  
query.setMaxResults(10);
List results = query.list();

标准查询

// 创建一个 Criteria 对象
Criteria cr = session.createCriteria(Employee.class);  
List results = cr.list();  
加限制

Criteria cr = session.createCriteria(Employee.class);    
// 
cr.add(Restrictions.eq("salary", 2000)); 

// To get records having salary more than 2000
cr.add(Restrictions.gt("salary", 2000));

// To get records having salary less than 2000
cr.add(Restrictions.lt("salary", 2000));

// To get records having fistName starting with zara
cr.add(Restrictions.like("firstName", "zara%"));

// Case sensitive form of the above restriction.
cr.add(Restrictions.ilike("firstName", "zara%"));

// To get records having salary in between 1000 and 2000
cr.add(Restrictions.between("salary", 1000, 2000));

// To check if the given property is null
cr.add(Restrictions.isNull("salary"));

// To check if the given property is not null
cr.add(Restrictions.isNotNull("salary"));

// To check if the given property is empty
cr.add(Restrictions.isEmpty("salary"));

// To check if the given property is not empty
cr.add(Restrictions.isNotEmpty("salary"));
List results = cr.list();  
条件组合

//
Criteria cr = session.createCriteria(Employee.class);

//
Criterion salary = Restrictions.gt("salary", 2000);
Criterion name = Restrictions.ilike("firstNname","zara%");

// To get records matching with OR condistions
LogicalExpression orExp = Restrictions.or(salary, name);
cr.add( orExp );

// To get records matching with AND condistions
LogicalExpression andExp = Restrictions.and(salary, name);
cr.add( andExp );

List results = cr.list();
分页使用标准

Criteria cr = session.createCriteria(Employee.class);
cr.setFirstResult(0);
cr.setMaxResults(10);
List results = cr.list();
排序

Criteria cr = session.createCriteria(Employee.class);
// To get records having salary more than 2000
cr.add(Restrictions.gt("salary", 2000));

// To sort records in descening order
crit.addOrder(Order.desc("salary"));

// To sort records in ascending order
crit.addOrder(Order.asc("salary"));

List results = cr.list();  
预测与聚合

Criteria cr = session.createCriteria(Employee.class);

// To get total row count.
cr.setProjection(Projections.rowCount());

// To get average of a property.
cr.setProjection(Projections.avg("salary"));

// To get distinct count of a property.
cr.setProjection(Projections.countDistinct("firstName"));

// To get maximum of a property.
cr.setProjection(Projections.max("salary"));

// To get minimum of a property.
cr.setProjection(Projections.min("salary"));

// To get sum of a property.
cr.setProjection(Projections.sum("salary"));  

示例

不使用注释方式
ManageEmployee.java


package com.sst.cx;
import java.util.List; 
import java.util.Date;
import java.util.Iterator; 

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;



public class ManageEmployee {
       private static SessionFactory factory; 
       public static void main(String[] args) {
          try{
             Configuration con = new Configuration();
             factory = con.configure().addPackage("com.sst.cx").addAnnotatedClass(Employee.class).buildSessionFactory();
          }catch (Throwable ex) { 
             System.err.println("Failed to create sessionFactory object." + ex);
             throw new ExceptionInInitializerError(ex); 
          }
          ManageEmployee ME = new ManageEmployee();

          /* Add few employee records in database */
          Integer empID1 = ME.addEmployee("Zara", "Ali", 2000);
          Integer empID2 = ME.addEmployee("Daisy", "Das", 5000);
          Integer empID3 = ME.addEmployee("John", "Paul", 5000);
          Integer empID4 = ME.addEmployee("Mohd", "Yasee", 3000);

          /* List down all the employees */
          ME.listEmployees();

          /* Print Total employee's count */
          ME.countEmployee();

          /* Print Toatl salary */
          ME.totalSalary();
       }
       /* Method to CREATE an employee in the database */
       public Integer addEmployee(String fname, String lname, int salary){
          Session session = factory.openSession();
          Transaction tx = null;
          Integer employeeID = null;
          try{
             tx = session.beginTransaction();
             Employee employee = new Employee(fname, lname, salary);
             employeeID = (Integer) session.save(employee); 
             tx.commit();
          }catch (HibernateException e) {
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             session.close(); 
          }
          return employeeID;
       }

       /* Method to  READ all the employees having salary more than 2000 */
       public void listEmployees( ){
          Session session = factory.openSession();
          Transaction tx = null;
          try{
             tx = session.beginTransaction();
             Criteria cr = session.createCriteria(Employee.class);
             // Add restriction.
             cr.add(Restrictions.gt("salary", 2000));
             List employees = cr.list();

             for (Iterator iterator = 
                               employees.iterator(); iterator.hasNext();){
                Employee employee = (Employee) iterator.next(); 
                System.out.print("First Name: " + employee.getFirstName()); 
                System.out.print("  Last Name: " + employee.getLastName()); 
                System.out.println("  Salary: " + employee.getSalary()); 
             }
             tx.commit();
          }catch (HibernateException e) {
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             session.close(); 
          }
       }
       /* Method to print total number of records */
       public void countEmployee(){
          Session session = factory.openSession();
          Transaction tx = null;
          try{
             tx = session.beginTransaction();
             Criteria cr = session.createCriteria(Employee.class);

             // To get total row count.
             cr.setProjection(Projections.rowCount());
             List rowCount = cr.list();

             System.out.println("Total Coint: " + rowCount.get(0) );
             tx.commit();
          }catch (HibernateException e) {
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             session.close(); 
          }
       }
      /* Method to print sum of salaries */
       public void totalSalary(){
          Session session = factory.openSession();
          Transaction tx = null;
          try{
             tx = session.beginTransaction();
             Criteria cr = session.createCriteria(Employee.class);

             // To get total salary.
             cr.setProjection(Projections.sum("salary"));
             List totalSalary = cr.list();

             System.out.println("Total Salary: " + totalSalary.get(0) );
             tx.commit();
          }catch (HibernateException e) {
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             session.close(); 
          }
       }
}  

原生SQL

标量查询

String sql = "SELECT first_name, salary FROM EMPLOYEE";
SQLQuery query = session.createSQLQuery(sql);
query.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
List results = query.list();

实体查询

String sql = "SELECT * FROM EMPLOYEE";
SQLQuery query = session.createSQLQuery(sql);
query.addEntity(Employee.class);
List results = query.list(); 

指定 SQL 查询

String sql = "SELECT * FROM EMPLOYEE WHERE id = :employee_id";
SQLQuery query = session.createSQLQuery(sql);
query.addEntity(Employee.class);
query.setParameter("employee_id", 10);
List results = query.list();  

示例

不使用注释方式
ManageEmployee.java

package com.sst.cx;
import java.util.List; 
import java.util.Date;
import java.util.Iterator; 
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;



public class ManageEmployee {
       private static SessionFactory factory; 
       public static void main(String[] args) {
          try{
             Configuration con = new Configuration();
             factory = con.configure().addPackage("com.sst.cx").addAnnotatedClass(Employee.class).buildSessionFactory();
          }catch (Throwable ex) { 
             System.err.println("Failed to create sessionFactory object." + ex);
             throw new ExceptionInInitializerError(ex); 
          }
          ManageEmployee ME = new ManageEmployee();

          /* Add few employee records in database */
          Integer empID1 = ME.addEmployee("Zara", "Ali", 2000);
          Integer empID2 = ME.addEmployee("Daisy", "Das", 5000);
          Integer empID3 = ME.addEmployee("John", "Paul", 5000);
          Integer empID4 = ME.addEmployee("Mohd", "Yasee", 3000);

          /* List down employees and their salary using Scalar Query */
          ME.listEmployeesScalar();

          /* List down complete employees information using Entity Query */
          ME.listEmployeesEntity();
       }
       /* Method to CREATE an employee in the database */
       public Integer addEmployee(String fname, String lname, int salary){
          Session session = factory.openSession();
          Transaction tx = null;
          Integer employeeID = null;
          try{
             tx = session.beginTransaction();
             Employee employee = new Employee(fname, lname, salary);
             employeeID = (Integer) session.save(employee); 
             tx.commit();
          }catch (HibernateException e) {
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             session.close(); 
          }
          return employeeID;
       }

       /* Method to  READ all the employees using Scalar Query */
       public void listEmployeesScalar( ){
          Session session = factory.openSession();
          Transaction tx = null;
          try{
             tx = session.beginTransaction();
             String sql = "SELECT first_name, salary FROM EMPLOYEE";
             SQLQuery query = session.createSQLQuery(sql);
             query.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
             List data = query.list();

             for(Object object : data)
             {
                Map row = (Map)object;
                System.out.print("First Name: " + row.get("first_name")); 
                System.out.println(", Salary: " + row.get("salary")); 
             }
             tx.commit();
          }catch (HibernateException e) {
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             session.close(); 
          }
       }

       /* Method to  READ all the employees using Entity Query */
       public void listEmployeesEntity( ){
          Session session = factory.openSession();
          Transaction tx = null;
          try{
             tx = session.beginTransaction();
             String sql = "SELECT * FROM EMPLOYEE";
             SQLQuery query = session.createSQLQuery(sql);
             query.addEntity(Employee.class);
             List employees = query.list();

             for (Iterator iterator = 
                               employees.iterator(); iterator.hasNext();){
                Employee employee = (Employee) iterator.next(); 
                System.out.print("First Name: " + employee.getFirstName()); 
                System.out.print("  Last Name: " + employee.getLastName()); 
                System.out.println("  Salary: " + employee.getSalary()); 
             }
             tx.commit();
          }catch (HibernateException e) {
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             session.close(); 
          }
       }
    }   

Hibernate 缓存

缓存是关于应用程序性能的优化,降低了应用程序对物理数据源访问的频次,从而提高应用程序的运行性能。
多级缓存
一级缓存
    第一级缓存是 Session 缓存并且是一种强制性的缓存,所有的要求都必须通过它。Session 对象在它自己的权利之下,在将它提交给数据库之前保存一个对象。
    如果你对一个对象发出多个更新,Hibernate 会尝试尽可能长地延迟更新来减少发出的 SQL 更新语句的数目。如果你关闭 session,所有缓存的对象丢失,或是存留,或是在数据库中被更新。

二级缓存
    第二级缓存是一种可选择的缓存并且第一级缓存在任何想要在第二级缓存中找到一个对象前将总是被询问。第二级缓存可以在每一个类和每一个集合的基础上被安装,并且它主要负责跨会话缓存对象。
任何第三方缓存可以和 Hibernate 一起使用。org.hibernate.cache.CacheProvider 接口被提供,它必须实现来给 Hibernate 提供一个缓存实现的解决方法。

查询层次缓存
    Hibernate 也实现了一个和第二级缓存密切集成的查询结果集缓存。
这是一个可选择的特点并且需要两个额外的物理缓存区域,它们保存着缓存的查询结果和表单上一次更新时的时间戳。这仅对以同一个参数频繁运行的查询来说是有用的。

第二级缓存
    Hibernate 使用默认的一级缓存并且你不用使用一级缓存。让我们直接看向可选的二级缓存。不是所有的类从缓存中获益,所以能关闭二级缓存是重要的。
Hibernate 的二级缓存通过两步设置。第一,你必须决定好使用哪个并发策略。之后,你使用缓存提供程序来配置缓存到期时间和物理缓存属性。

并发策略
  一个并发策略是一个中介,它负责保存缓存中的数据项和从缓存中检索它们。如果你将使用一个二级缓存,你必须决定,对于每一个持久类和集合,使用哪一个并发策略。
    Transactional:为主读数据使用这个策略,在一次更新的罕见状况下并发事务阻止过期数据是关键的。
    Read-write:为主读数据再一次使用这个策略,在一次更新的罕见状况下并发事务阻止过期数据是关键的。
    Nonstrict-read-write:这个策略不保证缓存和数据库之间的一致性。如果数据几乎不改变并且过期数据不是很重要,使用这个策略。
    Read-only:一个适合永不改变数据的并发策略。只为参考数据使用它。
Employee.hbm.xml中+

<cache usage="read-write"/>
缓存提供者

EHCache 
    它能在内存或硬盘上缓存并且集群缓存,而且它支持可选的 Hibernate 查询结果缓存。
OSCache 
    支持在一个单独的 JVM 中缓存到内存和硬盘,同时有丰富的过期策略和查询缓存支持。
warmCache   
    一个基于 JGroups 的聚集缓存。它使用集群失效但是不支持 Hibernate 查询缓存。
JBoss Cache 
    一个也基于 JGroups 多播库的完全事务性的复制集群缓存。它支持复制或者失效,同步或异步通信,乐观和悲观锁定。Hibernate 查询缓存被支持。

兼容
策略/提供者  Read-only   Nonstrictread-write Read-write  Transactional
EHCache       X X   X
OSCache       X X   X
SwarmCache    X X
JBoss Cache   X X

hibernate.cfg.xml 中+
<property name="hibernate.cache.provider_class">
      org.hibernate.cache.EhCacheProvider
   </property>
ehcache.xml

<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>

<cache name="Employee"
maxElementsInMemory="500"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false"
/>
查询层次缓存
    必须首先使用配置文件中的 hibernate.cache.use_query_cache="true" 属性激活它。

Session session = SessionFactory.openSession();
Query query = session.createQuery("FROM EMPLOYEE");
query.setCacheable(true);
List users = query.list();
SessionFactory.closeSession();

// 告诉 Hibernate 存储和寻找缓存 employee 区域的查询
Session session = SessionFactory.openSession();
Query query = session.createQuery("FROM EMPLOYEE");
query.setCacheable(true);
query.setCacheRegion("employee");
List users = query.list();
SessionFactory.closeSession();

批处理

Session session = SessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
    Employee employee = new Employee(.....);
    session.save(employee);
    if( i % 50 == 0 ) { // Same as the JDBC batch size避免最后一次行提交
        //flush a batch of inserts and release memory:
        session.flush();
        session.clear();
    }
}
tx.commit();
session.close();

示例

在hibernate.cfg.xml中+
<property name="hibernate.jdbc.batch_size">
      50
   </property>
ManageEmployee.java

package com.sst.cx;
import org.hibernate.HibernateException; 
import org.hibernate.Session; 
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;


public class ManageEmployee {
       private static SessionFactory factory; 
       public static void main(String[] args) {
          try{
             Configuration con = new Configuration();
             factory = con.configure().addPackage("com.sst.cx").addAnnotatedClass(Employee.class).buildSessionFactory();
          }catch (Throwable ex) { 
             System.err.println("Failed to create sessionFactory object." + ex);
             throw new ExceptionInInitializerError(ex); 
          }
          ManageEmployee ME = new ManageEmployee();

          /* Add employee records in batches */
          ME.addEmployees( );
       }
       /* Method to create employee records in batches */
       public void addEmployees( ){
          Session session = factory.openSession();
          Transaction tx = null;
          Integer employeeID = null;
          try{
             tx = session.beginTransaction();
             for ( int i=0; i<100000; i++ ) {
                String fname = "First Name " + I;
                String lname = "Last Name " + I;
                Integer salary = I;
                Employee employee = new Employee(fname, lname, salary);
                session.save(employee);
                if( i % 50 == 0 ) {
                   session.flush();
                   session.clear();
                }
             }
             tx.commit();
          }catch (HibernateException e) {
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             session.close(); 
          }
          return ;
       }
    }

Hibernate 拦截器

Interceptor 接口在不同阶段调用相应方法
  findDirty()
    当 flush() 方法在一个 Session 对象上被调用时被调用。
  instantiate()
    在一个持续类被实例化时调用。
  isUnsaved()
    在当一个对象被传到 saveOrUpdate() 方法时被调用。
  onDelete()
    在一个对象被删除前被调用。
  onFlushDirty()
    在当 Hibernate 探测到一个对象在一次 flush(例如,更新操作)中是脏的(例如,被修改)时被调用。
  onLoad()
    在一个对象被初始化之前被调用。
  onSave()
    在一个对象被保存前被调用。
  postFlush()
    在一次 flush 已经发生并且一个对象已经在内存中被更新后被调用。
  preFlush()
    在一次 flush 前被调用。


创建拦截器
    直接实现 Interceptor 类或者继承 EmptyInterceptor 类。

示例(不使用注释方式)

MyInterceptor.java

package com.sst.cx;
import java.io.Serializable;
import java.util.Date;
import java.util.Iterator;

import org.hibernate.EmptyInterceptor;
import org.hibernate.Transaction;
import org.hibernate.type.Type;

public class MyInterceptor  extends EmptyInterceptor {
       private int updates;
       private int creates;
       private int loads;

       public void onDelete(Object entity,
                         Serializable id,
                         Object[] state,
                         String[] propertyNames,
                         Type[] types) {
           // do nothing
       }

       // This method is called when Employee object gets updated.
       public boolean onFlushDirty(Object entity,
                         Serializable id,
                         Object[] currentState,
                         Object[] previousState,
                         String[] propertyNames,
                         Type[] types) {
           if ( entity instanceof Employee ) {
              System.out.println("Update Operation");
              return true; 
           }
           return false;
       }
       public boolean onLoad(Object entity,
                        Serializable id,
                        Object[] state,
                        String[] propertyNames,
                        Type[] types) {
           // do nothing
           return true;
       }
       // This method is called when Employee object gets created.
       public boolean onSave(Object entity,
                        Serializable id,
                        Object[] state,
                        String[] propertyNames,
                        Type[] types) {
           if ( entity instanceof Employee ) {
              System.out.println("Create Operation");
              return true; 
           }
           return false;
       }
       //called before commit into database
       public void preFlush(Iterator iterator) {
          System.out.println("preFlush");
       }
       //called after committed into database
       public void postFlush(Iterator iterator) {
          System.out.println("postFlush");
       }
    }
ManageEmployee.java


package com.sst.cx;
import java.util.List; 
import java.util.Date;
import java.util.Iterator; 

import org.hibernate.HibernateException; 
import org.hibernate.Session; 
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;


public class ManageEmployee {
       private static SessionFactory factory; 
       public static void main(String[] args) {
          try{
             Configuration con = new Configuration();
             factory = con.configure().addPackage("com.sst.cx").addAnnotatedClass(Employee.class).buildSessionFactory();
          }catch (Throwable ex) { 
             System.err.println("Failed to create sessionFactory object." + ex);
             throw new ExceptionInInitializerError(ex); 
          }
          ManageEmployee ME = new ManageEmployee();

          /* Add few employee records in database */
          Integer empID1 = ME.addEmployee("Zara", "Ali", 1000);
          Integer empID2 = ME.addEmployee("Daisy", "Das", 5000);
          Integer empID3 = ME.addEmployee("John", "Paul", 10000);

          /* List down all the employees */
          ME.listEmployees();

          /* Update employee's records */
          ME.updateEmployee(empID1, 5000);

          /* Delete an employee from the database */
          ME.deleteEmployee(empID2);

          /* List down new list of the employees */
          ME.listEmployees();
       }
       /* Method to CREATE an employee in the database */
       public Integer addEmployee(String fname, String lname, int salary){
          Session session = factory.withOptions().interceptor(new MyInterceptor()).openSession();
          Transaction tx = null;
          Integer employeeID = null;
          try{
             tx = session.beginTransaction();
             Employee employee = new Employee(fname, lname, salary);
             employeeID = (Integer) session.save(employee); 
             tx.commit();
          }catch (HibernateException e) {
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             session.close(); 
          }
          return employeeID;
       }
       /* Method to  READ all the employees */
       public void listEmployees( ){
          Session session = factory.withOptions().interceptor(new MyInterceptor()).openSession();
          Transaction tx = null;
          try{
             tx = session.beginTransaction();
             List employees = session.createQuery("FROM Employee").list(); 
             for (Iterator iterator = 
                               employees.iterator(); iterator.hasNext();){
                Employee employee = (Employee) iterator.next(); 
                System.out.print("First Name: " + employee.getFirstName()); 
                System.out.print("  Last Name: " + employee.getLastName()); 
                System.out.println("  Salary: " + employee.getSalary()); 
             }
             tx.commit();
          }catch (HibernateException e) {
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             session.close(); 
          }
       }
       /* Method to UPDATE salary for an employee */
       public void updateEmployee(Integer EmployeeID, int salary ){
          Session session = factory.withOptions().interceptor(new MyInterceptor()).openSession();

          Transaction tx = null;
          try{
             tx = session.beginTransaction();
             Employee employee = 
                        (Employee)session.get(Employee.class, EmployeeID); 
             employee.setSalary( salary );
             session.update(employee); 
             tx.commit();
          }catch (HibernateException e) {
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             session.close(); 
          }
       }
       /* Method to DELETE an employee from the records */
       public void deleteEmployee(Integer EmployeeID){
          Session session = factory.withOptions().interceptor(new MyInterceptor()).openSession();
          Transaction tx = null;
          try{
             tx = session.beginTransaction();
             Employee employee = 
                       (Employee)session.get(Employee.class, EmployeeID); 
             session.delete(employee); 
             tx.commit();
          }catch (HibernateException e) {
             if (tx!=null) tx.rollback();
             e.printStackTrace(); 
          }finally {
             session.close(); 
          }
       }
    }
上一篇下一篇

猜你喜欢

热点阅读