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