Hibernate的一级缓存

1.Hibernate的一级缓存的生命周期就是session的生命周期。

2.一级缓存存放的数据都是私有数据,不共享的。(因为session是存放在threadloacl中,不同的线程是不能访问的,所以保证了数据的安全性)

3.session.save(),update(),load(),get()方法会将数据库的数据存放在session一级的缓存中。

4.session.get()和load()可以获取到session一级缓存中的数据。

5.session.evict方法可以将一个指定缓存对象,从session的一级缓存中去除。

6.session.clear可以把session的一级缓存中的所有数据清空

7.session.refresh(obj)可以将指定对象数据从数据库更新到session的一级缓存中。

8.session.flush

          在session的缓存内部,会去检查所有的持久化对象
           1、如果一个持久化对象没有ID值,则会发出insert语句
           2、如果一个持久化对象有ID值,则会根据这个ID去快照中ID和此ID一样的数据进行对比,如果其他一样,则什么都不做,如果其他不一样,则发出update语句
           3、 检查所有的持久化对象是否有关联对象
                  检查关联对象的级联操作(cascade)
                  检查关联对象的关系操作(inverse)

9.在进行大批量操作的时候:

(1)当数据到某一个值的时候需要手动flush,否则内存会溢出

(2)session.flush方法并不会clear掉session中一级缓存的缓存数据,所以,在大批量操作的时候,手动flush后必须要紧跟手动clear操作。


public class One2ManyTest {
	private static SessionFactory sessionFactory;
	
	static{
		Configuration con = new Configuration().configure();
		sessionFactory = con.buildSessionFactory();
	}
	
	/**
	 * 测试load方法将数据放入一级缓存
	 * 只发出一条sql,从而可以得出一个结论:
	 * 		当get操作的时候,hibernate将查询出来的数据放到了sesseion的一级缓存中,因为当第二次执行同样的查询操作的时候,是不会进行sql操作了,但还是能拿到数据
	 * Hibernate: select student0_.sid as sid1_0_, student0_.sname as sname1_0_, student0_.description as descript3_1_0_, student0_.cid as cid1_0_ from Student student0_ where student0_.sid=?
	 */
	@Test
	public void testLoad(){
		Session session = sessionFactory.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		//由这句话发出sql语句
		Student stu = (Student) session.load(Student.class, 1L);
		System.out.println(stu.getSname());
		stu = (Student) session.load(Student.class, 1L);
		
		transaction.commit();
		//不需要seesion.close();因为是从当前线程获取到的session,它会在事务提交的时候自动关闭session
	}
	
	
	/**
	 * 测试get方法将数据放入一级缓存
	 * 只发出一条sql,从而可以得出一个结论:
	 * 		当load操作的时候,hibernate将查询出来的数据放到了sesseion的一级缓存中,因为当第二次执行同样的查询操作的时候,是不会进行sql操作了,但还是能拿到数据
	 * Hibernate: select student0_.sid as sid1_0_, student0_.sname as sname1_0_, student0_.description as descript3_1_0_, student0_.cid as cid1_0_ from Student student0_ where student0_.sid=?
	 */
	@Test
	public void testGet(){
		Session session = sessionFactory.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		//由这句话发出sql语句
		Student stu = (Student) session.get(Student.class, 1L);
		System.out.println(stu.getSname());
		stu = (Student) session.get(Student.class, 1L);
		
		transaction.commit();
		//不需要seesion.close();因为是从当前线程获取到的session,它会在事务提交的时候自动关闭session
	}
	
	
	/**
	 * 测试save方法将数据放入一级缓存
	 * 		先保存一条数据,然后将刚才保存的数据查询出来,如果发生了查询的sql,那就表示数据没进缓存,反之,则代表数据存入了缓存
	 */
	@Test
	public void testSave(){
		Session session = sessionFactory.getCurrentSession();
		Transaction transaction = session.beginTransaction();
	
		Student s = new Student();
		s.setSname("save学生");
		s.setDescription("save");
		session.save(s);
		/*
		 * 注意:
		 * 	如果这里s = (Student) session.load(Student.class, 1L);
		 *  还是会发出sql语句进行查询操作
		 */
		s = (Student) session.load(Student.class, s.getSid());
		System.out.println(s.getSname());
		
		transaction.commit();
	}
	
	/**
	 * 测试update方法将数据放入一级缓存(用evict将对象从session的一级缓存中情况)
	 * 		先查询条数据(由于查询的时候会将查询的结果放入到session的一级缓存中),手动将查询出来的对象从session的一级缓存中删除
	 * 		将查询出来的对象进行update操作,再进行次update那个对象的查询操作,如果此时没有发出sql语句,则表示update操作将对象放入了session的一级缓存中
	 * Hibernate: select student0_.sid as sid1_0_, student0_.sname as sname1_0_, student0_.description as descript3_1_0_, student0_.cid as cid1_0_ from Student student0_ where student0_.sid=?
	 * Hibernate: update Student set sname=?, description=?, cid=? where sid=?
	 */
	@Test
	public void testUpdate_evict(){
		Session session = sessionFactory.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		//由于get方法会将查询出来的数据放在session的一级缓存里,所以我们要清除这个对象
		Student s = (Student) session.get(Student.class, 1L);
		s.setDescription("改变");
		
		session.evict(s);//student对象从session缓存中清空了

		session.update(s);//update操作将student对象放入了session的一级缓存中
		s = (Student) session.get(Student.class, 1L);//这里就没有进行查询的sql操作
		System.out.println(s.getDescription());
		
		transaction.commit();//由于之前清空了一级缓存,session.update(s);操作的时候,发现缓存没有可以对比的对象,所以这里会进行update的sql操作
	}
	
	/**
	 * 测试update方法将数据放入一级缓存(用clear将session的一级缓存中所有缓存的对象清空)
	 * 		先查询条数据(由于查询的时候会将查询的结果放入到session的一级缓存中),手动将查询出来的对象从session的一级缓存中删除
	 * 		将查询出来的对象进行update操作,再进行次update那个对象的查询操作,如果此时没有发出sql语句,则表示update操作将对象放入了session的一级缓存中
	 * 
	 * Hibernate: select student0_.sid as sid1_0_, student0_.sname as sname1_0_, student0_.description as descript3_1_0_, student0_.cid as cid1_0_ from Student student0_ where student0_.sid=?
	 * Hibernate: update Student set sname=?, description=?, cid=? where sid=?
	 */
	@Test
	public void testUpdate_clear(){
		Session session = sessionFactory.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		//由于get方法会将查询出来的数据放在session的一级缓存里,所以我们要清除这个对象
		Student s = (Student) session.get(Student.class, 1L);
		s.setDescription("改变");
		
		session.clear();
		session.update(s);//update操作将student对象放入了session的一级缓存中
		
		s = (Student) session.get(Student.class, 1L);//这里就没有进行查询的sql操作
		System.out.println(s.getDescription());
		
		transaction.commit();//由于之前清空了一级缓存,session.update(s);操作的时候,发现缓存没有可以对比的对象,所以这里会进行update的sql操作
	}
	
	@Test
	public void testEquality_OID_ERROR(){
		Session session = sessionFactory.getCurrentSession();
		Transaction transaction = session.beginTransaction();

		Student s_get = (Student) session.get(Student.class, 1L);
		s_get.setDescription("改变");
		
		session.clear();
		
		Student s_new = new Student();
		s_new.setSid(1L);
		s_new.setSname("new_stu");
		s_new.setDescription("newStudent");
		
		/*
		 * 注意:
		 * 		* 如果这里是save的话,由于主键生成策略是identity,所以hibernate会无视s_new.setSid(1L);而用指定的方式生成主键,所以不会在session中出现两个id相同的情况而出现以下异常
		 * 		* 如果这里是update的话,由于之前已经进行了session.get(Student.class, 1L);所以在session的一级缓存里是有这个对象的
		 *        此时将新new的一个对象的id设值为1L,并将其进行update操作,势必造成session的一级缓存中出现了两个ID相同的对象,hibernate是不允许这种情况出现的,所以会出以下异常
		 *        org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.xxc.one2many_bothway.Student#1]
		 *        
		 * 解决办法:
		 * 		*将之前load方法查询出来的student对象从session的一级缓存中清除    可以用session.evict(s);或session.clear();
		 */
		//在这句代码前,s_new是一个临时状态对象
		session.update(s_new);
		
		transaction.commit();//由于之前清空了一级缓存,session.update(s);操作的时候,发现缓存没有可以对比的对象,所以这里会进行update的sql操作
	}
	
	/**
	 * 将指定数据从数据库刷新到session的一级缓存中
	 */
	@Test
	public void testRefresh(){
		Session session = sessionFactory.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		Student s_get = (Student) session.get(Student.class, 1L);
		s_get.setDescription("哈哈");
		
		session.refresh(s_get);
		System.out.println(s_get.getDescription());
		
		transaction.commit();
	}
	
	/**
	 * 将指定数据从一级缓存同步到数据路中
	 * 注意:
	 * 		session.flush()只是发出sql语句操作,但是并没有将缓存中的对象清空
	 */
	@Test
	public void testFlush(){
		Session session = sessionFactory.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		Student s_get = (Student) session.get(Student.class, 1L);
		s_get.setDescription("哈哈");
		
		session.flush();//例如insert和update语句都是在这句代码执行的时候才发出的,而不是commit执行的时候发出
		
		s_get = (Student) session.get(Student.class, 1L);//经过测试发现,flush并不回清空session中一级缓存的内容,因为这句代码没有发出sql语句
		
		
		transaction.commit();
	}
	
	/**
	 * 大批量数据操作
	 */
	@Test
	public void testBatch(){
		Session session = sessionFactory.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		/*这段话要是写在上边,实际保存的次数只有100000/100=1000次
		 * Student stu = new Student();
		 *	stu.setSname("1");
		 *	stu.setDescription("haha");
		 */
		
		
		for(int i=0;i<=100000;i++){
			//如果保存的是同一个对象,对象的创建要写在下边,否则hibernate的session的一级缓存中已经有了该对象,
			//所以不会每一次都执行保存操作,只有session.flush();session.clear();才会执行,所以以上这种写法只会保存1000次
			Student stu = new Student();
			stu.setSname("1");
			stu.setDescription("haha");
			session.save(stu);
			//批量操作的时候,一定要这么来,到一定数量就刷新给数据库,否则内存要溢出
			if(i%100==0){
				session.flush();
				session.clear();
			}
		}
		//最后还要刷一次,否则可能因为总次数没能被100整除,剩下的数据没能被保存
		session.flush();
		session.clear();
		
		transaction.commit();
	}
	
	
	/**
	 * 插入
	 */
	@Test
	public void testSaveStudent_Cascade_SaveClass(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		
		Student stu = new Student();
		stu.setSname("xxc1");
		stu.setDescription("1");
		
		Set<Student> stus = new HashSet<Student>();
		stus.add(stu);
		
		Class clzz = new Class();
		clzz.setCname("浙江大学一院");
		clzz.setDescription("1");
		clzz.setStudents(stus);
		
		//保存班级,级联保存学生
		session.save(clzz);
		
		transaction.commit();
		session.close();
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值