hiberante入门(十四):缓存1

1.模拟缓存并简要说明缓存实现原理

myhibernate项目下新建一个包com.asm.hibernate.test.cacheTest来说明与缓存有关的问题。首先看下面的一个模拟缓存程序,主要代码如下:

Java代码 复制代码
  1. package com.asm.hibernate.test.cacheTest;   
  2. public class CacheSimulate {   
  3.     static Map cache = new HashMap();   
  4.     public static void main(String[] args) {   
  5.         addUser();   
  6.         //第一次查询,会去连接数据库查询   
  7.         User u1 = getUser(1);   
  8.         //第二次查询,直接从Map cache中取   
  9.         User u2 = getUser(1);   
  10.         //第三次查询,同样从cache中直接取   
  11.         User u3 = getUser(1);   
  12.     }   
  13.   
  14.     static User getUser(int id) {   
  15.         String key = User.class.getName() + id;   
  16.         User user = (User) cache.get(key);   
  17.         if (user != null)   
  18.             return user;   
  19.         user = getUserFromDB(id);   
  20.         cache.put(key, user);   
  21.         return user;   
  22.     }   
  23.   
  24.     static void addUser() {   
  25.         省略代码,此方法的作用主要是向数据库添加一条记录,以方便查询操作   
  26.     }   
  27.   
  28.     static User getUserFromDB(int id) {   
  29.         省略代码,作用就是真正去查数据   
  30.     }   
  31. }  
package com.asm.hibernate.test.cacheTest;
public class CacheSimulate {
	static Map cache = new HashMap();
	public static void main(String[] args) {
		addUser();
		//第一次查询,会去连接数据库查询
		User u1 = getUser(1);
		//第二次查询,直接从Map cache中取
		User u2 = getUser(1);
		//第三次查询,同样从cache中直接取
		User u3 = getUser(1);
	}

	static User getUser(int id) {
		String key = User.class.getName() + id;
		User user = (User) cache.get(key);
		if (user != null)
			return user;
		user = getUserFromDB(id);
		cache.put(key, user);
		return user;
	}

	static void addUser() {
		省略代码,此方法的作用主要是向数据库添加一条记录,以方便查询操作
	}

	static User getUserFromDB(int id) {
		省略代码,作用就是真正去查数据
	}
}

 

分析:重点来看getUser方法:当我们查询一个数据时,会首先在cache中查找,如果是第一次查询某数据,cache中没有存这个数据,会去查数据库。但是如果已经查过数据,便会在cache中查找到此数据,然后直接返回。可以从控制台中看到:hibernate只与数据库交互一次。 

为什么要提出缓存的概念:在前面已经多次说过与数据库建立连接是非常耗资源,而且相当耗时。为了保证高效的查询性能,才提出了缓存的概念。缓存的原理:当第一次查询时会从数据库中查,当查出数据后会把数据保存在内存中,以后查询时直接从内存中查。当然,实际的缓存要远比此模拟程序复杂,但整个缓存机制是大同小异得,只是它要考虑到更多的细节。下面来谈谈缓存机制要解决的三个主要问题:

(1)向缓存中放数据:一般是发生在查询数据库时,因为每当我们不能从缓存中得到所需数据,便会去数据库中查找,查找完成后我们自然要把它更新到数据库中。

(2)从缓存中取数据:涉及到一个key的设置问题,比如我们在模拟程序中,key的取值来自“id + 类的类型信息”,这样就能保证key值的唯一性,因为如果仅以id作为key,那么其它的类会有相同的id时,在缓存中就不能区分。

(3)清掉缓存中失效的数据:当有其它的操作更新此数据时,原数据将不再正确,这时我们可以选择更新的方式来重新把新的数据更新到缓存中,也可以直接移除原数据,即调用 remove(key)

2.Hibernate中的一级Session缓存:

Java代码 复制代码
  1. package com.asm.hibernate.test.cacheTest;   
  2. public class HibernateCacheTest {   
  3.     public static void main(String[] args) {   
  4.         addUser();   
  5.         getUser(1);   
  6.     }   
  7.   
  8.     static User getUser(int id) {   
  9.         Session s = null;   
  10.         User user = null;   
  11.         try {   
  12.             s = HibernateUtil.getSession();   
  13.             user = (User) s.get(User.class, id);   
  14.             System.out.println("userName:" + user.getName());   
  15.   
  16.             // session缓存,当session未关闭时,再查询直接从缓存中获得数据。   
  17.             user = (User) s.get(User.class, id);   
  18.             System.out.println("userName:" + user.getName());   
  19.   
  20.             // 如果我们清掉缓存,再查询时将会重新连库。   
  21.             s.evict(user);// 清掉指定的数据   
  22.             // s.clear();//清掉当前session缓存中的所有内容   
  23.             user = (User) s.get(User.class, id);   
  24.             System.out.println("userName:" + user.getName());   
  25.         } finally {   
  26.             if (s != null)   
  27.                 s.close();   
  28.         }   
  29.   
  30.         // 当上面的session关闭后,如果想再获取前面查询的数据,必须重新查库。   
  31.         try {   
  32.             s = HibernateUtil.getSession();   
  33.             user = (User) s.get(User.class, id);   
  34.             System.out.println("userName:" + user.getName());   
  35.         } finally {   
  36.             if (s != null)   
  37.                 s.close();   
  38.         }   
  39.         return user;   
  40.     }   
  41.   
  42.     static void addUser() {   
  43.         User user = new User();   
  44.         user.setName("genName");   
  45.         HibernateUtil.add(user);   
  46.     }   
  47. }  
package com.asm.hibernate.test.cacheTest;
public class HibernateCacheTest {
	public static void main(String[] args) {
		addUser();
		getUser(1);
	}

	static User getUser(int id) {
		Session s = null;
		User user = null;
		try {
			s = HibernateUtil.getSession();
			user = (User) s.get(User.class, id);
			System.out.println("userName:" + user.getName());

			// session缓存,当session未关闭时,再查询直接从缓存中获得数据。
			user = (User) s.get(User.class, id);
			System.out.println("userName:" + user.getName());

			// 如果我们清掉缓存,再查询时将会重新连库。
			s.evict(user);// 清掉指定的数据
			// s.clear();//清掉当前session缓存中的所有内容
			user = (User) s.get(User.class, id);
			System.out.println("userName:" + user.getName());
		} finally {
			if (s != null)
				s.close();
		}

		// 当上面的session关闭后,如果想再获取前面查询的数据,必须重新查库。
		try {
			s = HibernateUtil.getSession();
			user = (User) s.get(User.class, id);
			System.out.println("userName:" + user.getName());
		} finally {
			if (s != null)
				s.close();
		}
		return user;
	}

	static void addUser() {
		User user = new User();
		user.setName("genName");
		HibernateUtil.add(user);
	}
}

 

分析:经过上面的测试和相关说明我们可以得知如下结论:

(1)session的缓存只在session未关闭前有效,关闭后再查同的数据会重新连库

(2)我们可以手工清除session中的缓存:evictclear

(3)如果我们清掉session中的缓存,或是第一次查询这个数据,都会引起连库

(4)saveupdate,savaOrUpdate,load,get,list,iterate,lock等方法都会将对象放在一级缓存中,具体可以在上例的基础上进行测试。

(5)session一级缓存不能控制缓存数量,所以在大批量操作数据时可能造成内存溢出,这时我们可以用evictclear来清除缓存中的内容

(6)sessionweb开发应用中,一般只在一个用户请求时进行缓存,随后将会关闭,这个session的存活时间很短,所以它的作用不大,因此提出了二级缓存在概念。

3.二级缓存:

二级缓存通常是第三方来实现,而我们使用时只需要对它进行配置即可。下面演示使用二级缓存的具体步骤。

>>步骤一,在主配置文件中指明支持使用二级缓存:

<property name="hibernate.cache.use_second_level_cache">true</property>

我们也可以不配置此属性,因为默认就是打开二级缓存。

>>步骤二、配置第三方缓存机制:

<property name="hibernate.cache.provider_class">

           org.hibernate.cache.OSCacheProvider

</property>   由于我们这里选择了OSCacheProvider(它貌似也是hibernate官方开发得缓存机制)来提供缓存,所以还需要把它的缓存配置文件放在src目录下以使配置能被读到,这里即是把hibernate解压下的etc目录中的oscache.properties文件复制到src目录下。

>>步骤三、两种方式指定要缓存的实体类,一种是在主配置文件中配置(注意class是完整的类名)<class-cache class="com.asm.hibernate.domain.User" usage="read-only"/>

另一种是在实体配置文件(映射文件)配置:比如在User.hbm.xml class元素下配置如下内容:<cache usage="read-only"/>  关于usage属性值的说明:

read-only:如果你的应用程序只需读取一个持久化类的实例,而无需对其修改,那么就可以对其进行只读缓存。这是最简单,也是实用性最好的方法。

read-write: 如果应用程序需要更新数据,那么使用“/写缓存”比较合适。 如果应用程序要求“序列化事务”的隔离级别(serializable transaction isolation level),那么就决不能使用这种缓存策略。

nonstrict-read-write: 如果应用程序只偶尔需要更新数据(也就是说,两个事务同时更新同一记录的情况很不常见),也不需要十分严格的事务隔离,那么比较适合使用非严格读/写缓存策略。
transactional: Hibernate的事务缓存策略提供了全事务的缓存支持,例如对JBoss TreeCache的支持。这样的缓存只能用于JTA环境中,你必须指定为其hibernate.transaction.manager_lookup_class属性。

你可能感兴趣的:(Hibernate,jboss,cache)