十九 hibernate3之缓存

什么是缓存?现在我们来看一个模拟的缓存操作
模拟一个缓存例子

package cn.itcast.hibernate;

import java.util.HashMap;
import java.util.Map;

import cn.itcast.hibernate.domain.User;

public class CacheDemo {

	static Map cache = new HashMap();

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		User u = getUser(1);	
		
		User u1 = getUser(1);

	}

	public static void update(User user){
		updateDB(user);
		String key = User.class.getName() + user.getId();
		cache.remove(key);
	}
	
	

	public static User getUser(int id) {
		String key = User.class.getName() + id;
		User user = (User) cache.get(key);
		if (user != null)
			return user;
		user = getFromDB();
		cache.put(key, user);
		return user;
	}
	
	private static void updateDB(User user) {
		// TODO Auto-generated method stub
		
	}
	private static User getFromDB() {
		// TODO Auto-generated method stub
		return null;
	}
}

这里实现的是简单的模拟缓存原理,只是简单的把数据放入到Map集合中去
牵扯的数据有键值更新加入删除操作



缓存的作用主要用来提高性能,可以简单的理解成一个Map;使用缓存涉及到三个操作:把数据放入缓存、从缓存中获取数据、
删除缓存中的无效数据。
一级缓存,Session级共享。
save,update,saveOrUpdate,load,get,list,iterate,lock这些方法都会将对象放在一级缓存中,
一级缓存不能控制缓存的数量,所以要注意大批量操作数据时可能造成内存溢出;可以用evict,clear方法清除缓存中的内容。 

理解:Session级缓存是相当短暂的,一个请求的完成,Session就会关闭,一级缓存是由Session去控制的,如果Session关闭
缓存数据也随之不存在,下次访问数据,还是要去访问数据库

二级缓存

二级缓存,SessionFactory级共享。
实现为可插拔,通过修改cache.provider_class参数来改变;
	hibernate内置了对EhCache,OSCache,TreeCache,SwarmCache的支持,
	可以通过实现CacheProvider和Cache接口来加入Hibernate不支持的缓存实现。
在hibernate.cfg.xml中加入:
	<class-cache class="className" usage="read-only"/>
	或在映射文件的class元素加入子元素:
	<cache usage="read-write"/>
	其中usage:read-only,read-write,nonstrict-read-write,transactional
Session的:save(这个方法不适合native生成方式的主键),
	update,saveOrUpdate,list,iterator,get,load,以及Query,Criteria都会填充二级缓存,
	
	但只有(没打开查询缓存时)Session的iterator,get,load会从二级缓存中取数据(iterator可能存在N+1次查询)。
Query,Criteria(查询缓存)由于命中率较低,所以hibernate缺省是关闭;修改cache.use_query_cache为true打开对查询的缓存,
并且调用query.setCacheable(true)或criteria.setCacheable(true)。
SessionFactory中提供了evictXXX()方法用来清除缓存中的内容。
统计信息打开generate_statistics,用sessionFactory.getSatistics()获取统计信息。 


下面我们来看二级缓存的一些重要参数
##########################
### Second-level Cache ###
##########################

## optimize chache for minimal "puts" instead of minimal "gets" (good for clustered cache)

#hibernate.cache.use_minimal_puts true


## set a prefix for cache region names

hibernate.cache.region_prefix hibernate.test


## disable the second-level cache

#hibernate.cache.use_second_level_cache false


## enable the query cache

#hibernate.cache.use_query_cache true


## store the second-level cache entries in a more human-friendly format

#hibernate.cache.use_structured_entries true


## choose a cache implementation

#hibernate.cache.provider_class org.hibernate.cache.EhCacheProvider
#hibernate.cache.provider_class org.hibernate.cache.EmptyCacheProvider
hibernate.cache.provider_class org.hibernate.cache.HashtableCacheProvider
#hibernate.cache.provider_class org.hibernate.cache.TreeCacheProvider
#hibernate.cache.provider_class org.hibernate.cache.OSCacheProvider   
#hibernate.cache.provider_class org.hibernate.cache.SwarmCacheProvider


## choose a custom query cache implementation

#hibernate.cache.query_cache_factory



解释: 
#hibernate.cache.use_second_level_cache false
这个是用来打开二级缓存的,一般在hibernate的hibernate.cfg.xml文件中去配置
配置方法:
1<property name="cache.use_second_level_cache">true</property>
这里只是配置二级缓存打开,缺省的就是true
2还要进一步配置,其二级缓存是用什么框架实现的
#hibernate.cache.provider_class org.hibernate.cache.OSCacheProvider    
<property name="cache.provider_class">org.hibernate.cache.OSCacheProvider</property>
并且需要把OSCache的配置文件加入到工程的src根目录下 oscache.properties 
同时需要引入OSCache框架包 oscache-2.1.jar
3还需要配置哪些类的对象需要二级缓存
<class-cache usage="read-only" class="vo.util.bean.Department"/>
usage节点是配置缓存策略 策略有四种
- read-only 只能对其读取用到,如果对所配置的类修改就报异常,效率比较高
- read-write  严格的读写限制
- nonstrict-read-write 
- transactional 事务型缓存

还有一种在映射文件中去配置缓存的对象 这相对一些比较简单 推荐方式
直接在映射文件中的class节点下加入 <cache usage="read-only"/> 
完整的映射文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping 
	package="vo.util.bean">

	<class name="Department">
	<!--是否使用SessionFactory缓存-->
	<cache usage="read-only"/>

		<id name="id">
			<generator class="native"/>
		</id>
		<property name="name"/>
		<!-- 配置一对多的映射关系  -->
		<set name="ems" cascade="all">
		<!-- 关联关系的外键  -->
		<key column="depaer_id"/>
		   <!-- 关联关系的实体类配置 -->
		  <one-to-many  class="Employee" />
		</set>
	</class>
	
</hibernate-mapping>
4 OSCacheProvider提供者的配置文件 

使用统计来分析缓存是否数据的正确
 <!-- 统计数 -->
<property name="generate_statistics">true</property>


完整的hibernate的配置文件
<!DOCTYPE hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<session-factory>
	<property name="connection.driver_class">
		com.mysql.jdbc.Driver
	</property>
	<property name="connection.url">jdbc:mysql:///test</property>
	<property name="connection.username">root</property>
	<property name="connection.password">root</property>
	<!-- 指定其方言 方言的作用就是告诉hibernate是哪种数据库 -->
	<property name="dialect">
		org.hibernate.dialect.MySQLDialect
	</property>
	<!-- 指定其hibernate是否根据映射文件自动创建表 -->
	<property name="hbm2ddl.auto">create</property>
	<property name="show_sql">true</property>
	<!-- 配置二级缓存是否打开 -->
	<property name="cache.use_second_level_cache">true</property>
	<!--二级缓存的提供者  这里需要注意的是你的工程中有没有OScache包 oscache-2.1.jar
	并且需要把oscache.properties文件拷贝进工程类路径的src目录下 在这个文件里配置
	cache.capacity参数
	-->
	<property name="cache.provider_class">org.hibernate.cache.OSCacheProvider</property>
	<!-- 这里配置哪些类的对象需要缓存 usage是缓存策略 -->
	<!--class-cache usage="read-only" class="vo.util.bean.Department"/-->
	
    <!-- 统计数 -->
    <property name="generate_statistics">true</property>
    
	<mapping resource="vo/util/bean/Department.hbm.xml" />
	<mapping resource="vo/util/bean/Employee.hbm.xml" />

</session-factory>
</hibernate-configuration>


然后就可以执行
Statistics st = HibernateUtil.getSessionFactory().getStatistics();
System.out.println("put:" + st.getSecondLevelCachePutCount());
System.out.println("hit:" + st.getSecondLevelCacheHitCount());
System.out.println("miss:" + st.getSecondLevelCacheMissCount());

通过执行这代码就可以知道二级缓存数据的读取成功与否
st.getSecondLevelCachePutCount() 放入缓存数据次数
st.getSecondLevelCacheHitCount() 读取缓存成功次数
st.getSecondLevelCacheMissCount() 读取缓存失败次数

分析 一般程序在第一次与数据库进行交互的时候,hibernate会从缓存中去找,首先从
一级缓存中去找,然后从二级缓存中去找,如果没有找到才去访问数据库,第一次运行时
缓存数据是没有的,所以二级缓存miss一次,同时它会put一次,第二次执行时,所以就会
报成功一次 

一级缓存数据的清理
  session=HibernateUtil.getSession();
 session.evict(arg0) 清理单个某一类Class的数据
session.clear() 清理全部一级缓存数据

二级缓存数据的清理
  HibernateUtil.getSessionFactory().evict(arg0) 清理单个缓存对象的数据
HibernateUtil.getSessionFactory().evict(arg0,id) 清理某一条单个缓存对象的某一条数据


二级缓存,SessionFactory级共享。
实现为可插拔,通过修改cache.provider_class参数来改变;
	hibernate内置了对EhCache,OSCache,TreeCache,SwarmCache的支持,
	可以通过实现CacheProvider和Cache接口来加入Hibernate不支持的缓存实现。
在hibernate.cfg.xml中加入:
	<class-cache class="className" usage="read-only"/>
	或在映射文件的class元素加入子元素:
	<cache usage="read-write"/>
	其中usage:read-only,read-write,nonstrict-read-write,transactional
Session的:save(这个方法不适合native生成方式的主键),
	update,saveOrUpdate,list,iterator,get,load,以及Query,Criteria都会填充二级缓存,
	但只有(没打开查询缓存时)Session的iterator,get,load会从二级缓存中取数据(iterator可能存在N+1次查询)。
Query,Criteria(查询缓存)由于命中率较低,所以hibernate缺省是关闭;修改cache.use_query_cache为true打开对查询的缓存
,并且调用query.setCacheable(true)或criteria.setCacheable(true)。
SessionFactory中提供了evictXXX()方法用来清除缓存中的内容。
统计信息打开generate_statistics,用sessionFactory.getSatistics()获取统计信息。 

e
分布式缓存
一个系统搭建多台服务器,一个数据库 并发访问共享出现问题

解决 中央缓存


使用缓存的条件
1.读取大于修改。
2.数据量不能超过内存容量。
3.对数据要有独享的控制。
4.可以容忍出现无效数据。


事务
	单个数据库(一个SesisonFactory对应一个数据库),由JDBC实现。
	Session session = null;
	Transaction tx =null;
	try {
		session = sessionFactory.openSession();
		tx = session.beginTransaction();
		//process
		tx.commit();
	} catch(HibernateException e){
		if(tx != null)tx.rollback();throw e;
	}finally {
		if (session != null)session.close();
	}
	connection.setAutoCommit(false);
	connection.commit();conn.rollback();



JTATransaction
	可以简单的理解成跨数据库的事物,由应用JTA 容器实现;
	使用JTATransaction需要配置hibernate.transaction.factory_class参数,
	该参数缺省值是org.hibernate.transaction. JDBCTransactionFactory,
	当使用JTATransaction时需要将该参数改成org.hibernate.transaction.JTATransactionFactory,
	并配置jta.UserTransaction参数JNDI名(Hibernate在启动JTATransaction时要用该值到JNDI的上
	下文Context中去找javax.transaction.UserTransaction)。
javax.transaction.UserTransactin tx = context.lookup(“jndiName”);
try{
	tx.begin();
	//多个数据库的session操作;
	//session1….
	//session2….
	tx.commit();
}catch(Exception e){
	tx.rollback(); throw e;
}



end 完毕!

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值