TutorialsPoint Hibernate 教程

来源：易百教程

Hibernate 教程

Hibernate是一个高性能的对象/关系持久性和其基于开源GNU宽通用公共许可证（LGPL）授权，可以免费下载查询服务。 Hibernate不仅仅关心从Java类映射到数据库表（包括Java数据类型到SQL数据类型），还提供数据查询和获取。

本教程将教你如何使用Hibernate来开发简单基于数据库的Web应用程序。

读者

本教程是为Java程序员设计了一个需要了解Hibernate框架和API。完成本教程后，你会发现自己在专业知识的中等水平。

必备条件

我们假设你有Java编程语言的很好的理解。关系数据库的一个基本的了解，JDBC和SQL是非常有帮助的。

ORM是什么？ORM介绍 - hibernate

JDBC是什么?

JDBC代表Java数据库连接，并提供一组Java API，用于Java程序访问关系数据库。这些Java的API允许Java程序执行SQL语句，并与任何SQL兼容的数据库进行交互。

JDBC提供了一个灵活的架构来编写一个独立于数据库应用程序，它可以在不同的平台上运行，并与不同的数据库管理系统交互，而无需任何修改。

JDBC的优点和缺点

JDBC的优点 | JDBC的缺点
干净和简单的SQL处理 良好的性能与大数据 用于小型应用很不错 简单，语法很容易学习 | 复杂，如果它被用在大型工程项目 大的编程开销 无封装 难以实现MVC的概念 查询是具体的数据库管理系统

为什么用对象关系映射（ORM）？

当我们与一个面向对象的系统工作，还有的对象模型和关系数据库之间的不匹配。 RDBMS代表以表格格式数据，而面向对象的语言，如Java或C＃将其表示为对象的互连图。考虑下面的Java类与适当的构造函数和相关的公共功能：

public class Employee {
   private int id;
   private String first_name;
   private String last_name;
   private int salary;

   public Employee() {}
   public Employee(String fname, String lname, int salary) {
      this.first_name = fname;
      this.last_name = lname;
      this.salary = salary;
   }
   public int getId() {
      return id;
   }
   public String getFirstName() {
      return first_name;
   }
   public String getLastName() {
      return last_name;
   }
   public int getSalary() {
      return salary;
   }
}

考虑上述目的需要存储和检索到下面的RDBMS表：

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)
);

第一个问题，如果我们需要开发有几页或我们的应用程序后，修改数据库的设计？其次，加载并存储对象在关系数据库使我们面临以下五大不匹配的问题。

不匹配 | 描述
Granularity | 有时候，将有哪些具有比在数据库中对应的表的数目更多的类的对象模型。
Inheritance | RDBMS中没有定义任何类似继承是面向对象编程语言的自然范式。
Identity | 关系数据库定义的'千篇一律'只有一个概念：主键。但是，Java定义了对象标识（a== b）和对象相等（那么a.Equals（b））
Associations | 面向对象的语言表示使用的对象引用，其中的上午RDBMS代表一个协会作为一个外键列关联。
Navigation | 访问Java和关系数据库对象的方法是根本不同。

对象 - 关系映射（ORM）是解决处理所有上述阻抗失配。

什么是ORM？

ORM代表对象 - 关系映射（ORM）是一种编程技术的ORM系统已通过纯JDBC的优点如下关系数据库和面向对象的编程语言，如Java，C＃等之间转换数据

S.N. | 优点
1 | 让业务代码访问对象，而不是数据库表。
2 | 隐藏了面向对象的逻辑SQL查询详情。
3 | 基于JDBC的“引擎盖下”
4 | 无需处理数据库实现。
5 | 基于业务概念，而不是数据库结构的实体。
6 | 事务管理和自动密钥生成。
7 | 应用程序的快速开发。

ORM解决方案由以下四种实体：

S.N. | 解决
1 | 一个API来对持久化类的对象执行基本的CRUD操作。
2 | 语言或API来指定引用的类和类的属性查询。
3 | 一个可配置的设备，用于指定映射元数据。
4 | 技术与事务对象交互，以执行脏数据检查，懒关联加载，以及其他优化功能。

Java ORM框架：

有几种持久性框架和Java的ORM方案。持久性框架是一个ORM的服务，存储和检索对象到关系型数据库。

企业JavaBeans实体Bean

Java Data Objects

Castor

TopLink

Spring DAO

Hibernate

And many more

Hibernate概述,Hibernate是什么？ - hibernate

Hibernate是对Java中的对象关系映射（ORM）解决方案，它由加文·金（Gavin King）在2001年提出并创建的一个开源持久框架。它是一个强大的，高性能的对象关系持久性和对任何Java应用程序的查询服务。

Hibernate映射Java类到数据库表和从Java数据类型到SQL数据类型和95％的通用数据持久化相关的编程任务，解放了开发者。

Hibernate位于传统的Java对象和数据库服务器来处理在持久化的基础上，适当的O/R机制和模式，这些对象在所有工作对象之间。

Hibernate 优点:

Hibernate会处理映射的Java类来使用XML文件，数据库表和无需编写任何一行代码。

提供了简单的API，用于直接从数据库中存储和检索Java对象。

如果有变化，数据库或任何表中的那么只需要修改XML文件的属性。

抽象掉不熟悉的SQL类型，并提供我们解决熟悉的Java对象。

Hibernate不要求应用服务器进行操作。

操纵数据库对象的复杂关联。

尽量减少与智能读取策略数据库的访问。

提供数据的简单查询。

支持的数据库：

Hibernate支持几乎所有主要的RDBMS。以下是Hibernate支持的几个数据库引擎列表。

HSQL Database Engine

DB2/NT

MySQL

PostgreSQL

FrontBase

Oracle

Microsoft SQL Server Database

Sybase SQL Server

Informix Dynamic Server

支持的技术：

Hibernate支持各种各样的其他技术，包括以下内容：

XDoclet Spring

J2EE

Eclipse plug-ins

Maven

Hibernate架构 - hibernate

Hibernate架构是分层的，隔离的不必知道底层API。 Hibernate中使用数据库和配置信息来为应用程序提供持久化服务（以及持久的对象）。

下面是Hibernate应用程序体系结构的一个非常高的水平视图。

下面是Hibernate的应用架构与一些重要的核心课程的详细视图。

Hibernate使用各种现有的Java API，如JDBC，Java事务API（JTA）和Java命名和目录接口（JNDI）。 JDBC提供了常见的关系数据库功能的抽象的一个基本水平，使具有JDBC驱动程序，Hibernate的支持几乎任何数据库。 JNDI和JTA允许Hibernate与J2EE应用服务器进行集成。

以下部分列出了每个参与Hibernate应用程序体系结构的类的对象的简要说明。

Configuration 对象:

Configuration对象是你在任何Hibernate应用程序中创建并通常在应用程序初始化创建一次，第一个Hibernate的对象。它代表了Hibernate所需的配置或属性文件。 Configuration对象提供了两个按键组成部分：

数据库连接：这是通过Hibernate支持的一个或多个配置文件来处理。这些文件是：hibernate.properties和hibernate.cfg.xml。

类映射设置此组件创建Java类和数据库表之间的连接

SessionFactory 对象:

Configuration对象用于创建一个SessionFactory对象，它反过来可以配置Hibernate的使用提供的配置文件的应用程序，并允许一个Session对象被实例化。通过SessionFactory是线程安全的对象和使用的应用程序的所有线程。

通过SessionFactory是重量级的对象，因此通常它被应用程序时创建的启动和保持以备后用。将使用一个单独的配置文件需要每个数据库都有一个SessionFactory对象。所以，如果正在使用多个数据库，那么就需要创建多个SessionFactory的对象。

Session 对象:

Session对象用于获取与数据库的物理连接。 Session对象是重量轻，设计了一个互动是需要与数据库每次被实例化。持久化对象被保存，并通过一个Session对象中检索。

会话中的对象不应该保持开放很长一段时间，因为他们通常不被线程安全的，应该被创建并根据需要销毁他们。

Transaction 对象:

事务代表一个工作单元与数据库和大部分RDBMS支持事务功能。在Hibernate事务是由一个基本的事务管理器和事务（从JDBC或JTA）来处理。

这是一个可选的对象和Hibernate应用程序可以选择不使用这个接口，而不是在他们自己的应用程序代码管理事务。

Query 对象:

查询对象使用SQL或Hibernate查询语言（HQL）字符串从数据库中检索数据并创建对象。一个查询实例是用来绑定查询参数，限制查询返回的结果数量，并最终执行查询。

Criteria 对象:

Criteria对象用于创建和执行面向对象的条件查询来检索对象。

Hibernate环境配置 - hibernate

本章将解释如何安装Hibernate和其他相关的包准备开发环境为Hibernate应用程序。我们将使用MySQL数据库的工作，尝试使用Hibernate的例子，所以一定要确保已经安装的MySQL数据库。有关MySQL的一个更详细信息，可以查看MySQL教程.

下载Hibernate:

假定你已经拥有Java的最新版本安装在机器上。以下是简单的步骤下载并安装Hibernate。

选择是否要在Windows或UNIX安装Hibernate，然后继续下一个步骤，下载zip文件适用于Windows，而Unix则为.tz文件。

下载Hibernate最新版本 http://www.hibernate.org/downloads.

在写这篇教程的时候，我下载了hibernate-distribution-3.6.4.Final，解压缩下载的文件，目录结构如下所示。

安装Hibernate:

下载并解压Hibernate安装最新版本，需要执行下面两个简单的步骤。请确保你设置CLASSPATH变量正确，否则编译应用程序将面临问题。

现在所有的库文件拷贝从 /lib 目录到CLASSPATH，并改变classpath变量包括所有的JAR文件：

最后复制 hibernate3.jar 里的文件到CLASSPATH。该文件位于安装的根目录，Hibernate需要做的工作主要的JAR。

Hibernate Prerequisites:

以下是由Hibernate要求，应该开始使用Hibernate之前安装它们的软件包 /lib 列表。要安装这些软件包，从/lib目录拷贝库文件到CLASSPATH，并相应地改变CLASSPATH变量。

S.N. | Packages/Libraries
1 | dom4j - XML parsing www.dom4j.org/
2 | Xalan - XSLT Processor http://xml.apache.org/xalan-j/
3 | Xerces - The Xerces Java Parser http://xml.apache.org/xerces-j/
4 | cglib - Appropriate changes to Java classes at runtime http://cglib.sourceforge.net/
5 | log4j - Logging Faremwork http://logging.apache.org/log4j
6 | Commons - Logging, Email etc. http://jakarta.apache.org/commons
7 | SLF4J - Logging Facade for Java http://www.slf4j.org

Hibernate配置 - hibernate

Hibernate要求预先知道在哪里可以找到它定义Java类是如何关联到数据库表的映射信息。 Hibernate也需要一组相关的数据库和其他相关参数的配置设置。所有这些信息通常是hibernate.properties，一个标准的Java属性文件，或者作为一个名为hibernate.cfg.xml的XML文件。

考虑XML格式的文件hibernate.cfg.xml中指定在例子必需的Hibernate属性。大部分的属性取默认值，它不需要在属性文件中指定它们，除非它真的是必需的。此文件保存在应用程序的类路径的根目录。

Hibernate 属性:

以下是需要在独立情况下配置一个数据库的重要属性的列表：

S.N. | 属性和说明
1 | hibernate.dialect This property makes Hibernate generate the appropriate SQL for the chosen database.
2 | hibernate.connection.driver_class The JDBC driver class.
3 | hibernate.connection.url The JDBC URL to the database instance.
4 | hibernate.connection.username The database username.
5 | hibernate.connection.password The database password.
6 | hibernate.connection.pool_size Limits the number of connections waiting in the Hibernate database connection pool.
7 | hibernate.connection.autocommit Allows autocommit mode to be used for the JDBC connection.

如果是随着应用程序服务器和JNDI使用一个数据库，那么就必须配置以下属性：

S.N. | 属性和说明
1 | hibernate.connection.datasource The JNDI name defined in the application server context you are using for the application.
2 | hibernate.jndi.class The InitialContext class for JNDI.
3 | hibernate.jndi.<JNDIpropertyname> Passes any JNDI property you like to the JNDI InitialContext.
4 | hibernate.jndi.url Provides the URL for JNDI.
5 | hibernate.connection.username The database username.
6 | hibernate.connection.password The database password.

Hibernate和MySQL数据库：

MySQL是最受欢迎的开源数据库系统之一。让我们创建hibernate.cfg.xml配置文件，并将其放置在应用程序的类的根路径。必须确保有MySQL数据库可供TESTDB数据库，必须提供一个用户test来访问数据库。

XML配置文件必须符合Hibernate 3配置的DTD，可从 http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd.

<?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/test
   </property>
   <property name="hibernate.connection.username">
      root
   </property>
   <property name="hibernate.connection.password">
      root123
   </property>

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

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

上面的配置文件包含这都与hibernate映射文件<mapping>标签，我们将在下一章看到到底什么是Hibernate映射文件，以及如何和为什么要使用它。以下是各种重要的数据库方言属性类型的列表：

Database | Dialect Property
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.SybaseAnywhereDialect

Hibernate Sessions - hibernate

Session对象用于获取与数据库的物理连接。 Session对象是重量轻，设计了一个互动是需要与数据库每次被实例化。持久化对象被保存，并通过一个Session对象中检索。

会话中的对象不应该保持开放很长一段时间，因为他们通常不被线程安全的，他们应该被创建并根据需要摧毁他们。这次会议的主要功能是提供创建，读取和删除操作映射的实体类的实例。实例中可能存在以下三种状态之一在给定时间点：

短暂性: 持久化类的未与会话相关联，并在数据库中没有代表性，没有标识值的新实例被Hibernate认为是暂时的。

持久性: 可以做一个瞬态的实例持久化通过将它与一个会话相关联。持久性实例都有一个表示在数据库中，一个标识符值，与会话相关联。

独立性: 一旦我们关闭Hibernate的Session，持久化实例将成为一个分离的实例。

一个Session实例是可序列化的，如果它的持久化类是可序列化的。一个典型的事务应该使用下面的语句：

Session session = factory.openSession();
Transaction tx = null;
try {
   tx = session.beginTransaction();
   // do some work
   ...
   tx.commit();
}
catch (Exception e) {
   if (tx!=null) tx.rollback();
   e.printStackTrace();
}finally {
   session.close();
}

如果Session抛出异常，事务必须回滚，会话必须被丢弃。

Session 接口方法:

Session接口提供多个方法，但这里列出的只有少数重要的方法，这些方法我们在本教程中会使用。您可以查看Hibernate文档Session和SessionFactory相关方法的完整列表。

S.N. | 会话的方法和说明
1 | Transaction beginTransaction() Begin a unit of work and return the associated Transaction object.
2 | void cancelQuery() Cancel the execution of the current query.
3 | void clear() Completely clear the session.
4 | Connection close() End the session by releasing the JDBC connection and cleaning up.
5 | Criteria createCriteria(Class persistentClass) Create a new Criteria instance, for the given entity class, or a superclass of an entity class.
6 | Criteria createCriteria(String entityName) Create a new Criteria instance, for the given entity name.
7 | Serializable getIdentifier(Object object) Return the identifier value of the given entity as associated with this session.
8 | Query createFilter(Object collection, String queryString) Create a new instance of Query for the given collection and filter string.
9 | Query createQuery(String queryString) Create a new instance of Query for the given HQL query string.
10 | SQLQuery createSQLQuery(String queryString) Create a new instance of SQLQuery for the given SQL query string.
11 | void delete(Object object) Remove a persistent instance from the datastore.
12 | void delete(String entityName, Object object) Remove a persistent instance from the datastore.
13 | Session get(String entityName, Serializable id) Return the persistent instance of the given named entity with the given identifier, or null if there is no such persistent instance.
14 | SessionFactory getSessionFactory() Get the session factory which created this session.
15 | void refresh(Object object) Re-read the state of the given instance from the underlying database.
16 | Transaction getTransaction() Get the Transaction instance associated with this session.
17 | boolean isConnected() Check if the session is currently connected.
18 | boolean isDirty() Does this session contain any changes which must be synchronized with the database?
19 | boolean isOpen() Check if the session is still open.
20 | Serializable save(Object object) Persist the given transient instance, first assigning a generated identifier.
21 | void saveOrUpdate(Object object) Either save(Object) or update(Object) the given instance.
22 | void update(Object object) Update the persistent instance with the identifier of the given detached instance.
23 | void update(String entityName, Object object) Update the persistent instance with the identifier of the given detached instance.

Hibernate持久化类 - hibernate

Hibernate的整个概念是采取从Java类属性的值，并将持久到数据库表。一个映射文件Hibernate的帮助确定如何从拉动类的值，并将它们映射与表和相关的域。

其对象或实例将存储在数据库表中的Java类在Hibernate中称为持久化类。 Hibernate的效果最好，如果这些类遵循一些简单的规则，也称为普通Java对象（POJO）编程模型。有下列持久化类的主要规则，但是，这些规则并不是必需的。

将所有的持久化Java类需要一个默认的构造函数。

所有类应该包含为了让容易识别对象内Hibernate和数据库的ID。此属性映射到数据库表的主键列。

所有属性将被持久化应该声明为private，并已在JavaBean风格的定义的getXXX和setXXX方法。

Hibernate的关键功能，代理，取决于持久化类或者是非final的，或者说声明的所有公共方法的接口的实现。

所有的类不扩展或实现的EJB框架需要进行一些专门的类和接口。

POJO名称用于强调一个给定的对象是一个普通的Java对象，而不是一个特殊的对象，好更不是Enterprise JavaBean。

一个简单的POJO例子：

基于上面提到的一些规则，我们可以如下定义一个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;
   }
}

Hibernate映射文件 - hibernate

对象/关系映射的XML文档中通常被定义。这个映射文件指示Hibernate如何定义的一个或多个类映射到数据库表。

虽然很多Hibernate用户选择手工编写XML中，有一些工具可以用来生成映射文档。包括XDoclet，Middlegen和AndroMDA等用于高级Hibernate的用户。

让我们考虑我们的对象将坚持在下一节中定义的表前面定义的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;
   }
}

会有一个表对应于每一个对象，你愿意提供持久性。考虑上述目的需要存储和检索到下面的RDBMS表：

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)
);

基于以上两个实体，我们可以定义它指示Hibernate如何定义的一个或多个类映射到数据库表下面的映射文件。

<?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="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>

保存的映射文件中的格式： <classname>.hbm.xml。我们保存映射文件中的文件Employee.hbm.xml。来看看关于在映射文件中使用的映射元素的小细节：

映射文档是具有<hibernate-mapping>为包含所有的<class>元素的根元素的XML文档。

在<class>元素被用于定义数据库表从一个Java类特定的映射。 Java类名指定使用class元素的name属性和使用表属性数据库表名指定。

<meta>元素是可选元素，可以用来创建类的描述。

<id>元素映射在类中的唯一ID属性到数据库表的主键。 id元素的name属性是指属性的类和column属性是指在数据库表中的列。 type属性保存了Hibernate映射类型，这种类型的映射将会从Java转换为SQL数据类型。

id元素内的<generator>元素被用来自动生成的主键值。将生成元素的class属性设置为原生让Hibernate拿起无论是identity，sequence或者hilo中的算法来创建主键根据底层数据库的支持能力。

<property>元素用于一个Java类的属性映射到数据库表中的列。元素的name属性是指属性的类和column属性是指在数据库表中的列。 type属性保存了Hibernate映射类型，这种类型的映射将会从Java转换为SQL数据类型。

还有这将在映射文件中使用，接下来尽量覆盖尽可能多其他的Hibernate相关主题的其他属性和可用的元素。

Hibernate映射类型 - hibernate

当编写Hibernate映射文件，映射的Java数据类型到关系型数据库的数据类型。声明及在映射文件中使用的类型不是Java的数据类型，它们不是SQL数据库的数据类型。这些类型就是所谓的Hibernate映射类型，它可以从Java转换到SQL数据类型，反之亦然。

本章列出了所有的基本，日期和时间，大对象，以及其他各种内置映射类型。

基本类型：

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

Date 和time 类型:

Mapping 类型 | Java 类型 | ANSI SQL 类型
date | java.util.Date or java.sql.Date | DATE
time | java.util.Date or java.sql.Time | TIME
timestamp | java.util.Date or java.sql.Timestamp | TIMESTAMP
calendar | java.util.Calendar | TIMESTAMP
calendar_date | java.util.Calendar | DATE

二进制大对象类型：

Mapping 类型 | 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-related 类型:

Mapping 类型 | Java 类型 | ANSI SQL 类型
class | java.lang.Class | VARCHAR
locale | java.util.Locale | VARCHAR
timezone | java.util.TimeZone | VARCHAR
currency | java.util.Currency | VARCHAR

Hibernate实例 - hibernate

我们尝试使用Hibernate提供的一个独立应用程序Java持久化例子。通过使用Hibernate技术创建Java应用程序，步骤如下：

创建POJO 类:

在创建应用程序的第一步是建立在Java POJO类或类，具体取决于将被持久化到数据库的应用程序。让我们考虑我们的Employee类的getXXX和setXXX方法，使其兼容JavaBean类。

POJO（普通Java对象）是一个Java对象，它不扩展或实现分别需要由EJB框架一些专门的类和接口。所有普通的Java对象都是POJO。

当设计一个类里面要Hibernate持久化，重要的是要提供的JavaBeans兼容的代码以及将工作作为索引，就像在Employee类的id属性。

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;
   }
}

创建数据库表:

第二步是在数据库中创建表。会有一张表对应于每一个对象提供持久性。考虑上述目的需要存储和检索到下面的RDBMS表：

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)
);

创建映射配置文件：

这一步是创建一个指示Hibernate如何定义的一个或多个类映射到数据库表的映射文件。

<?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="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>

应该保存的映射文件中的格式<classname>.hbm.xml。我们保存我们的映射文件中的文件Employee.hbm.xml。让我们来看看有关映射文件的小细节：

映射文档是具有<hibernate-mapping>为包含所有的<class>元素的根元素的XML文档。

<class>元素被用于定义数据库表从一个Java类特定的映射。 Java类名指定使用class元素的name属性和使用表属性数据库表名指定。

<meta>元素是可选元素，可以用来创建类的描述。

<id>元素映射在类中的唯一ID属性到数据库表的主键。 id 元素的 name 属性是指属性的类和 column 属性是指在数据库表中的列。 type属性保存了Hibernate映射类型，这种类型的映射将会从Java转换为SQL数据类型。

id 元素内的 <generator> 元素被用来自动生成的主键值。将生成元素的class属性设置为原产于让Hibernate无论是identity，sequence或者hilo中的算法来创建主键根据底层数据库的支持能力。

<property> 元素用于一个Java类的属性映射到数据库表中的列。元素的name属性是指属性的类和column属性是指在数据库表中的列。 type属性保存了Hibernate映射类型，这种类型的映射将会从Java转换为SQL数据类型。

还有这将在映射文件中使用，我会尽量覆盖尽可能多的在讨论其他的Hibernate相关主题的其他属性和可用的元素。

创建应用程序类：

最后，我们将创建应用程序类 main() 方法来运行应用程序。我们将使用这个应用程序来保存一些雇员的记录，然后我们将申请CRUD操作上的记录。

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{
         factory = new Configuration().configure().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(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.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();
      }
   }
}

编译和执行：

下面是步骤来编译并运行上述应用程序。请确保已在进行的编译和执行之前，适当地设置PATH和CLASSPATH。

创建hibernate.cfg.xml配置文件中配置章节解释。

创建Employee.hbm.xml映射文件，如上图所示。

创建Employee.java源文件，如上图所示，并编译它。

创建ManageEmployee.java源文件，如上图所示，并编译它。

执行ManageEmployee二进制文件来运行程序。

会得到以下结果，并记录将在EMPLOYEE表中创建。

$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........

First Name: Zara  Last Name: Ali  Salary: 1000
First Name: Daisy  Last Name: Das  Salary: 5000
First Name: John  Last Name: Paul  Salary: 10000
First Name: Zara  Last Name: Ali  Salary: 5000
First Name: John  Last Name: Paul  Salary: 10000

如果检查EMPLOYEE表，它应该有以下记录：

mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 29 | Zara       | Ali       |   5000 |
| 31 | John       | Paul      |  10000 |
+----+------------+-----------+--------+
2 rows in set (0.00 sec

mysql>

Hibernate O/R映射 - hibernate

到目前为止，我们已经看到了非常基本的O/R映射使用Hibernate，但也有我们必须学会在细节三个最重要的映射绘制的主题。这些都是集合的映射，关联的实体类和组件映射之间的映射。

集合映射：

如果一个实体或类有收集特定变量的值，那么我们就可以用在Java中可用的集合接口中的任何一个对应的值。 Hibernate可以持久java.util.Map，java.util.Set中，java.util.SortedMap，java.util.SortedSet，java.util.List和持久性的实体或值的任意阵列的实例。

集合类型 | 映射和说明
java.util.Set | This is mapped with a <set> element and initialized with java.util.HashSet
java.util.SortedSet | This is mapped with a <set> element and initialized with java.util.TreeSet. The sort attribute can be set to either a comparator or natural ordering.
java.util.List | This is mapped with a <list> element and initialized with java.util.ArrayList
java.util.Collection | This is mapped with a <bag> or <ibag> element and initialized with java.util.ArrayList
java.util.Map | This is mapped with a <map> element and initialized with java.util.HashMap
java.util.SortedMap | This is mapped with a <map> element and initialized with java.util.TreeMap. The sort attribute can be set to either a comparator or natural ordering.

数组是由Hibernate与<primitive-array>对Java基本值类型和针对的<array>所有其它支持。然而，他们很少用，所以我不打算讨论这些问题在本教程中。

如果要映射是不直接支持Hibernate的用户定义的集合接口，需要告诉Hibernate有关自定义集合是不太容易的，不建议使用的语义。

关联关系映射：

关联实体类和表之间的关系之间的映射是ORM的灵魂。以下是4的方法，使对象之间的关系的基数可以表示。关联映射可以是单向和双向的。

映射类型 | 描述
Many-to-One | Mapping many-to-one relationship using Hibernate
One-to-One | Mapping one-to-one relationship using Hibernate
One-to-Many | Mapping one-to-many relationship using Hibernate
Many-to-Many | Mapping many-to-many relationship using Hibernate

组件映射：

这是非常有可能是一个实体类可以有一个引用到另一个类的一个成员变量。如果提到类没有它自己的生命周期，并完全依赖于所属的实体类的生命周期被引用类，因此因此被称为Component类。

收集组件的映射也是可能以类似的方式只是作为与次要配置差异正规集合的映射。我们将看到这两个映射详细的例子。

映射类型 | 描述
Component Mappings | 映射一类具有参考到另一个类的一个成员变量。

Hibernate注解 - hibernate

到目前为止，已经看到Hibernate如何使用XML映射文件从POJO的数据到数据库表的改造，反之亦然。 Hibernate注解是一个没有使用XML文件来定义映射的最新方法。可以在除或替换的XML映射元数据使用注解。

Hibernate的注解是强大的方式来提供元数据对象和关系表的映射。所有的元数据被杵到一起的代码POJO java文件这可以帮助用户在开发过程中同时要了解表的结构和POJO。

如果打算让应用程序移植到其他EJB3规范的ORM应用程序，必须使用注解来表示映射信息，但仍然如果想要更大的灵活性，那么应该使用基于XML的映射去。

环境设置Hibernate注释

首先，必须确保使用的是JDK5.0，否则，需要JDK升级到JDK5.0带注解的原生支持的优势。

其次，需要安装Hibernate的3.x注解分发包，可从SourceForge上： (Download Hibernate Annotation) 并拷贝 hibernate-annotations.jar, lib/hibernate-comons-annotations.jar 和 lib/ejb3-persistence.jar 从Hibernate注解分配到CLASSPATH

注释的类实例：

正如提到的，同时使用Hibernate注释工作的所有元数据杵成随着代码的POJO java文件上面这可以帮助用户在开发过程中同时了解表结构和POJO。

考虑到将要使用下面的EMPLOYEE表来存储的对象：

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表的对象Employee类的映射：

import javax.persistence.*;

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

   @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;
   }
}

Hibernate检测@Id注释是对一个字段，并假设它应该直接通过在运行时域访问一个对象的属性。如果将@Id注释getId（）方法，将通过getter和setter方法默认情况下允许访问属性。因此，所有其他注释也被放置在任一字段或getter方法，以下所选择的策略。下面的部分将解释在上面的类中使用的注释。

@Entity 注解:

在EJB3规范说明都包含在javax.persistence包，所以我们导入这个包作为第一步。其次，我们使用了@Entity注解来这标志着这个类作为一个实体bean Employee类，因此它必须有一个无参数的构造函数，总算是有保护的范围可见。

@Table 注解:

@Table注释允许指定的表将被用于保存该实体在数据库中的详细信息。

@Table注释提供了四个属性，允许覆盖表的名称，它的目录，它的架构，并执行对列的唯一约束在表中。现在，我们使用的是刚刚是EMPLOYEE表的名称。

@Id 和 @GeneratedValue 注解:

每个实体bean将有一个主键，注释在类的@Id注解。主键可以是单个字段或根据表结构的多个字段的组合。

默认情况下，@Id注解会自动确定要使用的最合适的主键生成策略，但可以通过应用@GeneratedValue注释，它接受两个参数，strategy和generator，不打算在这里讨论，只使用默认的默认键生成策略。让Hibernate确定要使用的generator类型使不同数据库之间代码的可移植性。

@Column 注解:

@Column批注用于指定的列到一个字段或属性将被映射的细节。可以使用列注释以下最常用的属性：

name属性允许将显式指定列的名称。

length 属性允许用于映射一个value尤其是对一个字符串值的列的大小。

nullable 属性允许该列被标记为NOT NULL生成架构时。

unique 属性允许被标记为只包含唯一值的列。

创建应用程序类：

最后，我们将创建应用程序类的main（）方法来运行应用程序。我们将使用这个应用程序，以节省一些员工的记录，然后我们将申请CRUD操作上的记录。

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.cfg.AnnotationConfiguration;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class ManageEmployee {
   private static SessionFactory factory;
   public static void main(String[] args) {
      try{
         factory = new AnnotationConfiguration().
                   configure().
                   //addPackage("com.xyz") //add package if used.
                   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.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.jdbc.Driver
   </property>

   <!-- Assume students 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">
      cohondob
   </property>

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

编译和执行：

下面是步骤来编译并运行上述应用程序。请确保已在进行的编译和执行之前，适当地设置PATH和CLASSPATH。

从路径中删除Employee.hbm.xml映射文件。

创建Employee.java源文件，如上图所示，并编译它。

创建ManageEmployee.java源文件，如上图所示，并编译它。

执行ManageEmployee二进制文件来运行程序。

会得到以下结果，并记录将在EMPLOYEE表中。

$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........

First Name: Zara  Last Name: Ali  Salary: 1000
First Name: Daisy  Last Name: Das  Salary: 5000
First Name: John  Last Name: Paul  Salary: 10000
First Name: Zara  Last Name: Ali  Salary: 5000
First Name: John  Last Name: Paul  Salary: 10000

如果检查EMPLOYEE表，它应该有以下记录：

mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 29 | Zara       | Ali       |   5000 |
| 31 | John       | Paul      |  10000 |
+----+------------+-----------+--------+
2 rows in set (0.00 sec

mysql>

Hibernate查询语言 - hibernate

Hibernate查询语言（HQL）是一种面向对象的查询语言，类似于SQL，但不是对表和列操作，HQL适用于持久对象和它们的属性。 HQL查询由Hibernate转换成传统的SQL查询，这在圈上的数据库执行操作。

虽然可以直接使用SQL语句和Hibernate使用原生SQL，但建议使用HQL尽可能避免数据库可移植性的麻烦，并采取Hibernate的SQL生成和缓存策略的优势。

都像SELECT，FROM和WHERE等关键字不区分大小写，但如表名和列名的属性是区分在HQL敏感。

FROM 语句

使用FROM子句，如果要加载一个完整的持久化对象到内存中。下面是一个使用FROM子句的简单的语法：

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

如果需要完全限定在HQL一个类名，只需指定如下的包和类名：

String hql = "FROM com.hibernatebook.criteria.Employee";
Query query = session.createQuery(hql);
List results = query.list();

AS 语句

AS子句可以用来别名分配给类中的HQL查询，特别是当有很长的查询。例如，我们前面简单的例子是以下几点：

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

AS关键字是可选的，也可以直接在之后的类名指定别名，如下所示：

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

SELECT 子句

SELECT子句提供了更多的控制权比from子句的结果集。如果想获得对象而不是整个对象的几个属性，使用SELECT子句。下面是一个使用SELECT语句来获取Employee对象只是FIRST_NAME字段的简单的语法：

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

值得注意的是在这里，Employee.firstName是Employee对象的一个属性，而不是EMPLOYEE表的一个字段。

WHERE 子句

如果想缩小了从存储返回的特定对象，可以使用WHERE子句。下面是一个使用WHERE子句的简单的语法：

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

ORDER BY 子句

若要排序HQL查询的结果，将需要使用ORDER BY子句。您可以在结果集按升序（ASC）或降序（DESC）通过在对象的任何属性排序结果。下面是一个使用ORDER BY子句的简单的语法：

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

如果想通过一个以上的属性进行排序，你会仅仅是额外的属性添加到由子句用逗号隔开，如下所示的命令的结尾：

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 子句

该子句允许从Hibernate的它基于属性的值的数据库和组提取信息，并且通常使用结果包括总值。下面是一个使用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();

使用命名参数

Hibernate命名在其HQL查询参数支持。这使得编写接受来自用户的输入容易，不必对SQL注入攻击防御HQL查询。下面是一个使用命名参数的简单的语法：

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 子句

批量更新是新的HQL与Hibernate3，以及不同的删除工作，在Hibernate 3和Hibernate2一样。 Query接口现在包含一个名为executeUpdate()方法用于执行HQL UPDATE或DELETE语句。

在UPDATE子句可以用于更新一个或多个对象中的一个或多个属性。下面是一个使用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 子句

DELETE子句可以用来删除一个或多个对象。下面是一个使用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 子句

HQL支持INSERT INTO子句中只记录在那里可以插入从一个对象到另一个对象。以下是使用INSERT INTO子句的简单的语法：

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);

聚合方法

HQL支持多种聚合方法，类似于SQL。他们工作在HQL同样的方式在SQL和下面的可用功能列表：

S.N. | 方法 | 描述
1 | avg(property name) | The average of a property's value
2 | count(property name or *) | The number of times a property occurs in the results
3 | max(property name) | The maximum value of the property values
4 | min(property name) | The minimum value of the property values
5 | sum(property name) | The sum total of the property values

DISTINCT关键字只计算在该行设定的唯一值。下面的查询将只返回唯一的计数：

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

使用查询分页

有用于分页查询接口的两个方法。

S.N. | 方法与说明
1 | Query setFirstResult(int startPosition) This method takes an integer that represents the first row in your result set, starting with row 0.
2 | Query setMaxResults(int maxResult) This method tells Hibernate to retrieve a fixed number maxResults of objects.

采用上述两种方法一起，可以在网站或Swing应用程序构建一个分页组件。下面是例子，可以扩展来获取10行：

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

Hibernate查询条件 - hibernate

Hibernate提供了操作对象，并依次数据在RDBMS表可用的备用方式。其中一个方法是标准的API，它允许你建立一个标准的查询对象编程，可以套用过滤规则和逻辑条件。

Hibernate的Session接口提供了可用于创建一个返回的持久化对象的类的实例时，应用程序执行一个条件查询一个Criteria对象createCriteria()方法。

以下是最简单的一个条件查询的例子是将简单地返回对应于Employee类的每个对象。

Criteria cr = session.createCriteria(Employee.class);
List results = cr.list();

限制与标准：

可以使用add（）方法可用于Criteria对象添加限制条件查询。下面是例子增加一个限制与薪水返回的记录是等于2000：

Criteria cr = session.createCriteria(Employee.class);
cr.add(Restrictions.eq("salary", 2000));
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 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"));

可以创建AND或OR使用LogicalExpression限制如下条件：

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();

虽然上述所有条件，可以直接使用HQL在前面的教程中介绍。

分页使用标准：

还有的标准接口，用于分页的两种方法。

S.N. | 方法 & 描述
1 | public Criteria setFirstResult(int firstResult) This method takes an integer that represents the first row in your result set, starting with row 0.
2 | public Criteria setMaxResults(int maxResults) This method tells Hibernate to retrieve a fixed number maxResults of objects.

采用上述两种方法一起，我们可以在我们的网站或Swing应用程序构建一个分页组件。下面是例子，可以扩展来每次获取10行：

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

排序的结果：

标准的API提供了org.hibernate.criterion.Order类排序按升序或降序排列你的结果集，根据对象的属性。这个例子演示了如何使用Order类的结果集进行排序：

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 API提供了一个org.hibernate.criterion.Projections类可用于获取平均值，最大值或最小值的属性值。Projections类是类似于类限制，因为它提供了几个静态工厂方法用于获得Projection 实例。 provides the

以下是涉及不同的方案的一些例子，可按规定使用：

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"));

Criteria Queries 例子：

考虑下面的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;
   }
}

让我们创建下面的EMPLOYEE表来存储Employee对象：

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)
);

以下将被映射文件。

<?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="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>

最后，我们将创建应用程序类的main（）方法来运行，我们将使用Criteria查询的应用程序：

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.Criteria;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.Projections;
import org.hibernate.cfg.Configuration;

public class ManageEmployee {
   private static SessionFactory factory;
   public static void main(String[] args) {
      try{
         factory = new Configuration().configure().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();
      }
   }
}

编译和执行：

下面是步骤来编译并运行上述应用程序。请确保您已在进行的编译和执行之前，适当地设置PATH和CLASSPATH。

创建hibernate.cfg.xml配置文件中配置章节解释。

创建Employee.hbm.xml映射文件，如上图所示。

创建Employee.java源文件，如上图所示，并编译它。

创建ManageEmployee.java源文件，如上图所示，并编译它。

执行ManageEmployee二进制运行程序.

会得到以下结果，并记录将创建在EMPLOYEE表中。

$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........

First Name: Daisy  Last Name: Das  Salary: 5000
First Name: John  Last Name: Paul  Salary: 5000
First Name: Mohd  Last Name: Yasee  Salary: 3000
Total Coint: 4
Total Salary: 15000

如果检查EMPLOYEE表，它应该记录如下：

mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 14 | Zara       | Ali       |   2000 |
| 15 | Daisy      | Das       |   5000 |
| 16 | John       | Paul      |   5000 |
| 17 | Mohd       | Yasee     |   3000 |
+----+------------+-----------+--------+
4 rows in set (0.00 sec)

mysql>

Hibernate原生SQL - hibernate

可以使用原生SQL来表达数据库查询，如果想利用数据库特有的功能，如查询提示或者Oracle中的CONNECT关键字。 Hibernate3.x允许使用手写SQL语句，包括存储过程，所有的创建，更新，删除和load操作。

应用程序将从会话创建一个原生SQL查询（Session接口上）createSQLQuery()方法：

public SQLQuery createSQLQuery(String sqlString) throws HibernateException

当传递一个包含SQL查询到createSQLQuery()方法，可以将SQL结果与任何现有的Hibernate实体，联接，或者一个标量结果使用addEntity()方法，addJoin()，和addScalar()方法关联的字符串。

标量查询：

最基本的SQL查询是从一个或多个表中得到标量（数值）的列表。以下是语法使用原生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();

实体的查询：

上面的查询都是返回标量值，也就是从resultset中返回的“裸”数据。以下是语法通过addEntity（）方法来从原生SQL查询获得实体对象作为一个整体。

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

命名SQL查询：

以下是语法通过addEntity（）方法来从原生SQL查询获得实体对象和使用命名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();

Native SQL 例子：

考虑下面的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;
   }
}

让我们创建下面的EMPLOYEE表来存储Employee对象：

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)
);

以下将被映射文件。

<?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="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>

最后，我们将创建应用程序类的main（）方法来运行，我们将使用原生SQL查询的应用程序：

import java.util.*;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.SQLQuery;
import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.cfg.Configuration;

public class ManageEmployee {
   private static SessionFactory factory;
   public static void main(String[] args) {
      try{
         factory = new Configuration().configure().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();
      }
   }
}

编译和执行：

下面是步骤来编译并运行上述应用程序。请确保在进行的编译和执行之前，适当地设置PATH和CLASSPATH。

创建hibernate.cfg.xml配置文件中配置章节解释。

创建Employee.hbm.xml映射文件，如上图所示。

创建Employee.java源文件，如上图所示，并编译它。

创建ManageEmployee.java源文件，如上图所示，并编译它。

执行ManageEmployee二进制文件来运行程序。

会得到以下结果，并记录将在EMPLOYEE表中创建。

$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........

First Name: Zara, Salary: 2000
First Name: Daisy, Salary: 5000
First Name: John, Salary: 5000
First Name: Mohd, Salary: 3000
First Name: Zara  Last Name: Ali  Salary: 2000
First Name: Daisy  Last Name: Das  Salary: 5000
First Name: John  Last Name: Paul  Salary: 5000
First Name: Mohd  Last Name: Yasee  Salary: 3000

如果检查EMPLOYEE表，它应该记录下已：

mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 26 | Zara       | Ali       |   2000 |
| 27 | Daisy      | Das       |   5000 |
| 28 | John       | Paul      |   5000 |
| 29 | Mohd       | Yasee     |   3000 |
+----+------------+-----------+--------+
4 rows in set (0.00 sec)

mysql>

Hibernate缓存 - hibernate

缓存是所有关于应用程序的性能优化和它位于应用程序和数据库之间，以避免数据库访问多次，让性能关键型应用程序有更好的表现。

缓存对Hibernate很重要，它采用了多级缓存方案下文所述：

第一级缓存：

第一级缓存是Session的缓存，是一个强制性的缓存，通过它所有的请求都必须通过。 Session对象不断自身的动力的对象，提交到数据库之前。

如果发出多个更新一个对象，Hibernate试图拖延尽可能长的时间做了更新，以减少发出的更新SQL语句的数量。如果您关闭会话，所有被缓存的对象都将丢失，要么持久，或在数据库中更新。

二级缓存：

二级缓存是可选的缓存和一级缓存，总是会征询任何试图找到一个对象的二级缓存之前。第二级缓存可以在每个类和每个集合基础上进行配置，主要负责在会话缓存的对象。

任何第三方缓存可以使用Hibernate。org.hibernate.cache.CacheProvider接口提供，必须实施提供Hibernate一个句柄缓存实现。

查询级别缓存：

Hibernate也实现了查询结果集缓存与二级缓存的紧密集成在一起。

这是一个可选功能，需要两个额外的物理缓存中保存缓存的查询结果和地区当一个表的最后更新的时间戳。这只是针对那些使用相同的参数经常运行的查询非常有用。

二级缓存：

Hibernate使用一级缓存，默认情况下，你什么都没有做使用第一级缓存。让我们直接进入可选的第二级缓存。并不是所有的类受益于缓存，这样一来就能禁用二级缓存是很重要的

Hibernate二级缓存被设置为两个步骤。首先，必须决定要使用的并发策略。在此之后，可以配置缓存过期和使用缓存提供物理缓存属性。

并发策略：

并发策略是一个中介的负责存储数据项在缓存并从缓存中检索它们。如果要启用二级缓存，将必须决定，为每个持久化类和集合，要使用的缓存并发策略。

Transactional: 使用这种策略的主要读取数据的地方，以防止过时的数据的并发事务，在更新的罕见情况下是至关重要的。

Read-write: 再次使用这种策略的主要读取数据的地方，以防止并发事务陈旧的数据是至关重要的，在更新的罕见情况。

Nonstrict-read-write: 这种策略不保证缓存与数据库之间的一致性。使用此策略，如果数据很少改变和陈旧数据的可能性很小关键是不关注。

Read-only: 并发策略适用于数据，永远不会改变。使用数据仅供参考。

如果我们要使用第二级缓存为我们的Employee类，让我们添加告诉Hibernate使用可读写的高速缓存策略Employee实例所需的映射元素。

<?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="Employee" table="EMPLOYEE">
      <meta attribute="class-description">
         This class contains the employee detail.
      </meta>
      <cache usage="read-write"/>
      <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>

usage="read-write" 属性告诉Hibernate使用一个可读写的并发策略定义的缓存。

缓存提供者：

考虑到会用你的缓存候选类的并发策略后，下一步就是选择一个缓存提供程序。Hibernate迫使选择一个缓存提供整个应用程序。

S.N. | 缓存名称 | 描述
1 | EHCache | 它可以在内存或磁盘上以及群集缓存缓存，它支持可选的Hibernate查询结果缓存。
2 | OSCache | 支持缓存内存和磁盘在一个JVM中，有一组丰富的过期策略和查询缓存的支持。
3 | warmCache | 基于JGroups的集群缓存。它使用群集失效，但不支持Hibernate的查询缓存
4 | JBoss Cache | 一个完全的事务复制的集群缓存也是基于JGroups的组播库。它支持复制或失效，同步或异步通信，乐观和悲观锁定。支持Hibernate的查询缓存

每一个缓存提供程序是不是与每个并发策略兼容。以下兼容性矩阵将帮助选择合适的组合。

Strategy/Provider | 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配置文件中的缓存提供。选择EHCache作为第二级缓存提供程序：

<?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 students 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">
      root123
   </property>
   <property name="hibernate.cache.provider_class">
      org.hibernate.cache.EhCacheProvider
   </property>

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

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

现在，需要指定缓存区域的属性。EHCache都有自己的配置文件ehcache.xml，在应用程序在CLASSPATH中。在ehcache.xml中Employee类高速缓存配置可能看起来像这样：

<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"
/>

就这样，现在启用Employee类的二级缓存和Hibernate现在二级缓存，每当浏览到一个雇员或当通过标识符加载雇员。

应该分析你所有的类，并选择适当的缓存策略为每个类。有时，二级缓存可能降级的应用程序的性能。所以建议到基准应用程序第一次没有启用缓存，非常适合缓存和检查性能。如果缓存不提高系统性能再有就是在使任何类型的缓存是没有意义的。

查询级别缓存：

使用查询缓存，必须先使用 hibernate.cache.use_query_cache="true"属性配置文件中激活它。如果将此属性设置为true，让Hibernate的在内存中创建所需的高速缓存来保存查询和标识符集。

接下来，使用查询缓存，可以使用Query类的setCacheable（Boolean）方法。例如：

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

Hibernate也支持通过一个缓存区域的概念非常细粒度的缓存支持。缓存区是这是给定一个名称缓存的一部分。

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

此代码使用方法告诉Hibernate来存储和查找在缓存中的员工方面的查询。

Hibernate批量处理 - hibernate

考虑这样一种情况，当需要使用Hibernate上传大量的记录到数据库中。以下是代码片段实现这一使用Hibernate：

Session session = SessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
    Employee employee = new Employee(.....);
    session.save(employee);
}
tx.commit();
session.close();

因为默认情况下，Hibernate会缓存所有的持久对象在session级别的缓存，并最终应用程序会失败并发生OutOfMemoryException某处50,000条记录左右。如果使用的是批量处理与Hibernate解决这个问题。

要使用批量处理功能，首先设置hibernate.jdbc.batch_size为批量大小若干无论是在20或50根据对象的大小。这将告诉每X行插入批次hibernate的容器。为了实现这个在代码中，我们需要做一点修改如下：

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();

上面的代码将正常工作INSERT操作，但如果愿意做UPDATE操作，那么可以使用下面的代码实现：

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

ScrollableResults employeeCursor = session.createQuery("FROM EMPLOYEE")
                                   .scroll();
int count = 0;

while ( employeeCursor.next() ) {
   Employee employee = (Employee) employeeCursor.get(0);
   employee.updateEmployee();
   seession.update(employee);
   if ( ++count % 50 == 0 ) {
      session.flush();
      session.clear();
   }
}
tx.commit();
session.close();

批处理示例：

让我们修改配置文件作为补充hibernate.jdbc.batch_size属性：

<?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 students 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">
      root123
   </property>
   <property name="hibernate.jdbc.batch_size">
      50
   </property>

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

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

考虑下面的POJO Employee类：

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表来存储Employee对象：

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表的对象。

<?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="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>

最后，我们将创建与应用程序类main()方法来运行，我们将使用flush() 和 clear()可Session对象方法，使Hibernate的继续写这些记录到数据库中，而不是它们缓存中的应用内存。

import java.util.*;

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{
         factory = new Configuration().configure().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 ;
   }
}

编译和执行：

下面是步骤来编译并运行上述应用程序。请确保您已在进行的编译和执行之前，适当地设置PATH和CLASSPATH。

创建hibernate.cfg.xml配置文件，如上面所述。

创建Employee.hbm.xml映射文件，如上图所示。

创建Employee.java源文件，如上图所示，并编译它。

创建ManageEmployee.java源文件，如上图所示，并编译它。

执行ManageEmployee二进制运行将在EMPLOYEE表中创建100000条记录程序。

Hibernate拦截器 - hibernate

正如前面已经了解到，在Hibernate中，对象将被创建并保存。一旦对象已经改变，它必须被保存到数据库中。这个过程一直持续的对象是需要的，直到下一次，并且它将被从持久存储加载。

因此，一个对象通过不同阶段的生命周期和拦截器接口提供了可以在不同的阶段被调用来执行一些任务所需的方法。这些方法是从session到应用程序的回调，允许它被保存在申请前检查和/或操纵持久化对象的属性，更新，删除或加载。以下是拦截器界面中所有可用的方法列表：

S.N. | Method and 描述
1 | findDirty() This method is be called when the flush() method is called on a Session object.
2 | instantiate() This method is called when a persisted class is instantiated.
3 | isUnsaved() This method is called when an object is passed to the saveOrUpdate() method/
4 | onDelete() This method is called before an object is deleted.
5 | onFlushDirty() This method is called when Hibernate detects that an object is dirty (ie. have been changed) during a flush i.e. update operation.
6 | onLoad() This method is called before an object is initialized.
7 | onSave() This method is called before an object is saved.
8 | postFlush() This method is called after a flush has occurred and an object has been updated in memory.
9 | preFlush() This method is called before a flush.

Hibernate拦截器为我们提供了完全控制对象如何将目光转向应用程序和数据库。

如何使用拦截器？

为了建立一个拦截器可以直接实现Interceptor接口的类或继承自EmptyInterceptor类。以下将简单的步骤来使用Hibernate拦截功能。

创建拦截器：

我们将在例子在创建和更新Employee对象时，拦截器的方法将被自动调用继承自EmptyInterceptor。可以实现更多的方法按您的要求。

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");
   }
}

创建POJO类：

现在，让我们修改一点点，我们使用的EMPLOYEE表和Employee类一起看一个例子：

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;
   }
}

创建数据库表：

第二步是在数据库中创建表。会有一个表对应于每一个对象，愿意提供持久性。考虑上述目的需要存储和检索到下面的RDBMS表：

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)
);

创建映射配置文件：

这一步是创建一个指示Hibernate如何定义的一个或多个类映射到数据库表的映射文件。

<?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="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>

创建应用程序类：

最后，我们将创建应用程序类的main()方法来运行应用程序。这里应该指出的是，在创建会话对象，我们使用了拦截器类作为参数。

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{
         factory = new Configuration().configure().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( new MyInterceptor() );
      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.openSession( new MyInterceptor() );
      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( new MyInterceptor() );
      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( new MyInterceptor() );
      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();
      }
   }
}

编译和执行：

下面是步骤来编译并运行上述应用程序。请确保已在进行的编译和执行之前，适当地设置PATH和CLASSPATH。

创建hibernate.cfg.xml配置文件中配置章节解释。

创建Employee.hbm.xml映射文件，如上图所示。

创建Employee.java源文件，如上图所示，并编译它。

创建MyInterceptor.java源文件，如上图所示，并编译它。

创建ManageEmployee.java源文件，如上图所示，并编译它。

执行ManageEmployee二进制文件来运行程序。

会得到以下结果，并记录将在EMPLOYEE表中创建。

$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........

Create Operation
preFlush
postFlush
Create Operation
preFlush
postFlush
Create Operation
preFlush
postFlush
First Name: Zara  Last Name: Ali  Salary: 1000
First Name: Daisy  Last Name: Das  Salary: 5000
First Name: John  Last Name: Paul  Salary: 10000
preFlush
postFlush
preFlush
Update Operation
postFlush
preFlush
postFlush
First Name: Zara  Last Name: Ali  Salary: 5000
First Name: John  Last Name: Paul  Salary: 10000
preFlush
postFlush

如果检查EMPLOYEE表，它应该记录信息下：

mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 29 | Zara       | Ali       |   5000 |
| 31 | John       | Paul      |  10000 |
+----+------------+-----------+--------+
2 rows in set (0.00 sec

mysql>