`
schy_hqh
  • 浏览: 558255 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

Hibernate基于配置文件(十七)缓存策略

 
阅读更多

hibernate缓存策略---调整性能。
主要目的:提高查询效率

从内存中获取对象,不需要与数据库进行交互---提高查询性能
缓存:
    *一级缓存 session级别           只在session打开有效   生命周期:与session相关
    *二级缓存 sessionFactory级别(全局缓存)
    *查询缓存 sessionFactory级别(全局缓存)

缓存的命中:
通过什么key放到内存中,就通过什么key到内存中取   
   
一级、二级缓存,缓存的是key是ID,缓存的value是实体对象
查询缓存,缓存的key是HQL语句与参数,缓存的value:
        查询的是普通结果集,则缓存value为这些结果集
        特殊:查询的是实体对象,则缓存value为实体对象的ID列表[实体对象被放到了二级缓存中]
       
---------------------------------------------------------------------------------------
       
一级缓存---缓存对象:持久化对象:
hibernate中默认的缓存机制,不能取消,能对其进行管理
比如:
session.save() session.load() session.get()  加入到一级缓存
session.evict() session.clear() session.close() 从一级缓存中清除

两个特点:
    *session级别 (session关闭后内存中就不存在了)
    *缓存实体对象

get/load/list/iterate方法会把加载的实体对象放入一级缓存
get/load/iterate方法会利用缓存
    即在加载实体对象之前,会先判断缓存中是否存在该实体对象(根据id),如果不存在,则发出查询语句
list方法不会利用缓存,每次使用list查询,都会发出查询语句

结合list+iterator实现对缓存的利用
    首先使用list将数据加载到内存中,list只发出一条查询语句即可
    session有效期内再使用iterate,就能利用缓存进行数据获取了。
    此时iterate只会发出一条查询语句查询id列表,对象的获取直接从缓存中取,从而不会发生N+1现象
   
session.save() session.update() 也会将对象放入到一级缓存中
一级缓存:内存中处于持久化状态的对象

一级缓存的管理(重点理解):
*session.evict() 将一级缓存中某个实体对象清除出去
*session.clear() 清除一级缓存中所有的实体对象(flush + clear 做批量数据插入)
*session.close() session关闭,一级缓存中的实体对象全部无效
*flush 把一级缓存中对象属性更新到数据库记录中  
    强制hibernate即时执行insert update delete 操作
    (如果需要hibernate按照程序逻辑进行DML操作,必须使用flush,
    否则hibernate会按默认规则:commit的时候进行批量数据提交与更新
    而批量操作不会按照程序逻辑执行,会批量执行完insert再批量执行update)
    应用:目录树结构存储是对treeId的保存操作就需要使用flush强制hibernate即时更新数据
*refresh 把数据库中的记录同步到一级缓存中

大批量数据的插入:
hibernate一级缓存策略--凡是持久化对象就会放入一级缓存中
所以,在大数据批量插入时,必须及时清空缓存
save()+flush()+clear() 防止内存溢出[id生成策略不能使native]
--------------------------------------------------------------------------------------

二级缓存、查询缓存:
hibernate通过第三方框架实现,可以灵活配置[只用二级缓存、只用查询缓存、两个都用、都不用]

二级缓存:
    能够跨越不同的session而存在(一级缓存是与session绑定的,session关闭缓存便清空)
1.sessionFactory级别的缓存
2.缓存实体对象[保存内存中实体对象的引用,一级缓存被清除,但内存中的对象仍被二级缓存持有引用]

使用步骤:
1.启用(配置) hibernate.cfg.xml
    <property name="hibernate.cache.use_second_level_cache">true</property>
2.指定缓存策略提供商(配置)
    <property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>
    实际开发中,需要使用专业的缓冲提供商的缓存策略!hashtable仅用于测试!
3.指定哪些实体类对象需要使用二级缓存,以及如何使用缓存(配置)
    可以在hibernate.cfg.xml中指定
    <class-cache usage="read-write" class="org.leadfar.hibernate.model.ContactPerson"/>
    也可以在实体类对应的配置文件中进行配置
    比如在ContactPerson.hbm.xml中配置<cache usage="read-write"/>

使用session与二级缓存的交互:
session.setCacheMode(CacheMode.NORMAL);
NORMAL:表示查询的时候会利用二级缓存(get)、查询结果会放入二级缓存(put)

清除二级缓存中某个类型的实体对象
session.getSessionFactory().getCache().evictEntityRegion(ContactPerson.class);

hibernate查询机制:
1.首先到一级缓存中找
2.如果该实体类启用了二级缓存机制,则到二级缓存中找
3.如果也没有,则发出查询语句

--------------------------------------------------------------------------------
查询缓存
1.HQL语句查询部分属性
2.sessionFactory级别
使用步骤:
1.启用(配置) hibernate.cfg.xml
    <property name="hibernate.cache.use_query_cache">true</property>
2.指定缓存策略提供商(配置) --与二级缓存使用同一个缓存提供商[hibernate不能同时使用两个不同的提供商]
   
3.编程的时候指定哪些查询需要使用查询缓存(编程)
    每次查询都需设置:query.setCacheable(true);
   
清除查询缓存:
    session.getSessionFactory().getCache().evictDefaultQueryRegion();
   
注意:
慎用查询缓存
hql查询语句+查询参数  才唯一锁定一条查询,如果两者之一变化,则在内存中无法命中
所以,只有在hql语句及参数固定的情况下,才建议使用查询缓存
否则,容易导致内存溢出。。。
因为一旦某个参数变化了,就会生成一个新的对象,并放到查询缓存中,这样缓存会占用很大空间

如果要使用查询缓存,一定要配合二级缓存来使用!
当查询实体对象又使用查询缓存的时候,如果二级缓存被关闭,list()会发生N+1问题
因为查询缓存中存放的是ID列表,根据ID去二级缓存中找不到数据,就会按照ID发出查询语句

   


 

 


    <class name="org.leadfar.hibernate.model.ContactPerson" table="t_person" >
        <!-- 配置ContactPerson对象使用二级缓存 -->
        <cache usage="read-write"/>

 

 

 

package org.leadfar.hibernate.model;




import java.io.File;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import junit.framework.TestCase;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;


public class TestHQL extends TestCase {
	
	public void save_person() throws Exception {
		Configuration cfg = new Configuration().configure();
		
		SessionFactory sfactory = cfg.buildSessionFactory();
		
		Session session = sfactory.openSession();
		
		try {
			//开启事务
			session.beginTransaction();
			Random r = new Random();
			for(int i=0;i<100;i++) {
				ContactPerson cp = new ContactPerson("李四"+i);
				cp.setAge(r.nextInt(99));
				cp.setBirthday(new Date());
				session.save(cp);
			}
			
			
			
			//提交事务
			session.getTransaction().commit();
			
		} catch(Exception e) {
			e.printStackTrace();
			//出现异常,回滚事务
			session.getTransaction().rollback();
		} finally {
			//关闭session
			session.close();//session关闭之后,user对象处于离线Detached状态
		}
	}
	
	/**
	 * 一级缓存有效期:session有效
	 * session.get()查询出来的对象被放到一级缓存中
	 * 在session有效期内,访问同一个对象将不再发出查询语句,直接到一级缓存中通过ID获取实体对象
	 * 一级缓存中的key:id,value:实体对象
	 */
	public void cache_level_1_01() throws Exception {
		Configuration cfg = new Configuration().configure();		
		SessionFactory sfactory = cfg.buildSessionFactory();		
		Session session = sfactory.openSession();		
		try {
			session.beginTransaction();
			
			//hibernate发出查询语句,把id=1的实体对象加载到内存 ,并放到一级缓存中
			ContactPerson cp1 = (ContactPerson)session.get(ContactPerson.class, 1);
			
			//对同一个对象的访问,不发出查询语句,直接从一级缓存中取
			ContactPerson cp2 = (ContactPerson)session.get(ContactPerson.class, 1);
			
			//对同一个对象的访问,不发出查询语句,直接从一级缓存中取
			//由于使用的是get()获取到的对象,这里使用load()从一级缓存中取出的也是普通对象,而不是代理对象
			ContactPerson cp3 = (ContactPerson)session.load(ContactPerson.class, 1);
			
			session.getTransaction().commit();			
		} catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		} finally {
			session.close();
		}
	}
	/**
	 * session关闭之后,访问同一个对象会再次发出查询语句
	 * 因为一级缓存中的数据在session关闭后,就被清空了
	 */
	public void cache_level_1_02() throws Exception {
		Configuration cfg = new Configuration().configure();		
		SessionFactory sfactory = cfg.buildSessionFactory();		
		Session session = sfactory.openSession();		
		try {
			session.beginTransaction();
			
			//hibernate发出查询语句,把id=1的实体对象加载到内存 ,并放到一级缓存中
			ContactPerson cp1 = (ContactPerson)session.get(ContactPerson.class, 1);
			//由于一级缓存中已经缓存了id=1的实体对象,再次获取该实体对象,不会发出查询语句
			ContactPerson cp2 = (ContactPerson)session.get(ContactPerson.class, 1);
			
			session.getTransaction().commit();			
		} catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		} finally {
			session.close();
		}
		
		//打开一个新的session
		session = sfactory.openSession();		
		try {
			session.beginTransaction();
			
			//由于是新的session,一级缓存中并没有id=1的实体对象,所以会发出查询语句
			ContactPerson cp4 = (ContactPerson)session.get(ContactPerson.class, 1);
			
			session.getTransaction().commit();			
		} catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		} finally {
			session.close();
		}
	}
	
	/**
	 * list()会把查询的结果放入到一级缓存中
	 */
	public void cache_level_1_03() throws Exception {
		Configuration cfg = new Configuration().configure();		
		SessionFactory sfactory = cfg.buildSessionFactory();		
		Session session = sfactory.openSession();		
		try {
			session.beginTransaction();
			
			List<ContactPerson> cps = session.createQuery("from ContactPerson").list();
			
			//不会发出查询语句
			ContactPerson cp1 = (ContactPerson)session.load(ContactPerson.class, 2);
			ContactPerson cp2 = (ContactPerson)session.get(ContactPerson.class, 30);
			ContactPerson cp3 = (ContactPerson)session.load(ContactPerson.class, 66);
			
			session.getTransaction().commit();			
		} catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		} finally {
			session.close();
		}
	}
	/**
	 * list()不会利用一级缓存
	 */
	public void cache_level_1_04() throws Exception {
		Configuration cfg = new Configuration().configure();		
		SessionFactory sfactory = cfg.buildSessionFactory();		
		Session session = sfactory.openSession();		
		try {
			session.beginTransaction();
			
			List<ContactPerson> cps = session.createQuery("from ContactPerson").list();
			
			//不会发出查询语句
			ContactPerson cp1 = (ContactPerson)session.load(ContactPerson.class, 2);
			ContactPerson cp2 = (ContactPerson)session.get(ContactPerson.class, 30);
			ContactPerson cp3 = (ContactPerson)session.load(ContactPerson.class, 66);
			
			//list()不会利用缓存,再次发出查询语句
			List<ContactPerson> cps2 = session.createQuery("from ContactPerson").list();
			
			session.getTransaction().commit();			
		} catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		} finally {
			session.close();
		}
	}
	/**
	 * iterate() 存在N+1问题,但是其会利用缓存
	 * 由于iterate会利用缓存,再次使用iterate时将只发出一条查询id列表的语句,剩余N条查询语句不再发出
	 * 而是直接从缓存中获取对象
	 */
	public void cache_level_1_05() throws Exception {
		Configuration cfg = new Configuration().configure();		
		SessionFactory sfactory = cfg.buildSessionFactory();		
		Session session = sfactory.openSession();		
		try {
			session.beginTransaction();
			
			//共发出:N+1
			//iterate()查询出所有对象的id列表---1条查询语句
			Iterator<ContactPerson> it = session.createQuery("from ContactPerson").iterate();
			//迭代过程中,针对每个需要访问的对象再发出一条查询语句---N条查询语句
			while(it.hasNext()) {
				ContactPerson cp = it.next();
				//lazy=true,直到访问到对象非id属性才会发出查询语句
				System.out.println(cp.getName()+","+cp.getId());
			}
				
			//共发出:1条(查询ID列表)
			Iterator<ContactPerson> it2 = session.createQuery("from ContactPerson").iterate();		
			while(it2.hasNext()) {
				//iterate会利用缓存
				ContactPerson cp = it2.next();//判断缓存是否有需要的对象,没有才会发出查询语句
				//所以,不会再发出查询语句,直接从缓存中取
				System.out.println(cp.getName()+","+cp.getId());
			}
			
			session.getTransaction().commit();			
		} catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		} finally {
			session.close();
		}
	}
	/**
	 * list() + iterate()
	 * list()---发出1条查询语句查询所有对象 ,并将数据放入缓存(第一次使用iterate会发生N+1)
	 * iterate()---发出1条查询语句 查询id列表,再利用缓存获取数据(list已经把数据放入缓存了)
	 */
	public void cache_level_1_06() throws Exception {
		Configuration cfg = new Configuration().configure();		
		SessionFactory sfactory = cfg.buildSessionFactory();		
		Session session = sfactory.openSession();		
		try {
			session.beginTransaction();
			
			List<ContactPerson> cps = session.createQuery("from ContactPerson").list();
			
			//iterate()查询出所有对象的id列表---1条查询语句
			Iterator<ContactPerson> it = session.createQuery("from ContactPerson").iterate();
			//list()已经将数据放入缓存,iterate会利用缓存,所以,不再发出查询语句
			while(it.hasNext()) {
				ContactPerson cp = it.next();//判断缓存是否有需要的对象,没有才会发出查询语句
				System.out.println(cp.getName()+","+cp.getId());
			}
		
			
			session.getTransaction().commit();			
		} catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		} finally {
			session.close();
		}
	}
	
	/**
	 * 持久化对象---一定被放入到了一级缓存中
	 */
	public void cache_level_1_07() throws Exception {
		Configuration cfg = new Configuration().configure();		
		SessionFactory sfactory = cfg.buildSessionFactory();		
		Session session = sfactory.openSession();		
		try {
			session.beginTransaction();
			
			ContactPerson cp = new ContactPerson();
			cp.setAge(100);
			cp.setName("aa");
			//对象状态更新为持久化对象
			session.save(cp);
			
			//不会发出查询语句
			ContactPerson cp2 = (ContactPerson)session.get(ContactPerson.class, cp.getId());
			System.out.println(cp2.getId()+","+cp.getName()+","+cp.getAge());
			
			session.getTransaction().commit();			
		} catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		} finally {
			session.close();
		}
	}
	/**
	 * 对一级缓存的管理:refresh()
	 * refresh()操作会针对指定对象再次发出查询语句,
	 * 获取其属性并将一级缓存中的持久化对象属性进行更新
	 * 保持与数据库记录的一致
	 */
	public void cache_level_1_08() throws Exception {
		Configuration cfg = new Configuration().configure();		
		SessionFactory sfactory = cfg.buildSessionFactory();		
		Session session = sfactory.openSession();		
		try {
			session.beginTransaction();
			
			//查询某个对象的属性,get()会将结果放入到一级缓存中
			ContactPerson cp = (ContactPerson)session.get(ContactPerson.class, 1);
			System.out.println("原始记录:name="+cp.getName());
			
			//改变持久化对象的属性
			cp.setName("xx");
			System.out.println("改变持久化对象的属性:name="+cp.getName());
			
			//refresh:再次发出查询语句,获取对象最新的数据,并更新内存中的持久化对象属性
			session.refresh(cp);
			System.out.println("刷新持久化对象属性:name="+cp.getName());
			
			session.getTransaction().commit();			
		} catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		} finally {
			session.close();
		}
	}
	
	/**
	 * 对一级缓存的管理:flush()
	 * 某些情况下按照hibernate的性能优化方案--批量操作,将无法按照程序逻辑进行执行,所以需要flush
	 * 强制hibernate马上更新数据
	 * 而不是等到commit的时候进行批量执行
	 * 因为批量执行的时候,不会按照程序逻辑进行数据库的DML操作
	 * 而程序逻辑一旦被打乱,将导致错误发生
	 * 
	 * 何时使用flush:
	 * 	如果程序逻辑必须严格按照书写顺序执行,那么必须使用flush操作
	 * 原因:
	 *  hibernate性能优化方案之一:批量数据提交,集中操作
	 *  但是,批量操作对应的执行顺序与程序逻辑不符
	 *  比如:需要每insert一条记录,马上update此条记录(需要先生成id,再根据id更新某个字段)
	 *  但是hibernate批量数据执行的顺序是:批量insert,再批量update
	 *  最终就会导致程序运行错误
	 */
	public void cache_level_1_09() throws Exception {
		Configuration cfg = new Configuration().configure();		
		SessionFactory sfactory = cfg.buildSessionFactory();		
		Session session = sfactory.openSession();		
		try {
			session.beginTransaction();
			
			save(session,new File("e:/apache-tomcat-6.0.29"),null);
			
			session.getTransaction().commit();			
		} catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		} finally {
			session.close();
		}
	}
	
	//保存一个文件目录树到数据库---parent记录父子关系
	private void save(Session session,File file,Node parent) {
		Node node = new Node();
		node.setName(file.getName());
		node.setParent(parent);//关键:在多的一方建立关联
		node.setTreeId("");
		session.save(node);
		
		if(parent!=null) {
			node.setTreeId(parent.getTreeId()+"|"+node.getId());
		} else {
			node.setTreeId(node.getId()+"");
		}
		
		session.flush();
		
		if(file.isDirectory()) {
			File[] files = file.listFiles();
			if(files!=null) {
				for(File f : files) {
					save(session,f,node);
				}
			}
		}
	}
	
	/**
	 * ContactPerson类配置二级缓存策略
	 * 在不同的session中获取实体对象,而没有发出查询语句
	 * 原因就在于:二级缓存中已存放了该对象的引用,可以在二级缓存中进行获取
	 */
	public void cache_level_2_01() throws Exception {
		Configuration cfg = new Configuration().configure();		
		SessionFactory sfactory = cfg.buildSessionFactory();		
		Session session = sfactory.openSession();		
		try {
			session.beginTransaction();
			
			//hibernate发出查询语句,把id=1的实体对象加载到内存 ,并放到一级缓存中[默认]
			//同时会在二级缓存中增加对该实体对象的引用
			ContactPerson cp1 = (ContactPerson)session.get(ContactPerson.class, 1);
			
			session.getTransaction().commit();			
		} catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		} finally {
			session.close();
		}
		
		//打开一个新的session
		session = sfactory.openSession();		
		try {
			session.beginTransaction();
			
			//虽然是新的session,但是id=1的ContactPerson对象已经被存放到二级缓存中
			//所以不会发出查询语句
			ContactPerson cp4 = (ContactPerson)session.get(ContactPerson.class, 1);
			
			session.getTransaction().commit();			
		} catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		} finally {
			session.close();
		}
	}
	
	/**
	 * 可以使用session对二级缓存中的对象进行管理:比如清除掉某种类型的实体对象
	 * session.getSessionFactory().getCache().evictEntityRegion(ContactPerson.class);
	 * 
	 * 可以通过session设置配置了二级缓存策略的对象的缓存方式:
	 * session.setCacheMode(CacheMode.NORMAL); 查询时会利用、查询结果会放入
	 * session.setCacheMode(CacheMode.PUT); 会将结果放入二级缓存
	 * session.setCacheMode(CacheMode.GET); 查询时才利用二级缓存
	 */
	public void cache_level_2_02() throws Exception {
		Configuration cfg = new Configuration().configure();		
		SessionFactory sfactory = cfg.buildSessionFactory();		
		Session session = sfactory.openSession();		
		try {
			session.beginTransaction();
			
			//hibernate发出查询语句,把id=1的实体对象加载到内存 ,并放到一级缓存中
			ContactPerson cp1 = (ContactPerson)session.get(ContactPerson.class, 1);
			//由于一级缓存中已经缓存了id=1的实体对象,再次获取该实体对象,不会发出查询语句
			ContactPerson cp2 = (ContactPerson)session.get(ContactPerson.class, 1);
			
			session.getTransaction().commit();			
		} catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		} finally {
			session.close();
		}
		
		//打开一个新的session
		session = sfactory.openSession();		
		try {
			session.beginTransaction();
			
			//从二级缓存中将指定类型的对象清除
			session.getSessionFactory().getCache().evictEntityRegion(ContactPerson.class);
			
			//由于二级缓存中已经清除了对ContactPerson对象的引用,所以会再次发出查询语句
			ContactPerson cp4 = (ContactPerson)session.get(ContactPerson.class, 1);
			
			session.getTransaction().commit();			
		} catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		} finally {
			session.close();
		}
	}
	/**
	 * 查询缓存的使用
	 */
	public void cache_query_3_01() throws Exception {
		Configuration cfg = new Configuration().configure();		
		SessionFactory sfactory = cfg.buildSessionFactory();		
		Session session = sfactory.openSession();		
		try {
			session.beginTransaction();
			
			String hql = "select p.name,p.age from ContactPerson p where p.name like ?";
			Query query = session.createQuery(hql);//声明使用查询缓存
			query.setCacheable(true);//打开查询缓存
			query.setParameter(0, "%1%");
			
			List<Object[]> cps = query.list();
			for(Object[] cp : cps) {
				System.out.println(cp[0]+","+cp[1]);
			}
			
			session.getTransaction().commit();			
		} catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		} finally {
			session.close();
		}
		
		//打开一个新的session
		session = sfactory.openSession();		
		try {
			session.beginTransaction();
			
			String hql = "select p.name,p.age from ContactPerson p where p.name like ?";
			Query query = session.createQuery(hql);
			query.setCacheable(true);
			query.setParameter(0, "%1%");
			
			//由于前一个session中已将结果集放入查询缓存,
			//对于同一个hql语句和参数,这里不会发出查询语句
			List<Object[]> cps = query.list();
			for(Object[] cp : cps) {
				System.out.println(cp[0]+","+cp[1]);
			}
			
			session.getTransaction().commit();			
		} catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		} finally {
			session.close();
		}
	}
	/**
	 * 清除查询缓存
	 */
	public void cache_query_3_02() throws Exception {
		Configuration cfg = new Configuration().configure();		
		SessionFactory sfactory = cfg.buildSessionFactory();		
		Session session = sfactory.openSession();		
		try {
			session.beginTransaction();
			
			String hql = "select p.name,p.age from ContactPerson p where p.name like ?";
			Query query = session.createQuery(hql);
			query.setCacheable(true);
			query.setParameter(0, "%1%");
			
			List<Object[]> cps = query.list();
			for(Object[] cp : cps) {
				System.out.println(cp[0]+","+cp[1]);
			}
			
			session.getTransaction().commit();			
		} catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		} finally {
			session.close();
		}
		
		//打开一个新的session
		session = sfactory.openSession();		
		try {
			session.beginTransaction();
			
			//清除查询缓存
			session.getSessionFactory().getCache().evictDefaultQueryRegion();
			
			String hql = "select p.name,p.age from ContactPerson p where p.name like ?";
			Query query = session.createQuery(hql);
			query.setCacheable(true);
			query.setParameter(0, "%1%");
			
			//由于结果集已从查询缓存中清空,这里会重新发出查询语句
			List<Object[]> cps = query.list();
			for(Object[] cp : cps) {
				System.out.println(cp[0]+","+cp[1]);
			}
			
			session.getTransaction().commit();			
		} catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		} finally {
			session.close();
		}
	}
	/**
	 * list方法也可能发生N+1问题
	 */
	public void cache_query_3_03() throws Exception {
		Configuration cfg = new Configuration().configure();		
		SessionFactory sfactory = cfg.buildSessionFactory();		
		Session session = sfactory.openSession();		
		try {
			session.beginTransaction();
			
			//查询实体对象
			String hql = "select p from ContactPerson p where p.name like ?";
			Query query = session.createQuery(hql);
			query.setCacheable(true);
			query.setParameter(0, "%1%");
			
			List<ContactPerson> cps = query.list();
			for(ContactPerson cp : cps) {
				System.out.println(cp.getId()+","+cp.getName());
			}
			
			session.getTransaction().commit();			
		} catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		} finally {
			session.close();
		}
		
		//打开一个新的session
		session = sfactory.openSession();		
		try {
			session.beginTransaction();
			//查询实体对象,使用查询缓存进行存储,则查询缓存中存放的是对象的ID列表
			//如果二级缓存没有打开,会根据ID列表发出N条查询语句---list的N+1问题
			//实际发出N条,1条为查询ID列表,但ID列表已在查询缓存中存在了
			//所以,查询实体对象,并且使用查询缓存时,必须同时使用二级缓存
			//因为,实体对象会被放到二级缓存中,查询缓存中只存放对应的ID列表
			String hql = "select p from ContactPerson p where p.name like ?";
			Query query = session.createQuery(hql);
			query.setCacheable(true);
			query.setParameter(0, "%1%");
			
			//由于结果集已从查询缓存中清空,这里会重新发出查询语句
			List<ContactPerson> cps = query.list();
			for(ContactPerson cp : cps) {
				System.out.println(cp.getId()+","+cp.getName());
			}
			
			session.getTransaction().commit();			
		} catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		} finally {
			session.close();
		}
	}
}

 

  • 大小: 59.8 KB
  • 大小: 109.6 KB
分享到:
评论

相关推荐

    hibernate配置二三级缓存

    此外,还有一些场景下会用到所谓的“三级缓存”,虽然这一术语在官方文档中并未明确提及,但在实际应用中通常指的是查询缓存之外的一种自定义缓存策略。下面将详细探讨如何在Hibernate中配置二级缓存,并简要介绍...

    hibernate一级和二级缓存配置与详解

    然后,在`hibernate.cfg.xml`配置文件中,指定缓存提供者,并开启二级缓存: ```xml &lt;property name="hibernate.cache.region.factory_class"&gt;org.hibernate.cache.ehcache.EhCacheRegionFactory &lt;property name="...

    hibernate缓存策略

    2. **配置缓存插件**:在Hibernate配置文件中指定缓存插件,并对其进行相应的配置。 3. **实体缓存配置**:为特定实体配置缓存策略,可以选择哪些实体启用缓存以及采用何种缓存策略。 #### 示例代码 假设我们想...

    《Hibernate 各类映射文件与配置文件模板》HibernateMappingConfig.zip

    《Hibernate各类映射文件与配置文件模板》是一个包含多种Hibernate映射和配置示例的压缩包,用于帮助开发者理解和使用Hibernate框架。Hibernate是Java领域的一个流行的对象关系映射(ORM)框架,它允许开发者用面向...

    springmvc4+spring4+hibernate5.1.3+二级缓存ehcache+fastjson配置

    压缩包中的"SpringMVC4.3_Spring4_Hibernate5.1.3配置文件"应该包含了所有必要的配置文件,如Spring的bean定义XML文件、Hibernate的配置文件、Web应用的部署描述符(web.xml)等,以及可能的示例代码和测试用例。...

    hibernate和struts2所需的配置文件

    此外,它还包含了Hibernate的会话工厂配置,如缓存策略、方言设置、实体类映射等。每个实体类通常还会有一个对应的`.hbm.xml`文件,这是Hibernate的映射文件,它定义了实体类与数据库表之间的映射关系,包括字段映射...

    hibernateJar包及配置文件

    - 会话工厂配置:`&lt;session-factory&gt;`元素是配置的主要部分,其中包含了许多可配置的属性,例如缓存策略、查询语言、事务隔离级别等。 - 其他配置:如方言(Dialect)、实体别名、自动创建/更新/验证数据库结构等...

    springboot+jpa(hibernate配置redis为二级缓存) springboot2.1.4

    在本文中,我们将深入探讨如何在Spring Boot 2.1.4.RELEASE项目中结合JPA(Java Persistence API)和Hibernate实现Redis作为二级...记得在实际生产环境中,根据业务需求和服务器资源合理调整缓存策略,以达到最佳性能。

    hibernate开启二级缓存和查询缓存

    2. 在 Hibernate 配置文件中启用二级缓存。 3. 在实体类上添加 `@Cacheable` 注解或者在映射文件中配置 `&lt;cache&gt;` 元素。 4. 配置实体类的缓存策略,例如使用 `@Cache(usage=CacheConcurrencyStrategy.READ_ONLY)` ...

    hibernate二级缓存java包下载

    二级缓存是 Hibernate 缓存策略的一部分,它在应用程序的多个会话之间共享数据,进一步优化了数据库访问效率。 二级缓存分为以下关键知识点: 1. **一级缓存与二级缓存的区别**: - 一级缓存:每个 Hibernate ...

    spring2.5+hibernate基于xml配置的实例

    这个"spring2.5+hibernate基于xml配置的实例"是一个经典的组合,展示了如何在旧版本的Spring(2.5)和Hibernate中通过XML配置文件来整合和管理应用的组件。 首先,Spring 2.5是Spring框架的一个早期版本,它引入了...

    Hibernate教程25_Hibernate缓存

    4. **缓存配置**:在Hibernate中,可以通过XML配置文件或注解来配置缓存。这包括设置缓存策略(读/写、非严格读/写、只读等)、指定缓存区域以及选择缓存提供商。 5. **缓存同步**:为了确保数据一致性,Hibernate...

    Spring+struts+hibernate配置文件

    这个"Spring+struts+hibernate配置文件"的压缩包,显然是为了搭建一个基于这三大框架的Java Web项目而准备的。 Spring框架是Java开发中的核心组件,它提供了强大的依赖注入(DI)和面向切面编程(AOP)功能,帮助...

    hibernate包和配置文件

    - **hibernate.cfg.xml**:这是Hibernate的主要配置文件,其中包含了数据库连接信息(如URL、用户名、密码)、JDBC驱动、缓存策略、方言设置等。例如: ```xml &lt;hibernate-configuration&gt; &lt;property name="...

    struts hibernate sprint 经典实例 配置文件的设置

    在构建一个整合Struts、Hibernate和Spring的经典实例时,配置文件的设置至关重要,因为这些配置文件定义了框架间的交互和应用的行为。以下将详细讲解这三者在配置文件中的设置: 1. **Struts配置文件**(struts-...

    Hibernate一级缓存、二级缓存以及查询缓存实例

    项目中可能包含了配置文件(如hibernate.cfg.xml),实体类,以及测试用例。通过运行测试,我们可以观察到不同缓存机制如何工作,比如一级缓存如何避免重复的数据库访问,二级缓存如何在多个Session间共享数据,以及...

    Hibernate二级缓存+分页功能

    2. 配置hibernate.cfg.xml,启用二级缓存并指定Ehcache配置文件。 3. 在实体类上添加`@Cacheable`或`@Cache`注解,声明哪些实体类或属性需要缓存。 4. 对于特定查询,可以使用`@CacheRegion`注解来定义查询结果的...

    基于hibernate的简单留言本

    1. **配置Hibernate**: 配置Hibernate的主配置文件(hibernate.cfg.xml),包括数据库连接信息、方言、缓存策略等。 2. **创建实体类和映射**: 定义实体类,并用注解或XML文件描述其与数据库的映射关系。 3. **...

    hibernate转换编码配置和权限及java代码

    在Java Web开发中,...在处理缓存时,可以使用过滤器来控制HTTP响应的缓存策略,而在ORM层面上,Hibernate的二级缓存可以优化数据库交互。理解并熟练运用这些技术,对于构建高效、安全的Java Web应用程序至关重要。

    Hibernate EhCache 二级缓存配置.docx

    Hibernate EhCache 二级缓存配置 Hibernate EhCache 二级缓存配置是 Hibernate 框架中的一种缓存机制,它可以提高应用程序的性能和效率。下面是关于 Hibernate EhCache 二级缓存配置的详细知识点: 一、简介 ...

Global site tag (gtag.js) - Google Analytics