hibernate......1、2级缓存
1.什么是缓存?
缓存是介于物理数据源与应用程序之间,是对数据库中的数据复制一份临时放在内存中的容器,其作用是为了减少应用程序对物理数据源访问的次数,从而提高了应用程序的运行性能。Hibernate在进行读取数据的时候,根据缓存机制在相应的缓存中查询,如果在缓存中找到了需要的数据(我们把这称做“缓存命 中"),则就直接把命中的数据作为结果加以利用,避免了大量发送SQL语句到数据库查询的性能损耗。
缓存策略提供商:
提供了HashTable缓存,EHCache,OSCache,SwarmCache,jBoss Cathe2,这些缓存机制,其中EHCache,OSCache是不能用于集群环境(Cluster Safe)的,而SwarmCache,jBoss Cathe2是可以的。HashTable缓存主要是用来测试的,只能把对象放在内存中,EHCache,OSCache可以把对象放在内存(memory)中,也可以把对象放在硬盘(disk)上(为什么放到硬盘上?上面解释了)。
Hibernate缓存分类:
一、Session缓存(又称作事务缓存):Hibernate内置的,不能卸除。
缓存范围:缓存只能被当前Session对象访问。缓存的生命周期依赖于Session的生命周期,当Session被关闭后,缓存也就结束生命周期。
二、SessionFactory缓存(又称作应用缓存):使用第三方插件,可插拔。
缓存范围:缓存被应用范围内的所有session共享,不同的Session可以共享。这些session有可能是并发访问缓存,因此必须对缓存进行更新。缓存的生命周期依赖于应用的生命周期,应用结束时,缓存也就结束了生命周期,二级缓存存在于应用程序范围。
一级缓存:
Hibernate一些与一级缓存相关的操作(时间点):
数据放入缓存:
1. save()。当session对象调用save()方法保存一个对象后,该对象会被放入到session的缓存中。
2. get()和load()。当session对象调用get()或load()方法从数据库取出一个对象后,该对象也会被放入到session的缓存中。
3. 使用HQL和QBC等从数据库中查询数据。
例如:数据库有一张表如下:
使用get()或load()证明缓存的存在:
public class Client
{ public static void main(String[] args)
{
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = null; try
{ /*开启一个事务*/
tx = session.beginTransaction(); /*从数据库中获取id="402881e534fa5a440134fa5a45340002"的Customer对象*/
Customer customer1 = (Customer)session.get(Customer.class, "402881e534fa5a440134fa5a45340002");
System.out.println("customer.getUsername is"+customer1.getUsername()); /*事务提交*/
tx.commit();
System.out.println("-------------------------------------");
/*开启一个新事务*/
tx = session.beginTransaction(); /*从数据库中获取id="402881e534fa5a440134fa5a45340002"的Customer对象*/
Customer customer2 = (Customer)session.get(Customer.class, "402881e534fa5a440134fa5a45340002");
System.out.println("customer2.getUsername is"+customer2.getUsername()); /*事务提交*/
tx.commit();
System.out.println("-------------------------------------");
/*比较两个get()方法获取的对象是否是同一个对象*/
System.out.println("customer1 == customer2 result is "+(customer1==customer2));
} catch (Exception e)
{ if(tx!=null)
{
tx.rollback();
}
} finally
{
session.close();
}
}
}
程序控制台输出结果:
Hibernate:
select
customer0_.id as id0_0_,
customer0_.username as username0_0_,
customer0_.balance as balance0_0_
from
customer customer0_
where
customer0_.id=?
customer.getUsername islisi
-------------------------------------
customer2.getUsername islisi
-------------------------------------
customer1 == customer2 result is true
其原理是:在同一个Session里面,第一次调用get()方法, Hibernate先检索缓存中是否有该查找对象,发现没有,Hibernate发送SELECT语句到数据库中取出相应的对象,然后将该对象放入缓存中,以便下次使用,第二次调用get()方法,Hibernate先检索缓存中是否有该查找对象,发现正好有该查找对象,就从缓存中取出来,不再去数据库中检索,没有再次发送select语句。
数据从缓存中清除:
1. evit()将指定的持久化对象从缓存中清除,释放对象所占用的内存资源,指定对象从持久化状态变为脱管状态,从而成为游离对象。
2. clear()将缓存中的所有持久化对象清除,释放其占用的内存资源。
其他缓存操作:
1. contains()判断指定的对象是否存在于缓存中。
2. flush()刷新缓存区的内容,使之与数据库数据保持同步。
二级缓存:
@Testpublic void testCache2() {
Session session1 = sf.openSession();//获得Session1session1.beginTransaction();
Category c = (Category)session1.load(Category.class, 1);
System.out.println(c.getName());
session1.getTransaction().commit();
session1.close();
Session session2 = sf.openSession();//获得Session2session2.beginTransaction();
Category c2 = (Category)session2.load(Category.class, 1);
System.out.println(c2.getName());
session2.getTransaction().commit();
session2.close();
}
当我们重启一个Session,第二次调用load或者get方法检索同一个对象的时候会重新查找数据库,会发select语句信息。
原因:一个session不能取另一个session中的缓存。
性能上的问题:假如是多线程同时去取Category这个对象,load一个对象,这个对像本来可以放到内存中的,可是由于是多线程,是分布在不同的session当中的,所以每次都要从数据库中取,这样会带来查询性能较低的问题。
解决方案:使用二级缓存。
1.什么是二级缓存?
SessionFactory级别的缓存,可以跨越Session存在,可以被多个Session所共享。
2.适合放到二级缓存中:
(1)经常被访问
(2)改动不大
(3)数量有限
(4)不是很重要的数据,允许出现偶尔并发的数据。
这样的数据非常适合放到二级缓存中的。
用户的权限:用户的数量不大,权限不多,不会经常被改动,经常被访问。
例如组织机构。
思考:什么样的类,里面的对象才适合放到二级缓存中?
改动频繁,类里面对象特别多,BBS好多帖子,这些帖子20000多条,哪些放到缓存中,不能确定。除非你确定有一些经常被访问的,数据量并不大,改动非常少,这样的数据非常适合放到二级缓存中的。
3.二级缓存实现原理:
Hibernate如何将数据库中的数据放入到二级缓存中?注意,你可以把缓存看做是一个Map对象,它的Key用于存储对象OID,Value用于存储POJO。首先,当我们使用Hibernate从数据库中查询出数据,获取检索的数据后,Hibernate将检索出来的对象的OID放入缓存中key 中,然后将具体的POJO放入value中,等待下一次再次向数据查询数据时,Hibernate根据你提供的OID先检索一级缓存,若有且配置了二级缓存,则检索二级缓存,如果还没有则才向数据库发送SQL语句,然后将查询出来的对象放入缓存中。
4.使用二级缓存
(1)打开二级缓存:
为Hibernate配置二级缓存:
在主配置文件中hibernate.cfg.xml :
<!-- 使用二级缓存 -->
<!-- 使用二级缓存 -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<!--设置缓存的类型,设置缓存的提供商-->
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
或者当hibernate与Spring整合后直接配到Spring配置文件applicationContext.xml中
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>com/lp/ecjtu/model/Employee.hbm.xml</value>
<value>com/lp/ecjtu/model/Department.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.OracleDialect
hibernate.hbm2ddl.auto=update
hibernate.show_sql=true
hibernate.format_sql=true
hibernate.cache.use_second_level_cache=true
hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider
hibernate.generate_statistics=true
</value>
</property>
</bean>
(2)配置ehcache.xml
<?xml version="1.0" encoding="UTF-8"?><ehcache>
<!--
缓存到硬盘的路径 -->
<diskStore path="d:/ehcache"></diskStore>
<!--
默认设置
maxElementsInMemory : 在內存中最大緩存的对象数量。
eternal : 缓存的对象是否永远不变。
timeToIdleSeconds :可以操作对象的时间。
timeToLiveSeconds :缓存中对象的生命周期,时间到后查询数据会从数据库中读取。
overflowToDisk :内存满了,是否要缓存到硬盘。 -->
<defaultCache maxElementsInMemory="200" eternal="false"
timeToIdleSeconds="50" timeToLiveSeconds="60" overflowToDisk="true"></defaultCache>
<!--
指定缓存的对象。
下面出现的的属性覆盖上面出现的,没出现的继承上面的。 -->
<cache name="com.suxiaolei.hibernate.pojos.Order" maxElementsInMemory="200" eternal="false"
timeToIdleSeconds="50" timeToLiveSeconds="60" overflowToDisk="true"></cache></ehcache>
(3)使用二级缓存需要在实体类中加入注解:
需要ehcache-1.2.3.jar包:
还需要 commons_loging1.1.1.jar包
在实体类中通过注解可以配置实用二级缓存:
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
Load默认使用二级缓存,就是当查一个对象的时候,它先会去二级缓存里面去找,如果找到了就不去数据库中查了。
Iterator默认的也会使用二级缓存,有的话就不去数据库里面查了,不发送select语句了。
List默认的往二级缓存中加数据,假如有一个query,把数据拿出来之后会放到二级缓存,但是执行查询的时候不会到二级缓存中查,会在数据库中查。原因每个query中查询条件不一样。
(4)也可以在需要被缓存的对象中hbm文件中的<class>标签下添加一个<cache>子标签:
<hibernate-mapping>
<class name="com.suxiaolei.hibernate.pojos.Order" table="orders">
<cache usage="read-only"/>
<id name="id" type="string">
<column name="id"></column>
<generator class="uuid"></generator>
</id>
<property name="orderNumber" column="orderNumber" type="string"></property>
<property name="cost" column="cost" type="integer"></property>
<many-to-one name="customer" class="com.suxiaolei.hibernate.pojos.Customer"
column="customer_id" cascade="save-update">
</many-to-one>
</class>
</hibernate-mapping>
存在一对多的关系,想要在在获取一方的时候将关联的多方缓存起来,需要再集合属性下添加<cache>子标签,这里需要将关联的对象的 hbm文件中必须在存在<class>标签下也添加<cache>标签,不然Hibernate只会缓存OID。
<hibernate-mapping>
<class name="com.suxiaolei.hibernate.pojos.Customer" table="customer">
<!-- 主键设置 -->
<id name="id" type="string">
<column name="id"></column>
<generator class="uuid"></generator>
</id>
<!-- 属性设置 -->
<property name="username" column="username" type="string"></property>
<property name="balance" column="balance" type="integer"></property>
<set name="orders" inverse="true" cascade="all" lazy="false" fetch="join">
<cache usage="read-only"/>
<key column="customer_id" ></key>
<one-to-many class="com.suxiaolei.hibernate.pojos.Order"/>
</set>
</class>
</hibernate-mapping>
hibernate......1、2级缓存的更多相关文章
- Hibernate的一级二级缓存机制配置与测试
特别感谢http://www.cnblogs.com/xiaoluo501395377/p/3377604.html 在本篇随笔里将会分析一下hibernate的缓存机制,包括一级缓存(session ...
- Hibernate中延迟加载和缓存
什么是延迟加载? 延迟加载是指当应用程序想要从数据库获取对象时(在没有设置lazy属性值为false),Hibernate只是从数据库获取符合条件的对象的OId从而生成代理对象,并没有加载出对象 访问 ...
- Hibernate-一级缓存session
hibernate提供的一级缓存 hibernate是一个线程对应一个session,一个线程可以看成一个用户.也就是说session级缓存(一级缓存)只能给一个线程用,别的线程用不了,一级缓存就是和 ...
- Hibernate学习笔记--------3.缓存
一.一级缓存 一级缓存又称为“Session缓存”或者“会话级缓存”,通过Session从数据库查询实体时,会把实体在内存中存储起来,下一次查询同一实体时不再再次执行sql语句查询数据库,而是从内存中 ...
- Hibernate的三种缓存
一级缓存 hibernate的一级缓存是跟session绑定的,那么一级缓存的生命周期与session的生命周期一致,因此,一级缓存也叫session级缓存或者事务级缓存. 支持一级缓存的方法有: q ...
- Spring 整合 Hibernate 时启用二级缓存实例详解
写在前面: 1. 本例使用 Hibernate3 + Spring3: 2. 本例的查询使用了 HibernateTemplate: 1. 导入 ehcache-x.x.x.jar 包: 2. 在 a ...
- Hibernate 二(一级缓存,多表设计之一对多)
1 对象状态与一级缓存 1.1 状态介绍 l hibernate 规定三种状态:瞬时态.持久态.脱管态 l 状态 瞬时态:transient,session没有缓存对象,数据库也没 ...
- Hibernate三种状态,缓存,以及update更新问题
一. Hibernate中对象的三种状态 1. 瞬时状态(transient) 当我们通过Java的new关键字来生成一个实体对象时,这时这个实体对象就处于自由状态,此时该对象只是通过JVM获得了一块 ...
- Hibernate中 一 二级缓存及查询缓存(1)
最近趁有空学习了一下Hibernate的缓存,其包括一级缓存,二级缓存和查询缓存(有些是参照网络资源的): 一.一级缓存 一级缓存的生命周期和session的生命周期一致,当前sessioin ...
随机推荐
- js的浅拷贝和深拷贝
转载:http://www.jb51.net/article/91906.htm //深拷贝,并且把合并后的值放到第二个参数里 function deepCopy(p, c) { var c = c ...
- Windows7 x64配置 Apache2 + PHP5 + MySQL5
1:相关软件下载: Apache HTTP Server 版本:(httpd-2.2.25-win32-x86-openssl-0.9.8y) PHP ...
- 1018Mysql分表分库
单库单表 单库单表是最常见的数据库设计,例如,有一张用户(user)表放在数据库db中,所有的用户都可以在db库中的user表中查到. 单库多表 随着用户数量的增加,user表的数据量会越来越大,当数 ...
- 使用jsp/servlet简单实现文件上传与下载
使用JSP/Servlet简单实现文件上传与下载 通过学习黑马jsp教学视频,我学会了使用jsp与servlet简单地实现web的文件的上传与下载,首先感谢黑马.好了,下面来简单了解如何通过使用 ...
- 【POJ 3415】Common Substrings 长度不小于k的公共子串的个数
长度不小于k的公共子串的个数,论文里有题解,卡了一上午,因为sum没开long long!!! 没开long long毁一生again--- 以后应该早看POJ里的Discuss啊QAQ #inclu ...
- java环境变量设置
java环境变量设置 1.打开我的电脑--属性--高级--环境变量 2.新建系统变量JAVA_HOME 和CLASSPATH 变量名:JAVA_HOME 变量值:C:\Program Files\Ja ...
- lucene-查询query->PrefixQuery使用前缀搜索
PrefixQuery就是使用前缀来进行查找的.通常情况下,首先定义一个词条Term.该词条包含要查找的字段名以及关键字的前缀,然后通过该词条构造一个PrefixQuery对象,就可以进行前缀查找了. ...
- java基础1.0::Java面向对象、面向对象封装、抽象类、接口、static、final
一.前言 一直以来都是拿来主义,向大神学习,从网上找资料,现在就把自己在工作中和学习中的所理解的知识点写出来,好记星不如烂笔头,一来可以作为笔记自己温习,二来也可以给走在求学之路的同学们一点参考意见, ...
- C#-WinForm-公共控件的基本属性及练习
视图→工具箱 基本操作:控件的取值.赋值.改值.事件 1.Button --按钮 AutoSize-指示该控件是否自动调整自身的大小以适应其内容的大小. 默认False,此时文字内容超过其宽度时自动 ...
- BuiltWith
BuiltWith网站技术信息查询工具 利用该网站所提供的功能,你可以查询出某网站背后是由哪些技术来支持的, 比如操作系统的类型.所采用的访问量统计服务.采用的发布平台.广告平台.语言框架.聚合功能. ...