hibernate缓存.docx

上传人:b****7 文档编号:16461461 上传时间:2023-07-13 格式:DOCX 页数:23 大小:247.92KB
下载 相关 举报
hibernate缓存.docx_第1页
第1页 / 共23页
hibernate缓存.docx_第2页
第2页 / 共23页
hibernate缓存.docx_第3页
第3页 / 共23页
hibernate缓存.docx_第4页
第4页 / 共23页
hibernate缓存.docx_第5页
第5页 / 共23页
hibernate缓存.docx_第6页
第6页 / 共23页
hibernate缓存.docx_第7页
第7页 / 共23页
hibernate缓存.docx_第8页
第8页 / 共23页
hibernate缓存.docx_第9页
第9页 / 共23页
hibernate缓存.docx_第10页
第10页 / 共23页
hibernate缓存.docx_第11页
第11页 / 共23页
hibernate缓存.docx_第12页
第12页 / 共23页
hibernate缓存.docx_第13页
第13页 / 共23页
hibernate缓存.docx_第14页
第14页 / 共23页
hibernate缓存.docx_第15页
第15页 / 共23页
hibernate缓存.docx_第16页
第16页 / 共23页
hibernate缓存.docx_第17页
第17页 / 共23页
hibernate缓存.docx_第18页
第18页 / 共23页
hibernate缓存.docx_第19页
第19页 / 共23页
hibernate缓存.docx_第20页
第20页 / 共23页
亲,该文档总共23页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

hibernate缓存.docx

《hibernate缓存.docx》由会员分享,可在线阅读,更多相关《hibernate缓存.docx(23页珍藏版)》请在冰点文库上搜索。

hibernate缓存.docx

hibernate缓存

hibernate缓存

缓存:

在word中敲入一些字符...;在线视频网站;

一、Session级缓存(一级缓存)

1.一级缓存很短和session的生命周期一致,因此也叫session级缓存或事务级缓存

2.支持一级缓存的方法get()load()iterate()(查询实体对象)

publicvoidqueryNewsIterate(){

session.beginTransaction();

Queryquery=session.createQuery("fromNewsnwheren.newsId<=5");

Iteratoritor=query.iterate();//一个一个遍历实体对象

while(itor.hasNext()){

Newsnews=itor.next();

System.out.println(news.getNewsTitle()+",是"

+news.getNt().getTypeName()+"类型的.");

}

System.out.println("*******************");

query=session.createQuery("fromNewsnwheren.newsId<=5");

itor=query.iterate();//一个一个遍历实体对象

while(itor.hasNext()){

Newsnews=itor.next();

System.out.println(news.getNewsTitle()+",是"

+news.getNt().getTypeName()+"类型的.");

}

//query.list();//放在一个集合

session.getTransaction().commit();

}

3.Session缓存是实体级别的缓存,就是只有在查询对象级别的时候才使用,如果使用HQL和SQL是查询属性级别的,是不使用一级缓存的

4.管理一级缓存:

session.clear(),session.evict()

5.如何避免一次性大量的实体数据入库导致内存溢出先flush,再clear

一级缓存的管理:

1、在进行大批量数据一次性插入的时候:

publicvoidSaveAccount(){

session.beginTransaction();

for(inti=1;i<5000;i++){

Accounta=newAccount();

a.setName("测试账户"+i);

a.setCount(i+1);

session.save(a);

//在这里定时根据特定的条件将缓存中的对象清除

if(i%20==0)

{

session.flush();

session.clear();

}

}

session.getTransaction().commit();

}

2、在进行大批量数据一次性更新的时候,会占用非常多的内存来缓存被更新的对象。

这时就应该阶段性地调用clear()方法来清空一级缓存中的对象,控制一级缓存的大小,以避免产生内存溢出的情况.

思考如下问题:

我们想批量修改Student表中的学生的年龄,如每人加1:

?

 

解决方案:

1、先进行flush();clear();evict();

2、用原始的jdbc代码去操作:

批量执行相同相似的sql语句的方法:

Update表set列=?

whereid=?

Insert....

@Test

publicvoidSaveAccountJdbc(){

try{

Class.forName("");

java.sql.Connectionconn=DriverManager.getConnection("");

conn.setAutoCommit(false);

java.sql.PreparedStatementpstmt=conn.prepareStatement("insertintoaccount(name,count)values(?

?

)");

for(inti=1;i<5000;i++){

Accounta=newAccount();

a.setName("测试账户"+i);

a.setCount(i+1);

pstmt.setString(1,a.getName());

pstmt.setInt(2,a.getCount());

pstmt.addBatch();

}

pstmt.executeBatch();

mit();

}catch(ClassNotFoundExceptione){

//TODOAuto-generatedcatchblock

e.printStackTrace();

}catch(SQLExceptione){

//TODOAuto-generatedcatchblock

e.printStackTrace();

}

}

二、二级缓存

1.二级缓存也称为进程级的缓存,也可称为SessionFactory级的缓存(因为SessionFactory可以管理二级缓存),它与session级缓存不一样,一级缓存只要session关闭缓存就不存在了。

而二级缓存则只要进程在二级缓存就可用。

2.二级缓存可以被所有的session共享

3.二级缓存的生命周期和SessionFactory的生命周期一样,SessionFactory可以管理二级缓存

4.二级缓存同session级缓存一样,只缓存实体对象,普通属性的查询不会缓存

5.二级缓存一般使用第三方的产品,如EhCache

6.二级缓存的配置和使用:

需要加入外部jar包:

commons-logging-1.1.3.jar

ehcache-1.2.3.jar

配置二级缓存的配置文件:

模板文件位于hibernate\etc目录下(如ehcache.xml),将模板存放在ClassPath目录中,一般放在根目录下(src目录下)

--设置当缓存对象益出时,对象保存到磁盘时的保存路径。

   如 d:

\xxxx

Thefollowingpropertiesaretranslated:

user.home-User'shomedirectory

user.dir-User'scurrentworkingdirectory

java.io.tmpdir-windows的临时目录-->

--默认配置/或对某一个类进行管理

maxInMemory-缓存中可以存入的最多个对象数

eternal-true:

表示永不失效,false:

不是永久有效的。

timeToIdleSeconds-空闲时间,当第一次访问后在空闲时间内没有访问,则对象失效,单位为秒

timeToLiveSeconds-被缓存的对象有效的生命时间,单位为秒

overflowToDisk当缓存中对象数超过核定数(益出时)时,对象是否保存到磁盘上。

true:

保存;false:

不保存

如果保存,则保存路径在标签中属性path指定

-->

maxElementsInMemory="10000"

eternal="false"

timeToIdleSeconds="120"

timeToLiveSeconds="120"

overflowToDisk="true"

/>

开启二级缓存并指定提供商:

--开启二级缓存,hibernate默认的二级缓存就是开启的-->

true

--指定二级缓存提供商-->

org.hibernate.cache.EhCacheProvider

以下为常见缓存提供商:

Cache

Providerclass

Type

ClusterSafe

QueryCacheSupported

Hashtable(notintendedforproductionuse)

org.hibernate.cache.HashtableCacheProvider

memory

 

yes

EHCache

org.hibernate.cache.EhCacheProvider

memory,disk

 

yes

OSCache

org.hibernate.cache.OSCacheProvider

memory,disk

 

yes

SwarmCache

org.hibernate.cache.SwarmCacheProvider

clustered(ipmulticast)

yes(clusteredinvalidation)

 

JBossTreeCache

org.hibernate.cache.TreeCacheProvider

clustered(ipmulticast),transactional

yes(replication)

yes(clocksyncreq.)

使用二级缓存

a)xml方式:

指定哪些实体类使用二级缓存:

在实体类映射文件中,使用来指定那个实体类使用二级缓存,如下:

usage="transactional|read-write|nonstrict-read-write|read-only"

(1)

region="RegionName"

(2)

include="all|non-lazy"(3)

/>

(1)usage(必须)说明了缓存的策略:

transactional、read-write、nonstrict-read-write或read-only。

(2)region(可选,默认为类或者集合的名字(classorcollectionrolename))指定第二级缓存的区域名(nameofthesecondlevelcacheregion)

(3)include(可选,默认为all)non-lazy当属性级延迟抓取打开时,标记为lazy="true"的实体的属性可能无法被缓存

这里的usage属性指明了缓存并发策略(cacheconcurrencystrategy)。

修改对应的的映射文件:

--指定实体类使用二级缓存 -->

方法二:

在hibernate配置文件(hibernate.cfg.xml)使用标签中指定

要求:

标签必须放在标签之后。

…………

 

2、二级缓存的管理:

1、清除指定实体类的所有数据

SessionFactory.evict(Student.class);

2、清除指定实体类的指定对象

SessionFactory.evict(Student.class,1);

测试类:

publicvoidqueryAccount(){

Sessionsession=sf.getCurrentSession();

session.beginTransaction();

System.out.println("*******session********");

Accountaccount=(Account)session.get(Account.class,1);

System.out.println(account.getName());

System.out.println("*******session1********");

session.getTransaction().commit();

//sf.evict(Account.class);

Sessionsession1=sf.getCurrentSession();

session1.beginTransaction();

Accountaccount1=(Account)session1.get(Account.class,1);

System.out.println(account1.getName());

session1.getTransaction().commit();

}

控制台的输出结果:

*******session********

Hibernate:

selectaccount0_.idasid0_0_,account0_.nameasname0_0_,account0_.countascount0_0_fromAccountaccount0_whereaccount0_.id=?

测试账户1

*******session1********

测试账户1

 

三、查询缓存

查询缓存,是用于缓存普通属性查询的,当查询实体时缓存实体ID。

查询缓存,对list/iterator这样的操作会起作用。

默认是关闭的。

具体来说:

即让hibernate缓存list、iterator、createQuery等方法的查询结果集。

如果没有打开查询缓存,hibernate将只缓存load方法获得的单个持久化对象。

在打开了查询缓存之后,需要注意,调用query.list()操作之前,必须显式调用query.setCachable(true)来标识某个查询使用缓存。

查询缓存依赖于二级缓存,因为使用查询缓存需要打开二级缓存,查询缓存的生命周期:

当前关联的表发生修改,那么查询缓存生命周期结束.

查询缓存的配置和使用:

在hibernate.cfg.xml文件中启用查询缓存

true

在程序中必须手动启用查询缓存

query.setCacheable(true);

查询缓存的测试代码:

@Test

publicvoidqueryAccount(){

Sessionsession=sf.getCurrentSession();

session.beginTransaction();

Queryquery=session.createQuery("fromAccountawherea.id<=10");

query.setCacheable(true);

Listlist=query.list();

for(Accounta:

list){

System.out.println(a.getName());

}

System.out.println("***************");

query=session.createQuery("fromAccountawherea.id<=10");

query.setCacheable(true);

list=query.list();

for(Accounta:

list){

System.out.println(a.getName());

}

session.getTransaction().commit();

}

事务并发处理

为了得到更好的运行性能,各种数据库都允许多个事务同时运行,这就是事务并发。

当并发的事务访问或修改数据库中相同的数据时,通常需要采取必要的隔离机制,反之会出现各种并发问题,常见的并发问题:

脏读:

没有提交就可以读取到数据称为脏读

不可重复读:

再重复读一次,数据与你上的不一样。

称不可重复读。

幻读:

在查询某一条件的数据,开始查询的后,别人又加入或删除些数据,再读取时与原来的数据不一样了。

具体问题简单解释如下:

数据的读取的问题:

更新有关的问题:

解决并发问题的方式是:

采取有效的隔离机制。

怎样实现事务的隔离呢?

隔离机制的实现必须使用锁,下面是锁的基本原理:

a.当一个事务访问某个数据库资源时,如果执行的是select语句,必须为资源加上共享锁,如果执行的是insert,update,delete语句,必须为资源加上排他锁,这些锁锁定正在被操作的资源。

b.当第二个事务也要访问相同的资源时,如果执行的select语句,那么也必须为资源加上共享锁;如果执行的是insert,update,或delete语句,也必须为资源加上排他锁。

但此时第二个事务并非就立即能为资源加上锁,当第一个事务为资源加的是共享锁时,第二个事务能够为资源加上共享锁,但当第一个事务为资源加的是排他锁时,第二个事务必须等待第一个事务结束,才能为资源加上排他锁。

上面已经引出了,共享锁,排他锁。

下面来阐述一下锁的种类及概念。

1.共享锁

共享锁用于读取数据操作,它允许其他事务同时读取锁定的资源,但不允许其他事务更新它。

2.排他锁

排他锁用于修改数据的场合,他锁定的资源,其他事务部能读取也不能修改。

3.更新锁

更新锁在更新操作初始化截断用来锁定可能要被修改的资源,从而避免使用共享锁造成的死锁现象。

锁机制能有效地解决并发事务时的各种问题,但是也会影响到并发的性能。

数据库系统提供了4种可选的事务隔离级别

1.ReadUncommited(未提交读):

没有提交就可以读取到数据(发出了Insert,但没有commit就可以读取到。

)很少用

1、ReadCommited(提交读):

只有提交后才可以读,常用,

2、RepeatableRead(可重复读):

mysql默认级别,必需提交才能见到,读取数据时数据被锁住。

3、Serialiazble(序列化读):

最高隔离级别,串型的,你操作完了,我才可以操作,并发性特别不好,

隔离级别

是否存在脏读

是否存在不可重复读

是否存在幻读

ReadUncommitted(未提交读)

Y

Y

Y

ReadCommited(提交读)

N

Y(可采用悲观锁解决)

Y

RepeatableRead(可重复读)

N

N

Y

Serialiazble(序列化读)

 

1、Mysql查看数据库隔离级别:

方法:

select@@tx_isolation;

2、Mysql数据库修改隔离级别:

方法:

settransactionisolationlevel隔离级别名称;

例如:

修改为未提交读:

settransactionisolationlevelreaduncommitted;

悲观锁、乐观锁

Hibernate谈到悲观锁、乐观锁,就要谈到数据库的并发问题,数据库的隔离级别越高它的并发性就越差

并发性:

当前系统进行了序列化后,当前读取数据后,别人查询不了,看不了。

称为并发性不好.

一、悲观锁

悲观锁:

具有排他性(我锁住当前数据后,别人看到不此数据)

悲观锁一般由数据机制来做到的。

1、悲观锁的实现

通常依赖于数据库机制,在整修过程中将数据锁定,其它任何用户都不能读取或修改(如:

必需我修改完之后,别人才可以修改)

2、悲观锁的适用场景:

悲观锁一般适合短事务比较多(如某一数据取出后加1,立即释放)

长事务占有时间(如果占有1个小时,那么这个1小时别人就不可以使用这些数据),不常用。

3、实例:

数据库中的原始数据是1000.

用户1、用户2 同时读取到数据,但是用户2先 -200,这时数据库里的是800,现在用户1也开始-200,可是用户1刚才读取到的数据是1000,现在用户用刚刚一开始读取的数据1000-200为800,而用户1在更新时数据库里的是更新的数据800,按理说用户1应该是800-200=600,而现在是800,这样就造成的更新丢失。

此时可用两种方法:

悲观锁、乐观锁。

悲观锁:

用户1读取数据后,用锁将其读取的数据锁上,这时用户2是读取不到数据的,只有用户1释放锁后用户2才可以读取,同样用户2读取数据也锁上。

这样就可以解决更新丢失的问题了。

实体类:

packagecom.etc.entity;

importjava.io.Serializable;

publicclassAccountimplementsSerializable{

privateintid;

privateStringname;

privateintquantity;

publicintgetId(){

returnid;

}

publicvoidsetId(intid){

this.id=id;

}

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2