主要来源:

http://blog.csdn.net/csh624366188/article/details/7612142  (比较详细)

http://www.cnblogs.com/200911/archive/2012/10/09/2716873.html

http://dododo1234321-163-com.iteye.com/blog/1828173

什么是缓存?

  缓存是介于物理数据源与应用程序之间,是对数据库中的数据复制一份临时放在内存中的容器,其作用是为了减少应用程序对物理数据源访问的次数,从而提高了应用程序的运行性能。Hibernate在进行读取数据的时候,根据缓存机制在相应的缓存中查询,如果在缓存中找到了需要的数据(我们把这称做“缓存命 中"),则就直接把命中的数据作为结果加以利用,避免了大量发送SQL语句到数据库查询的性能损耗。

  缓存策略提供商:

提供了HashTable缓存,EHCache,OSCache,SwarmCache,jBoss Cathe2,这些缓存机制,其中EHCache,OSCache是不能用于集群环境(Cluster Safe)的,而SwarmCache,jBoss Cathe2是可以的。HashTable缓存主要是用来测试的,只能把对象放在内存中,EHCache,OSCache可以把对象放在内存(memory)中,也可以把对象放在硬盘(disk)上(为什么放到硬盘上?上面解释了)

6. Hibernate缓存

总体分为:  一级缓存、二级缓存、查询缓存。

缓存是为了提高性能

变化不是很大,相对静态的对象放入缓存

6.1 一级缓存

Hibernate向我们提供的主要的操纵数据库的接口,Session就是其中的一个,它提供了基本的增,删,改,查方法(如session.save , session.delete , session.update , session.get , session.load方法).对应的它有一个缓存机制(一级缓存) ,能够按照某个时间点,按照缓存中的持久化对象属性的变化来更新数据库,这就是Session的缓存清理过程.

一级缓存的生命周期跟Session的生命周期一样,所以也可以理解为一级Hibernate缓存是session缓存,因此将一级缓存称为session级缓存或事务级缓存。

TIPS: 每一个Hibernate Session实例和一个数据库事务绑定通常将每一个Hibernate Session实例和一个数据处理库事务绑定就是说,每执行一个数据库事务(操作),都应该先创建一个新的Hibernate Session实例.
如果事务执行中出现异常,应该撤消事务.不论事务执行成功与否,最后都应该调用Session的close()方法,从而释放Hibernate Session实例占用的资源.

6.1.1 Session缓存的作用

将相关数据映射为对象放到内存中,减轻对数据库的操作次数。

一般情况下调用session.get / load 通过id加载对象的时候, Hibernate会首先到一级缓存中查找是否存在该对象/对象的代理.如没有则在二级缓存中查找. 如找到则直接返回.如找不到才会去数据库查询.

所以在第一次session.get()查询出某对象后, 只要同一session并未close. 再次调用get/load查询同一id的对象.数据库不再发出SQL语句.(相关细节涉及get/load的异同, 以及延迟加载).

总而言之: 一级缓存的主要作用为

(1)减少访问数据库的频率。应用程序从内存中读取持久化对象的速度显然比到数据库中查询数据的速度快多了,因此Session的缓存可以提高数据访问的性能。

(2)保证缓存中的对象与数据库中的相关记录保持同步。当缓存中持久化对象的状态发生了变化,Session并不会立即执行相关的SQL语句,这使得Session能够把几条相关的SQL语句合并为一条SQL语句,以便减少访问数据库的次数,从而提高应用程序的性能。

6.1.2 Session缓存(一级缓存)的实现

  一级缓存采用的是key-value的Map方式来实现的,在缓存实体对象时,对象的主关键字ID是Map的key,实体对象就是对应的值。所以说,一级缓存是以实体对象为单位进行存储的,在访问的时候使用的是主关键字ID。
虽然,Hibernate对一级缓存使用的是自动维护的功能,没有提供任何配置功能,但是可以通过Session中所提供的方法来对一级缓存的管理进行手工干预。

6.1.3 Session的清理缓存

    (即一级缓存清理并同步更新数据库)

  清理缓存是指按照缓存中对象的状态的变化来同步更新数据库。

 6.1.3.1 Session会在下面的时间点清理缓存(一级缓存将变化同步至数据库):

1.当应用程序调用org.hibernate.Transaction的commit()方法的时候,commit()方法先清理缓存(通过自动调用session.flush),然后再向  

数据库提交事务。
2.当应用程序显式调用Session的flush()方法的时候,其实这个方法我们几乎很少用到,因为我们一般都是在完成一个事务才去清理缓存,提交数

据更改,这样我们直接提交事务就可以。

 6.1.3.2 支持一级缓存的方法

* get()

使用例子

 Student s = (Student)session.get(Student.class, 1);
System.out.println(s.getName());
System.out.println("---------------------");
s = (Student)session.load(Student.class, 1);
System.out.println(s.getName());

跟1中load一样,只发出一条sql语句。

* load()

使用例子

 Student student = (Student)session.createQuery("from Student s where s.id=1").iterate().next();
System.out.println("student.name=" + student.getName()); //会发出查询id的sql,不会发出查询实体对象的sql,因为iterate使用缓存
student = (Student)session.createQuery("from Student s where s.id=1").iterate().next();
System.out.println("student.name=" + student.getName());

* iterate(查询实体对象)

iterate方法只对实体对象查询才支持一级缓存,如果使用iterate来查询对象里面的相关属性,则查询的时候不支持一级缓存。

 String name = (String)session.createQuery("select s.name from Student s where s.id=1").iterate().next();
System.out.println("student.name=" + name); //iterate查询普通属性,一级缓存不会缓存,所以发出sql
//一级缓存是缓存实体对象的
name = (String)session.createQuery("select s.name from Student s where s.id=1").iterate().next();
System.out.println("student.name=" + name);

由于iterate()方法查询实体对象属性,一级缓存不会产生作用,所以发出两条sql语句。

 6.1.3.3 如何手动干预,管理一级缓存

*session.flush()

在hibernate中也存在flush这个功能,在默认的情况下session.commit()之前时,其实执行了一个flush命令。

Session.flush功能:

①   清理缓存;

②   执行sql(确定是执行SQL语句(确定生成update、insert、delete语句等),然后执行SQL语句。)

*session.clear()

  无论是Load 还是 Get 都会首先查找缓存(一级缓存) 如果没有,才会去数据库查找,调用Clear() 方法,可以强制清除Session缓存(不管缓存与数据库的同步)

*session.evict()

  将某个对象从hibernate  session剔除,使该对象成为游离态。该对象之后的变更不会同步至DB,而evict之前对象的变化在事务提交时仍

将影响DB。

 6.1.3.4 大批量处理

在进行大批量数据一次性更新的时候,会占用非常多的内存来缓存被更新的对象。这时就应该阶段性地调用clear()方法来清空一级缓存中的对象,控制一级缓存的大小,以避免产生内存溢出的情况。
Hibernate大批量更新时缓存的处理方法:

* 先flush,再clear

 for(int i=0;i<10000;i++)
{
Student s = new Student();
s.setName("s"+i);
session.save(s);
if(i%20==0)
{
session.flush();
session.clear();
}
}

在数据量比较大的情况下管理一级缓存的做法,一般都是设定一定数量的记录给更新或者保存等操作之后,避免一次性大量的实体数据入库导致内存溢出,所以才去先是用第8行的flush和第9行的clear方法来实现比较好的缓存管理。这里

在数据量特别大的时候,可以使用jdbc来实现,因为hibernate不太适合于数据量特别大的场合使用,如果连jdbc都满足不了数据量的效率要求,只好利用相关的数据库机制来实现。

如果数据量特别大,考虑采用jdbc实现,如果jdbc也不能满足要求可以考虑采用数据本身的特定导入工具。

以下跳过Hibernate API  而直接通过JDBC API来执行:

 Session session=SessionFactory.openSession();
Transaction tx =session.beginTransaction();
Connection conn =session.connection();
PreparedStatement pstmt = conn.prepareStatement("update users set age=age+1 "+"where age >0");
pstmt.executeUpdate();
tx.commit();

虽说这是通过JDBC API.但本质上还是通过Hibernater Transaction的事务这个接口来声明事务的边界的...

其实最好的解决方法就是以创建存储过程,用底层的数据库运行..这样性能好,速度快....

我就简单的以Oracle数据库为例子.创建一个名为UserUpdate的存储过程...然后在程序中进行调用...

 UserUpdate的存储过程代码:
create or replace procadure UserUpdate(u_age in number) as
begin update users set age=age+1 where age>u_age;
end;

下面的是在程序中如何调用我们命名的存储过程

 Session session =SessionFactory.openSession();
Transaction tx =session.beginTransaction();
Connection conn=session.connection();
String str="{call UserUpdate(?)}";
CallableStatement cstmt= conn.prepareCall(str);
cstmt.setInt(1,0);
cstmt.executeUpdate();
tx.commit();

注意.开源的MySQL中不支持存储过程的..
用JDBC API的好处是这样的..
它不用把大批量的数据事先加载到内存中,然后再进行更新与修改..所以不会消耗大量内存....
(小程序中是看不出什么差别的..当数据的记录达到一定的数据量的时候自然会发现用Hibernate API 与JDBC API的差别)
在一个就是只能一条记录进行批量更新..不像Hibernate中更新每一条的..


Hibernate3回顾-6-hibernate缓存(性能优化策略)的更多相关文章

  1. 028hibernate缓存(性能优化策略)

    一级缓存 二级缓存 查询缓存 缓存是为了提高性能 变化不是很大,相对静态的对象放入缓存 对象的创建比较耗时

  2. 常见性能优化策略的总结 good

    阅读目录 代码 数据库 缓存 异步 NoSQL JVM调优 多线程与分布式 度量系统(监控.报警.服务依赖管理) 案例一:商家与控制区关系的刷新job 案例二:POI缓存设计与实现 案例三:业务运营后 ...

  3. c++ 性能优化策略

    c++ 性能优化策略 作者:D_Guco 来源:CSDN 原文:https://blog.csdn.net/D_Guco/article/details/75729259 1 关于继承:不可否认良好的 ...

  4. 52 条 SQL 语句性能优化策略,建议收藏

    本文会提到 52 条 SQL 语句性能优化策略. 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在where及order by涉及的列上建立索引. 2.应尽量避免在where子句中对字段进行nul ...

  5. 90 % Java 程序员被误导的一个性能优化策略

    我们经常看到一些 Java 性能优化的书或者理念,说不要在循环内定义变量,这样会占用过多的内存影响性能,而要在循环外面定义.接触 Java 这么久以来,相信很多 Java 程序员都被这种代码性能优化策 ...

  6. 在 Android开发中,性能优化策略十分重要

    在 Android开发中,性能优化策略十分重要本文主要讲解性能优化中的布局优化,希望你们会喜欢.目录 示意图 1. 影响的性能 布局性能的好坏 主要影响 :Android应用中的页面显示速度 2. 如 ...

  7. Spring/Hibernate 应用性能优化的7种方法

    对于大多数典型的 Spring/Hibernate 企业应用而言,其性能表现几乎完全依赖于持久层的性能.此篇文章中将介绍如何确认应用是否受数据库约束,同时介绍七种常用的提高应用性能的速成法.本文系 O ...

  8. Hibernate查询以及优化策略04

    一. HQL查询 1. HQL(hibernate query language)单表查询 1.1 准备项目 创建项目: hinernate-03-query 引入jar,同前一个项目 复制实体(订单 ...

  9. Hibernate缓存原理与策略

    Hibernate缓存原理: 对于Hibernate这类ORM而言,缓存显的尤为重要,它是持久层性能提升的关键.简单来讲Hibernate就是对JDBC进行封装,以实现内部状态的管理,OR关系的映射等 ...

随机推荐

  1. for else

  2. js 中对字符串操作的函数

    concat() – 将两个或多个字符的文本组合起来,返回一个新的字符串. indexOf() – 返回字符串中一个子串第一处出现的索引.如果没有匹配项,返回 -1 . charAt() – 返回指定 ...

  3. Core Java Volume I — 5.1. Classes, Superclasses, and Subclasses

    5.1. Classes, Superclasses, and SubclassesLet's return to the Employee class that we discussed in th ...

  4. hdu 3666 Making the Grade

    题目大意 给出了一列数,要求通过修改某些值,使得最终这列数变成有序的序列,非增或者非减的,求最小的修改量. 分析 首先我们会发现,最终修改后,或者和前一个数字一样,或者和后一个数字一样,这样才能修改量 ...

  5. 光流算法:Brox算法(转载)

    参考论文:1. High Accuracy Optical Flow Estimation Based on a Theory for Warping, Thomas Box, ECCV20042. ...

  6. 装载: Matlab 提取矩阵 某一行 或者 某一列 的方法

    比如,从一个6*6矩阵中,提取它的第一行元素,形成一个6维行向量. A(i,:)行  A(:,i)列 方法: A(i,:) 提取矩阵A的第 i行 A(:,i) 提取矩阵A的第 i列   给你个例子: ...

  7. mybatis+spring的简单介绍学习

    参考下面链接 http://mybatis.github.io/spring/zh/index.html

  8. leetcode 148. Sort List ----- java

    Sort a linked list in O(n log n) time using constant space complexity. 排序,要求是O(nlog(n))的时间复杂度和常数的空间复 ...

  9. Web服务器IPtables配置

    #允许SSH流量(重要) iptables -A INPUT -p tcp --dport 22 -j ACCEPT iptables -A INPUT -p tcp --dport 222 -j A ...

  10. linux下删除所有.svn目录

    linux下删除所有.svn目录方法为    find . -type d -name ".svn"|xargs rm -rf    或者    find . -type d -i ...