主要解决的是个例问题:
脏读:一个事务读到另一个事务未提交的内容
不可重复读:一个事务读到另一个事务已提交的内容(insert)
虚读(幻读):一个事务读到另一个事务已提交的内容(update)
解决这三个问题的级别:
read uncommittd,读未提交。存在3个问题。
readcommitted,读已提交。解决:脏读。存在2个问题。
repeatableread ,可重复读。解决:脏读、不可重复读。存在1个问题。
serializable,串行化。单事务。没有问题。
乐观锁:
就是再起POJO对象中加一个version字段,表示其版本号,类型是Integer
在*.hbm.xml文件中配置<version name="...">
public class Customer {
private Integer id;
private String cname;
//表示客户与订单之间的一对多关系
private Set<Order> orderSet=new HashSet<Order>();
private Integer version;
<version name="version"></version>
hibernate的二级缓存
hibernate的二级缓存是SessionFactory级别的缓存。
hibernate二级缓存操作配置:
1.导入jar包:ehcache-1.5.0.jar/commons-logging.jar/ backport-util-concurrent.jar
2.开启二级缓存(我要使用二级缓存)
3.确定二级缓存提供商(我要使用哪个二级缓存)
4.确定需要缓存内容
导入jar包:
ehcache-1.5.0.jar是二级缓存的核心包,commons-logging.jar/和backport-util-concurrent.jar都是其依赖包
开启二级缓存:
<property name="hibernate.cache.use_second_level_cache">true</property>
配置二级缓存提供商:
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
缓存内容配置:
<!-- 类缓存配置 -->
<class-cache usage="read-only" class="com.study.hibernate.Customer"/>
<class-cache usage="read-only" class="com.study.hibernate.Order"/>
<!--集合缓存设置-->
<collection-cache usage="read-only" collection="com.study.hibernate.Customer.orderSet"/>
类缓存测试:
@Test
public void test8(){
Session session=HBUtils.getSession();
//开启事物
Transaction tr = session.beginTransaction();
Customer customer1 = (Customer) session.get(Customer.class, 6);
session.clear();//清楚一级缓存
Customer customer2 = (Customer) session.get(Customer.class, 6);
System.out.println(customer1==customer2);
//提交事物
tr.commit();
//关闭会话
session.close();
}
上述测试如果打印两次sql语句,那么二级缓存失效,如果打印一次,则二级缓存起作用。
测试结果:打印一次 但是比较结果是false
类缓存存储的不是类对象,而是散列码,所以,当有数据要查询的时候,查看二级缓存中有无此数据,如果有,则把该数据组装成对象,然后返回。
集合缓存测试:
@Test
public void test9(){
Session session=HBUtils.getSession();
//开启事物
Transaction tr = session.beginTransaction();
Customer customer1 = (Customer) session.get(Customer.class, 6);
for(Order o:customer1.getOrderSet()){
System.out.println(o);
}
session.clear();//清楚一级缓存
Customer customer2 = (Customer) session.get(Customer.class, 6);
for(Order o:customer2.getOrderSet()){
System.out.println(o);
}
//提交事物
tr.commit();
//关闭会话
session.close();
}
集合缓存存储的不是集合,而是id的值,所以在二级缓存中取数据的时候,是取到的id,然后再去类缓存中去数据。
时间戳测试:
假如我们在一次查询后,更改了其数据库中的数据,那么它是怎么
@Test
public void test10() {
Session session = HBUtils.getSession();
// 开启事物
Transaction tr = session.beginTransaction();
Customer customer1 = (Customer) session.get(Customer.class, 6);
System.out.println(customer1.getCname());
session.createQuery("update Customer set cname=:cname where id=:id")
.setParameter("cname", "pe").setParameter("id", 6)
.executeUpdate();
// 提交事物
tr.commit();
// 关闭会话
session.close();
Session session1 = HBUtils.getSession();
// 开启事物
Transaction tr1 = session1.beginTransaction();
Customer customer2 = (Customer) session1.get(Customer.class, 6);
System.out.println(customer2.getCname());
// 提交事物
tr1.commit();
// 关闭会话
session1.close();
}
查询缓存:
查询缓存默认不使用。需要手动开启
查询缓存:将HQL语句与 查询结果进行绑定。通过HQL相同语句可以缓存内容。
默认情况Query对象只将查询结果存放在一级和二级缓存,不从一级或二级缓存获取。
查询缓存就是让Query可以从二级缓存获得内容
要使用查询缓存,则必须开启查询缓存
<!--开启查询缓存 -->
<property name="hibernate.cache.use_query_cache">true</property>
@Test
public void test11() {
Session session = HBUtils.getSession();
// 开启事物
Transaction tr = session.beginTransaction();
Query query=session.createQuery("from Customer");
query.setCacheable(true); //从二级缓存中取数据,取不到就查询数据,并且把数据放到二级缓存中
List<Customer> cusList=query.list();//查询所有的数据
for(Customer c:cusList){
System.out.println(c.getCname());
}
// 提交事物
tr.commit();
// 关闭会话
session.close();
Session session1 = HBUtils.getSession();
// 开启事物
Transaction tr1 = session1.beginTransaction();
Query query1=session1.createQuery("select c from Customer c");//不同的hql语句,从二级缓存中获取
query1.setCacheable(true);
List<Customer> cusList1=query1.list();//查询所有的数据
for(Customer c:cusList1){
System.out.println(c.getCname());
}
// 提交事物
tr1.commit();
// 关闭会话
session1.close();
}
测试结果:打印一次语句,可以看到上述的技术hql不同,但转换成的sql语句相同,所以只打印一次。
所以,查询缓存中根据sql语句判断对否相同。
ehcache文件配置:
在使用二级缓存的时候,可以配置一些参数来优化二级缓存
默认的配置文件:ehcahe-1.5.0.jar//ehcache-failsafe.xml文件中,主要的配置项如下:
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
我们现在要更改其文件配置,只需在src下创建一个名为ehcache.xml的文件
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<diskStore path="D:/ehcache"/> <!-- 二级缓存文件的存放位置 -->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
</ehcache>