Hibernate
jdbc Java Databases Connectivity, 他是提供了一组Java API来访问关系数据库的Java程序。这些Java API 可以使Java应用程序执行SQL语句,能够与任何符合SQL规范的数据进行交互。
JDBC提供了一个灵活的框架来编写操作数据库的独立的应用程序,该程序能够运行在不同的平台上且不需修改,能够与不同的DBMS 进行交互。
- ORM 对象关系映射 Object-Relational Mapping(ORM),是一个方便在关系数据库和类似于Java等面向对象的编程语言中转换数据的技术。一个ORM系统相比于普通的JDBC有以下优点。
1) 使用业务代码访问对象而不是数据库中的表
2) 从面向对象逻辑中隐藏SQL查询的细节
3) 基于JDBC的under the hood
4) 没有必要去处理数据库 实现
5) 实体是基于业务的概念而不是数据库的结构
6) 事务管理和键的自动生成
7) 应用程序的快速开发
一个ORM解决方案由一下四个实体组成:
1) 一个API来在持久类的对象上实现基本的CRUD操作
2) 一个语言或API来指定引用类和属性的查询
3) 一个可配置的服务用来指定映射元数据
4) 一个技术和事务对象交互来执行 dirty checking,lazy association fething 和其他优化的功能。
Java ORM 框架
Hibernate 优势
1) Hibernate使用XML文件来处理映射Java类别到数据库表格中,并且不用编写任何代码。
2) 为在数据库红直接储存和检索Java对象提供简单的APIs
3) 如果在数据库中或任何其他表格中出现变化,那么仅需要改变XML文件属性。
4) 抽象不熟悉的SQL类型,并未我们提供工作中所熟悉的Java对象
5) Hibernate 不需要应用程序服务器来操作。
6) 操作你数据库中复杂的关联
7) 最小化与访问数据库的只能提取策略。
8) 提供简单的数据询问
支持的技术
Hibernate 支持多种技术
- 架构
下面是Hibernate应用程序体系结构视图以及一些重要的类
配置对象
配置对象使你再任何hibernate应用程序中创造的第一个Hibernate对象,并且经常只在应用程序初始化期间创造。它代表了Hibernate所需一个配置或属性文件。配置对象提供了两种基础组件。
1) 数据库连接:由Hibernate支持的一个或多个配置文件处理。这些文件是hibernate.properties 和 hibernate.cfg.xml
2) 类映射设置:这个组件创造了Java类和数据库表格之间的联系。
SessionFactory 对象
配置对象被用于创造一个SessionFactory对象,使用提供的配置文件为应用程序依次配置hibernate,并允许实例化一个会话对象。SessionFactory是一个线程安全对象并由应用程序多有的线程所使用。
SessionFactory是一个重量级对象所以它通常都是在应用程序启动时创造然后留存为以后使用。每个数据库需要一个SessionFactory对象使用一个单独的配置文件。所以如果你使用多种数据库那么你要创造多种SessionFactory 对象。
Session 对象
一个会话被用于与数据库的物理连接。Session对象是轻量级的,并被设计为每次实例化都需要与数据库的交互。持久对象通过Session对象保存和检索。
Transaction 对象
一个事务代表了与数据库工作的一个单元并且大部分RDBMS 支持事务功能。在hibernate中事务由底层事务管理器和事务(来自于JDBC或者JTA)处理
这是一个选择性对象,hibernate应用程序可能不选择使用这个接口,而是在自己应用程序代码中管理事务。
Query对象
Query对象使用SQL或者 Hibernate查询语言(HQL)字符串在数据库中来检索数据并创造对象。一个查询的实例被用于连接查询参数,限制由查询返回的结果数量,并最终执行查询。
Criteria 对象
Criteria对象被用于创造和执行面向规则查询的对象来检索对象。
- 环境
- 配置
Hibernate 属性
Hibernate.dialect
这个属性使hibernate应用为被选择的数据库生成适当的SQL
Hibernate.connection.driver_class
JDBC驱动程序类
Hibernate.connection.url
数据库实例的JDBC URL
Hibernate.connection.username
数据库用户名
Hibernate.connection.password
数据库密码
Hibernate.connection.pool_size
限制在hibernate应用数据库连接池中连接的数量
Hibernate.connection.autocommit
允许在JDBC连接中使用自动提交模式
如果你正在使用JNDI和数据库应用程序服务器然后你必须配置以下属性
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
数据库密码
- 会话
Session 用于获取与数据库的物理连接。Session对象是轻量级的,并且为在每次需要与数据库进行交互时被实例化。持久态对象被保存,并通过Session对象检索找回。
改Session对象不应该长时间保持开放状态,因为他们通常不能保证线程安全,而应该根据需求被创建和销毁。Session的主要功能是为了映射实体类的实例提供创建,读取和删除操作。这些实例可能在给定时间点时存在以下三种状态之一:
1) 瞬时状态:一种新的持久性实例,被hibernate认为是瞬时的,它不与Session相关联,在数据库中没有与之关联的记录且无标识符值。
2) 持久状态:可以将一个瞬时状态实例通过与一个Session关联的方式将其转化为持久状态实例。持久状态实例在数据库中没有与之关联的记录,有标识符值,并与一个Session关联。
3) 脱管状态:一旦关闭hibernate Session,持久状态实例将会成为脱管状态实例。
- 持久化类
Hibernate的完整概念是提取Java类属性汇总的值,并且将他们保存到数据库表单中。映射文件能够帮助hibernate确定如何从该类中提取值,并将他们映射在表格和相关域中。
在hibernate中,其对象或实例将会被存储在数据库表单中的Java类被成为持久化类。若该类遵循一些简单的规则或者被大家所熟知的Plain Old Java Object(POJO)变成模型,hibernate将会处于其最佳运行状态。以下就是持久化类的主要规则,然而,在这些规则中,没有一条是硬性要求。
1) 所有将被持久化的Java类都需要一个默认的构造函数
2) 为了使对象能够在hibernate和数据库中容易识别,所有类都需要包含一个ID。此属性映射到数据库表的主键列
3) 所有将被持久化的属性都应该声明为private,并具有JavaBean风格定义的getXXX和setXXX方法
4) Hibernate的一个重要特征为代理,他取决于该持久化类是出于非final的,还是处于一个所有方法都声明的public接口
5) 所有的类是不可扩展或按EJB要求实现的一些特殊的类和接口
POJO的名称用于强调一个给定的对象是普通的Java对象,而不是特殊的对象,尤其不是一个Enterprise JavaBean。
- 映射文件
一个对象/关系型映射一般定义在XML文件中。映射文件指示hibernate如何将已经定义的类或类组与数据库中的表对应起来。
尽管有些hibernate用户选择手写XML文件,但是有很多工具可以用来给先进的hibernate用户生成映射文件。这样的工具包括XDoclet,Middlegen,AndROMDA。
<?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中。让我们来详细地看一下在映射文件中使用的一些标签:
1) 映射文件是一个以<hibernate-mapping>为根元素的XML文件,里面包含所有<class>标签。
2) <class>标签是用来定义从一个Java类到数据库的特定映射。Java的类名使用name属性来表示,数据库表名用table属性来表示
3) <meta>标签是一个可选元素,可以用来修饰类。
4) <id>标签将类中独一无二的ID属性与数据库表中的name属性引用类的属性,column属性引用数据库表的列。Type属性保存hibernate映射的类型,这个类型会将从Java转换成sql数据类型。
5) 在id元素中的<generateor>标签用来自动生成主键值。设置generator标签中的class属性可以设置native使hibernate可以使用identity,sequence或hilo算法根据底层数据库的情况来创建主键。
6) <property>标签用来将Java类的属性与数据库表的列匹配。标签中name属性引用的死类的性质,column属性引用的是数据库表的列。Type属性保存hibernate映射的类型,这个类型会将从Java转换成sql数据类型
- 映射类型
当你准备一个hibernate映射文件时,我们已经看到你把Java数据类型映射到了RDBMS数据格式。在映射文件中已经声明被使用的types不是Java数据类型;他们也不是sql数据库类型。这种类型被称为hibernate映射类型,可以从Java翻译擦恒sql,反之亦然。
1) 原始类型
2) 日期和时间类型
3) 二进制和大型数据对象
4) JDK相关类型
5) 集合映射
如果一个实例或者类中有特定变量的值的集合,那么我们可以应用Java中的任何的可用的接口来映射这些值。Hibernate可以保存java.util.Set,java.util.Map,java.util.SortedMap,java.util.List和其他持续的实例或者值的任何数组的实例。
对于Java的原始数据值hibernate采用<primitive-array>支持数组,对于Java的其他数值hibernate采用<array>支持数组。然而它们很少被应用。
6) 关联映射
实体类质检的关联映射以及表质检的关系是ORM的灵魂之处。对象间的关系的子集可以用下列四种方法解释。关联映射可以使单向的也可以使双向的。
- 注释
到现在为止,你已经看到hibernate如何使用XML映射文件来完成从POJO到数据表的数据转换的,反之亦然。Hibernate注释是无需使用XML文件来定义映射的最新方法。你可以额外使用注释或直接代替XML映射元数据。
Hibernate注释是一种强大的来给对象和关系映射表提供元数据的方法。所有的元数据被添加到POJO java文件代码中,这有利于用户在开发时更好的理解表的结构和POJO
如果你想让你的应用程序一直到其他EJB 3 的ORM应用程序中,你必须使用注释来表示映射信息,但是如果想要得到更大的灵活性,那么你应该使用基于XML的映射。
@Entity注释
EJB 3 标准的注释包含在javax.persistence包,所以我们第一步需要导入这个包。第二步我们对Employee类使用@Entity注释,标志着这个类为一个实体bean,所以它必须含有一个没有参数的构造函数并且在可保护范围是可见的。
@Table注释
@table注释允许你明确表的详细信息保证实体在数据库中持续存在。
@table 注释提供了四个属性,允许你覆盖的表的名称,目录及其模式,在表中可以对列制定独特的约束。现在我们使用的是表名为EMPLOYEE
@Id和@GeneratedValue注释
每一个实体bean都有一个主键,你再类中可以用@Id来进行注释。主键可以使一个字段或者是多个字段的组合,这取决于你的表的结构。
默认情况下,@Id注释将自动确定最合适的主键生成策略,但是你可以通过使用@GeneratedValue注释来覆盖掉它。strategy和generator两个参数不在这里讨论。
@Column Annotation
@Column注释用于指定某一列与某一个字段或者是属性映射的细节信息。你可以使用下列注释的最常用的属性:
1) name 属性允许显式地指定列的名称
2) length属性允许为用于映射一个值,特别为一个字符串值的列的大小。
3) nullable属性允许当生成模式时,一个列可以被标记为非空
4) unique属性允许列中只能含有唯一的内容
- 数据库配置
现在,让我们创建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>
- 查询语言
Hibernate查询语言(HQL)是一种面向对象的查询语言,类似于SQL,但不是去对表和列进行操作,而是面向对象和他们的属性。HQL查询被Hibernate翻译为传统的SQL查询而对数据库进行操作。
尽管你能直接用本地SQL语句,但我还是建议你尽可能的使用HQL语句,以避免数据库关于可一致性的麻烦,并且体现了Hibernate的SQL生成和缓存策略。
在HQL中一些关键字比如SELECT,FROM 和WHERE等 ,是不区分大小写的,但是一些属性比如表名和列名是区分大小写的。
1) FROM语句
如果你想要在存储中加载一个完整并持久的对象,你将使用FROM语句。一下是FROM语句的一些简单的语法:
String hql = “FROM Employee”;
Query query = session.createQuery(hql);
List results = query.list();
2) AS语句
在HQL中AS语句能够给你的类分配别名,尤其是在长查询的情况下。例如,我们之前的例子,可以用如下方式展示:
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();
3) 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的字段。
4) WHERE语句
如果你想要精确地从数据库储存中返回特定的对象,你需要使用WHERE语句。下面是WHERE语句的简单语法例子:
String hql = “FROM Employee E WHERE E.id = 10”;
Query query = session.createQuery(hql);
List results = query.list();;
5) ORDER BY语句
为了给HSQ查询结果进行排序,你将需要使用ORDER BY语句。你能利用任意一个属性给你的结果进行排序,包括升序或降序排序。下面是一个使用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();
如果你想要给多个属性进行排序,你只需在ORDER BY 语句后面添加你要进行排序的属性即可,并且用逗号进行分割:
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();
6) 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();
7) 使用命名参数
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);
8) 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);
9) 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);
10)聚合方法
HQL 类似于 SQL,支持一系列的聚合方法,它们以同样的方式在 HQL 和 SQL 中工作,以下列出了几种可用方
法:
distinct 关键字表示只计算行集中的唯一值。下面的查询只计算唯一的值:
String hql = "SELECT count(distinct E.firstName) FROM Employee E";
Query query = session.createQuery(hql);
List results = query.list();
11)使用分页查询
以下为两种分页查询页面的方法
使用以下两种方法,我们可以在我们的web或spring应用程序中构造一个分页组件。
String hql = "FROM Employee";
Query query = session.createQuery(hql);
query.setFirstResult(1);
query.setMaxResults(10);
List results = query.list();
13.标准查询
Hibernate提供了操作对象和相应的RDBMS表中可用的数据的替代方法。一种方法的标准的API,他允许你建立一个标准的可编程查询对象来应用过滤规则和逻辑条件。
Hibernate Session接口提供了createCriteria()方法,可用于创建一个Criteria对象,使当您的应用程序执行一个标准查询时返回一个持久化对象的类的实例。
以下是一个最简单的标准查询的例子,它只是简单地返回对应于员工类的每个对象:
Criteria cr = session.createCriteria(Employee.class);
List results = cr.list();
对标准的限制
你可以使用Criteria对象可用的add()方法去添加一个标准查询的限制。
以下是一个实例,他实现了添加一个现实,令返回工资等于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 的条件组合:
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 直接使用。
分页使用标准
这里有两种分页标准接口方法:
利用上述两种方法结合在一起,我们可以在我们的web或swing应用程序构建一个分页组件。以下是一个例子,利用它你可以一次取出10行:
Criteria cr = session.createCriteria(Employee.class);
cr.setFirstResult(1);
cr.setMaxResults(10);
List results = cr.list();
排序结果
标准API提供了org.hibernate.criterion.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();
预测与聚合
标准 API 提供了 s org.hibernate.criterion.projections 类可得到各属性值的平均值,最大值或最小值。Projectio
ns 类与 Restrictions 类相似,均提供了几个获取预测实例的静态工厂方法。
以下是几个例子,涵盖了不同的情况,可按要求进行使用:
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"));
15. 原生SQL
如果你想使用数据库特定的功能如查询提示或Oracle中的CONNECT关键字的话,你可以使用原生SQL数据库来表达查询。Hibernate 允许你为所有的创建,更新,删除,和加载操作指定手写SQL,包括存储过程。你的应用程序会在会话界面用createSQLQuery(String sqlString)throws HibernateException
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();
实体查询
以上的查询都是关于返回标量值的查询,只是基础性地返回结果集中的“原始”值。以下是从原生SQL查询中通过addEntity()方法获取实体对象整体的语法:
String sql = "SELECT * FROM EMPLOYEE";
SQLQuery query = session.createSQLQuery(sql);
query.addEntity(Employee.class);
List results = query.list();
指定SQL查询
以下是从原生 SQL 查询中通过 addEntity() 方法和使用指定 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();
16. 缓存
缓存是关于应用程序性能的优化,降低了应用程序对物理数据源访问的频次,从而提高应用程序的运行性能。缓存对Hibernate来说也是重要的,他使用了如下解释的多级缓存方案:
1) 一级缓存
第一级缓存是Session缓存并且是一种强制性的缓存,所有的要求都必须通过它。Session对象在它自己的权利之下,在将它提交给数据库之前保存一个对象。
如果你对一个对象发出多个更新,Hibernate会尝试尽可能长地延迟更新来减少发出的SQL更新语句的数目。如果你关闭session,所有缓存的对象丢失,或是存留,或是在数据库中被更新。
2) 二级缓存
第二季缓存是一种可选择的缓存并且第一级缓存在任何想要在第二级缓存中找到一个对象前将总是被询问。第二级缓存可以在每一个类和每一个集合的基础上安装,并且他主要负责跨会话缓存对象。
任何第三方缓存可以和Hibernate一起使用。Org.hibernate.cache.CacheProvider接口被提供,他必须实现来是给Hibernate提供一个缓存实现解决方法。
3) 查询层次缓存
Hibernate也实现了一个和第二级缓存密切集成的查询结果集缓存。
这是一个可选择的特点并且需要两个额外的物理缓存区域,它们保存着缓存的查询结果和表单上一次更新时间戳。这仅对以同一个参数频繁运行的查询来说是有用的。
4) 第二级缓存
Hibernate使用默认的一级缓存并且你不用使用一级缓存。让我们直接看向可选的二级缓存。不是所有的类从缓存中获益,所以能关闭二级缓存是重要的。
Hibernate的二级缓存通过两部设置。第一,你必须决定好使用哪个并发策略。之后,你使用提供程序来配置缓存到期时间和物理缓存属性。
5) 并发策略
一个并发策略是一个中介,他负责保存缓存中的数据项和从缓存中检索它们。如果你将使用一个二级缓存,你必须决定,对于每一个持久类和集合,使用哪一个并发策略。
Transactional:为主读数据使用这个策略,在一次更新的罕见状况下并发事务阻止过期数据是关键的
Read-write:为主读数据再一次使用这个策略,在一次更新的罕见状况下并发事务阻止过期数据是关键的
Nonstrict-read-write:这个策略不保证缓存和数据库之间的一致性。如果数据几乎不改变并且过期数据不是
很重要,使用这个策略。
Read-only:一个适合永不改变数据的并发策略。只为参考数据使用它。
如果我们将为我们的 e Employee 类使用二级缓存,让我们使用 read-write 策略来添加需要告诉 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 为定义的缓存使用 read-write 并发策略
6) 缓存提供者
在考虑你将为你的缓存候选类所使用的并发策略后你的下一步是挑选一个缓存提供者。Hibernate让你为整个应用程序选择一个单独的缓存提供者。
每一个缓存提供者都不和每个并发策略兼容。以下的兼容性矩阵将帮助你选择一个合适的组合。
你将在hibernate.cfg.cml配置文件中指定一个缓存提供者。我们选择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,它应该在应用程序的classpah中。Employee类的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"
/>
就是这样,现在我们有Employee类的二级缓存Hibernate现在能命中缓存无论你是导航到Employee时 或是当你通过标识符上传Employee时。
你应该为每个类分析你所有的类并选择合适的缓存策略。有时候,二级缓存可能是应用程序的表现下降。所以首先不允许缓存用基准程序测试你的应用程序,然后开启合适的缓存,之后检测表现是退件的。如果缓存不提升系统表现那么支持任何类型的缓存都是没有意义的。
7) 查询层次缓存
为了使用查询缓存,你必须首先使用配置文件中的hibernate.cache.use_query_cache=“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存储和寻找缓存Employee区域的查询。
17. 批处理
18. 拦截器
你已经学到,在Hibernate中,一个对象将被创建和保持。一旦对象已经被修改,它必须被保存到数据库里。这个过程持续到下一次对象被需要,它将被从持久的存储中加载。
因此一个对象通过它生命周期中的不同阶段,并且Interceptor接口提供了在不同阶段给你被调用来进行一些所需要的任务的方法。这些方法是从会话到应用程序的回调函数,允许应用程序检查或操作一个持续对象的属性,在它被保存,更新,删除或上传之前。以下是在Interceptor接口中可用的所有方法的列表。
Hibernate拦截器给予了我们一个对象如何应用到应用程序和数据库的总控制。
如何使用拦截器
为了创建一个拦截器你可以直接实现interceptor类或者继承EmptyInterceptor类。