`
schy_hqh
  • 浏览: 542343 次
  • 性别: 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常见难点.zip

    N关系时保存技巧、Hibernate缓存机制、Hibernate批量处理数据、Hibernate三种继承映射策略、hibernate映射体系、Hibernate主键生成策略、持久层DAO设计建议、基于xml文件的bean、使用HibernateAPI在Spring中、事务...

    hibernate 教程

    XML配置文件 4. 持久化类(Persistent Classes) 4.1. POJO简单示例 4.1.1. 为持久化字段声明访问器(accessors)和是否可变的标志(mutators) 4.1.2. 实现一个默认的构造方法(constructor) 4.1.3. ...

    最全Hibernate 参考文档

    3.7. XML配置文件 3.8. J2EE应用程序服务器的集成 3.8.1. 事务策略配置 3.8.2. JNDI绑定的SessionFactory 3.8.3. JTA和Session的自动绑定 3.8.4. JMX部署 4. 持久化类(Persistent Classes) 4.1. 一个简单的...

    Hibernate教程

    4.7. XML配置文件 4.8. J2EE应用程序服务器的集成 4.8.1. 事务策略配置 4.8.2. JNDI绑定的SessionFactory 4.8.3. JTA和Session的自动绑定 4.8.4. JMX部署 5. 持久化类(Persistent Classes) 5.1. 一个简单的...

    hibernate

    XML配置文件 4. 持久化类(Persistent Classes) 4.1. POJO简单示例 4.1.1. 为持久化字段声明访问器(accessors)和是否可变的标志(mutators) 4.1.2. 实现一个默认的构造方法(constructor) 4.1.3. ...

    hibernate3.04中文文档.chm

    4.7. XML配置文件 4.8. J2EE应用程序服务器的集成 4.8.1. 事务策略配置 4.8.2. JNDI绑定的SessionFactory 4.8.3. JTA和Session的自动绑定 4.8.4. JMX部署 5. 持久化类(Persistent Classes) 5.1. 一个...

    Hibernate3+中文参考文档

    3.7. XML配置文件 3.8. J2EE应用程序服务器的集成 3.8.1. 事务策略配置 3.8.2. JNDI绑定的SessionFactory 3.8.3. JTA和Session的自动绑定 3.8.4. JMX部署 4. 持久化类(Persistent Classes) 4.1. 一个简单的...

    hibernate 框架详解

    XML配置文件 4.8. J2EE应用程序服务器的集成 4.8.1. 事务策略配置 4.8.2. JNDI绑定的SessionFactory 4.8.3. JTA和Session的自动绑定 4.8.4. JMX部署 5. 持久化类(Persistent Classes) 5.1. 一个简单的...

    低清版 大型门户网站是这样炼成的.pdf

    4.2.4 hibernate的映射配置文件 201 4.2.5 体验hibernate(会员管理) 203 4.3 hibernate的映射机制 212 4.3.1 hibernate的基本映射数据类型 212 4.3.2 hibernate的主键映射 218 4.3.3 hibernate的实体映射 228...

    从J2SE到J2EE知识点介绍

    2. 通过web.xml配置文件访问servlet的流程 129 (七) servlet里面的跳转和传参数的方法 130 1. 跳转 130 2. 传参数 131 (八) jsp中文乱码问题 131 1. JSP页面乱码 132 2. 表单提交中文时出现乱码 134 3. 关于jsp在...

    工程硕士学位论文 基于Android+HTML5的移动Web项目高效开发探究

    其中使用Struts作为系统的整体基础架构,负责MVC的分离,在Struts框架的模型部分,控制业务跳转,利用Hibernate框架对持久层提供支持,Spring做管理,管理Struts和Hibernate。 WebStorage HTML新增的本地存储解决...

    Spring面试题

    类与类之间的关系主要体现在表与表之间的关系进行操作,它们都市对对象进行操作,我们程序中把所有的表与类都映射在一起,它们通过配置文件中的many-to-one、one-to-many、many-to-many、 4. 说下Hibernate的缓存...

    jdbc基础和参考

    3.hibernate的配置文件(hibernate.cfg.xml)得存在 4.POJO.hbm.xml文件存在 5.hibernate的jar包以及数据库的驱动包存在 Hibernate的编程: 1.构建Configuration对象读取配置文件 2.读取映射文件 3.构建SessionFactory...

    iBATIS实战

    9.6 确定高速缓存策略 166 9.6.1 高速缓存只读的长效数据 167 9.6.2 高速缓存可读写数据 169 9.6.3 高速缓存旧的静态数据 170 9.7 小结 172 第10章 iBATIS数据访问对象 173 10.1 隐藏实现细节 173 10.1.1 为何要...

    达内java培训目录

    持久层框架技术 ORM概念、Hibernate核心API、Hibernate实体映射技术、Hibernate关系映射技巧、HQL查询、OSCache及Hibernate缓存技术; 掌握JQuery核心API;了解JQuery基本设计原则;了解多种JQuery插件;掌握DWR的...

    NHibernate参考文档 2.0.0 chm

    3.8. XML配置文件 4. 持久化类(Persistent Classes) 4.1. 一个简单的POCO例子 4.1.1. 为持久化成员变量声明读写属性 4.1.2. 实现一个默认的构造器(constructor) 4.1.3. 提供一个标识属性(identifier property)...

    NHibernate中文帮组文档(2008.11月更新)

    3.8. XML配置文件 4. 持久化类(Persistent Classes) 4.1. 一个简单的POCO例子 4.1.1. 为持久化成员变量声明读写属性 4.1.2. 实现一个默认的构造器(constructor) 4.1.3. 提供一个标识属性(identifier property)...

    Spring 2.0 开发参考手册

    12.2.5. 基于Hibernate3的原生API实现DAO 12.2.6. 编程式的事务划分 12.2.7. 声明式的事务划分 12.2.8. 事务管理策略 12.2.9. 容器资源 vs 本地资源 12.2.10. 在应用服务器中使用Hibernate的注意点 12.3. JDO ...

    spring chm文档

    12.2.5. 基于Hibernate3的原生API实现DAO 12.2.6. 编程式的事务划分 12.2.7. 声明式的事务划分 12.2.8. 事务管理策略 12.2.9. 容器资源 vs 本地资源 12.2.10. 在应用服务器中使用Hibernate的注意点 12.3. JDO ...

    Spring-Reference_zh_CN(Spring中文参考手册)

    12.2.5. 基于Hibernate3的原生API实现DAO 12.2.6. 编程式的事务划分 12.2.7. 声明式的事务划分 12.2.8. 事务管理策略 12.2.9. 容器资源 vs 本地资源 12.2.10. 在应用服务器中使用Hibernate的注意点 12.3. JDO 12.3.1...

Global site tag (gtag.js) - Google Analytics