Hibernate一级缓存

一级缓存

一、介绍

一级缓存:又称为session级别的缓存。

当获得一次会话(session),hibernate在session中创建多个集合(map),用于存放操作数据(PO对象),为程序优化服务,

如果之后需要相应的数据,hibernate优先从session缓存中获取,如果有就使用;如果没有再查询数据库。

当session关闭时,一级缓存销毁。


一级缓存(更深层次理解Hibernate中对象的操作)
缓存:Hibernate中也存在缓存. Hibernate中存在的缓存也是用来提高效率.
Hibernate中存在两种缓存:
1.线程级别的缓存. Session缓存   
2.进程级别的缓存. Hibernate 二级缓存.
session缓存: 就是session对象中存在的缓存.缓存中存在的是(持久化)对象.

缓存中的快照: 在从数据库取得数据时, 会将数据一式两份,一份作为缓存中的对象,一份作为快照.
 在session提交时作为对比.
 
感受一级缓存的存在是否提高了效率呢?

二、一级缓存操作

1、证明一级缓存

Hibernate一级缓存_第1张图片

@Test
	public void demo02(){
		//证明一级缓存
		Session session = factory.openSession();
		session.beginTransaction();
		
		//1 查询 id = 1
		User user = (User) session.get(User.class, 1);
		System.out.println(user);
		//2 再查询 -- 不执行select语句,将从一级缓存获得
		User user2 = (User) session.get(User.class, 1);
		System.out.println(user2);
		
		session.getTransaction().commit();
		session.close();
	}


2、移除

@Test
	public void demo03(){
		//清除缓存
		Session session = factory.openSession();
		session.beginTransaction();
		
		User user = (User) session.get(User.class, 1);  //--select
		System.out.println(user);
		
		//清除
		//session.clear();
		session.evict(user);
		
		// 一级缓存没有缓存对象,从数据库直接查询
		User user2 = (User) session.get(User.class, 1);  //--select
		System.out.println(user2);
		
		session.getTransaction().commit();
		session.close();
	}


3、一级缓存快照

快照:与一级缓存一样的存放位置,对一级缓存数据备份。

保证数据库的数据与 一级缓存的数据必须一致。

如果一级缓存修改了,在执行commit提交时,将自动刷新一级缓存,执行update语句,将一级缓存的数据更新到数据库。

Hibernate一级缓存_第2张图片
缓存中的快照: 在从数据库取得数据时, 会将数据一式两份,一份作为缓存中的对象,一份作为快照.在session提交时作为对比.

Hibernate一级缓存_第3张图片

Hibernate一级缓存_第4张图片

case:

package com.itheima.b_cache;

import org.hibernate.Session;
import org.junit.Test;

import com.itheima.domain.User;
import com.itheima.utils.HibernateUtils;
//session缓存
public class Demo1 {
	@Test
	//证明session缓存的存在
	public void fun1(){
		Session session = HibernateUtils.openSession();
		session.beginTransaction();
		//------------------------------------------------
		User u1 = (User) session.get(User.class, 1);// 发送select语句,从数据库取出记录.并封装成对象
												   // 持久化状态对象=> 存到缓存中
		
		User u2 = (User) session.get(User.class, 1);//再次查询时,会从缓存中查找,不会发送select
		
		User u3 = (User) session.get(User.class, 1);//再次查询时,会从缓存中查找,不会发送select
		
		System.out.println(u1==u2);//true
		System.out.println(u1==u3);//true
		//------------------------------------------------
		session.getTransaction().commit();
		session.close(); // 游离状态
	}
	@Test
	//session缓存中的快照
	public void fun2(){
		Session session = HibernateUtils.openSession();
		session.beginTransaction();
		//------------------------------------------------
		User u1 = (User) session.get(User.class, 1);// 发送select语句,从数据库取出记录.并封装成对象
		
		session.update(u1);
		
		//------------------------------------------------
		session.getTransaction().commit();
		session.close(); // 游离状态
	}
	
	
	@Test
	//session缓存中的快照
	public void fun3(){
		Session session = HibernateUtils.openSession();
		session.beginTransaction();
		//------------------------------------------------
		User u1 = new User();
		u1.setId(1);
		u1.setName("jerry");
		u1.setPassword("1234");
		
		session.update(u1);
	
		//------------------------------------------------
		session.getTransaction().commit();
		session.close(); // 游离状态
	}
	
	
	@Test
	//感受一级缓存效率的提高
	public void fun4(){
		Session session = HibernateUtils.openSession();
		session.beginTransaction();
		//------------------------------------------------
		User u1 = (User) session.get(User.class, 1);
		
		u1.setName("tom");
		session.update(u1);
		u1.setName("jack");
		session.update(u1);
		u1.setName("rose");
		session.update(u1);
		//------------------------------------------------
		session.getTransaction().commit();
		session.close(); // 游离状态
	}
	// 持久化状态: 本质就是存在缓存中的对象,就是持久化状态.
	
	
	
}

一级缓存细节问题:

package com.itheima.b_cache;

import java.util.List;

import org.hibernate.Session;
import org.junit.Test;

import com.itheima.domain.User;
import com.itheima.utils.HibernateUtils;
//session缓存 的细节问题
public class Demo2 {
	@Test
	//1.保存对象时使用 save方法
	//  保存对象时使用 persist方法
	// 区别? 没有区别
	// persist(持久) 方法 来自于JPA 接口
	// save(保存) 方法来自于Hibernate
	public void fun1(){
		Session session = HibernateUtils.openSession();
		//session.beginTransaction();
		//------------------------------------------------
		User u = new User();
		u.setName("张三");
		
		//session.save(u); //insert语句被打印=> 目的:获得id
		session.persist(u); //
		//------------------------------------------------
		//session.getTransaction().commit();
		session.close(); // 游离状态
	}
	
	//2.1 HQL查询是否会使用一级缓存? HQL不会使用一级缓存.
	@Test
		public void fun2(){
			Session session = HibernateUtils.openSession();
			session.beginTransaction();
			//------------------------------------------------
			
			List list1 = session.createQuery("from User").list();
			
			List list2 = session.createQuery("from User").list();
			
			List list3 = session.createQuery("from User").list();
			//------------------------------------------------
			session.getTransaction().commit();
			session.close(); // 游离状态
		}
	//2.2 HQL语句批量查询时,查询结果是否会进入缓存? 查询结果会放入缓存中
		@Test
			public void fun3(){
				Session session = HibernateUtils.openSession();
				session.beginTransaction();
				//------------------------------------------------
				
				List list1 = session.createQuery("from User").list();
				
				User u = (User) session.get(User.class, 1);
				//------------------------------------------------
				session.getTransaction().commit();
				session.close(); // 游离状态
			}
		@Test
		//3.1 SQL查询 结果会不会放入1级缓存中? 如果把查询结果封装到对象中,对象会放入一级缓存
		public void fun4(){
			Session session = HibernateUtils.openSession();
			session.beginTransaction();
			//------------------------------------------------
			
			List list1 = session.createSQLQuery("select * from t_user").addEntity(User.class).list();
			
			User u = (User) session.get(User.class, 1);
			
			System.out.println(u);
			//------------------------------------------------
			session.getTransaction().commit();
			session.close(); // 游离状态
		}	
		@Test
		//3.2 SQL查询 结果会不会放入1级缓存中?没有把查询结果封装到对象中,对象不会放入一级缓存
		public void fun5(){
			Session session = HibernateUtils.openSession();
			session.beginTransaction();
			//------------------------------------------------
			
			List list1 = session.createSQLQuery("select * from t_user").list();
			
			User u = (User) session.get(User.class, 1);
			
			System.out.println(u);
			//------------------------------------------------
			session.getTransaction().commit();
			session.close(); // 游离状态
		}	
		
		//criteria => 会将查询结果放入一级缓存. 但是查询不会使用一级缓存. 与Hql查询结论一致.
}

save 和 persist 方法细节:

package com.itheima.c_question;

import java.util.List;

import org.hibernate.Session;
import org.junit.Test;

import com.itheima.domain.User;
import com.itheima.utils.HibernateUtils;

//1 save 和 persist 方法 对比之后,没有区别?
public class Demo1 {
	@Test
	public void fun1(){
		Session session = HibernateUtils.openSession();
		session.beginTransaction();
		//------------------------------------------------
		User u = new User();
		
		u.setId(99);
		
		session.persist(u); 
		// 体现的是持久化. persist提供的理念是将对象完整的持久化. 持久化也包括对象的ID.
		// 在保存之前设置了ID.那么就会将设置的ID进行insert. 但是 主键策略是由数据库来维护. 所以产生矛盾.所以抛出异常.
		//------------------------------------------------
		session.getTransaction().commit();
		session.close(); // 游离状态
	}
	@Test
	public void fun2(){
		Session session = HibernateUtils.openSession();
		session.beginTransaction();
		//------------------------------------------------
		User u = new User();
		
		u.setId(99);
		
		session.save(u); // save方法,如果保存的对象在保存之前设置了ID.那么该ID也被认为是无效的ID.
		System.out.println(u.getId());
		//------------------------------------------------
		session.getTransaction().commit();
		session.close(); // 游离状态
	}
}


Hql查询细节:

package com.itheima.c_question;

import java.util.List;

import org.hibernate.Session;
import org.junit.Test;

import com.itheima.domain.User;
import com.itheima.utils.HibernateUtils;

//2 Hql查询,查询结果会放入Session一级缓存中.但是每次调用Hql查询都会生成Sql语句?
// 并不代表 Hql没有使用1级缓存. 
public class Demo2 {
	@Test
	public void fun1(){
		Session session = HibernateUtils.openSession();
		session.beginTransaction();
		//------------------------------------------------
		List list1 = session.createQuery("from User").list(); // 发送sql
		
		List list2 = session.createQuery("from User").list();// 发送sql
		
		System.out.println(list1.get(0)==list2.get(0));//true =>  
		//------------------------------------------------
		session.getTransaction().commit();
		session.close(); // 游离状态
	}
	//问题: 缓存中的数据如果与数据库中的不同步,会怎么样?
	// 会优先使用缓存中的. 使用JDBC
	// 在一级缓存中出现该问题的几率比较小.
	//openSession==> 一级缓存生命周期开始
	//session.close();=> 一级缓存销毁
	@Test
	public void fun2(){
		Session session = HibernateUtils.openSession();
		session.beginTransaction();
		//------------------------------------------------
		
		User u1 = (User) session.get(User.class, 1);
		
		User u2 = (User) session.get(User.class, 1);
		
		//------------------------------------------------
		session.getTransaction().commit();
		session.close(); // 游离状态
	}
}

过程:

Hibernate一级缓存_第5张图片

4、refresh刷新

refresh 保证 一级缓存的数据 与 数据库的数据 保持一致。

将执行select语句查询数据库,将一级缓存中的数据覆盖掉。只要执行refresh都将执行select语句。

@Test
	public void demo04(){
		//刷新
		Session session = factory.openSession();
		session.beginTransaction();
		
		User user = (User) session.get(User.class, 1);  //--select
		System.out.println(user);
		
		session.refresh(user);
		
		session.getTransaction().commit();
		session.close();
	}


5、快照演示(一级缓存刷新)

@Test
	public void demo05(){
		//快照
		Session session = factory.openSession();
		session.beginTransaction();
		
		User user = (User) session.get(User.class, 1);  //--select
		System.out.println(user);
		
		//修改持久态对象内容(一级缓存内容)--默认在commit时,将触发update语句。
		user.setUsername("rose2");
		
		
		session.getTransaction().commit();
		session.close();
	}

l  问题:一级缓存什么时候刷新?(了解)

       默认情况提交(commit())刷新。

@Test
	public void demo06(){
		//设置刷新时机
		Session session = factory.openSession();
		session.beginTransaction();
		
		//1 设置
		session.setFlushMode(FlushMode.MANUAL);
		
		User user = (User) session.get(User.class, 1);
		user.setUsername("rose4");
		
		//1 查询所有 -- AUTO , 查询之前先更新,保存一级缓存和数据库一样的
		//List allUser = session.createQuery("from User").list();
		
		//2手动刷新 --MANUAL 将执行update,注意:一级缓存必须修改后的
		session.flush();
		
		// 如果MANUAL 在执行commit 不进行update
		session.getTransaction().commit();
		session.close();
	}




三、PO对象操作

1、save&persist

l  save方法:瞬时态 转换持久态 ,会初始化OID

              1.执行save方法,立即触发insert语句,从数据库获得主键的值(OID值)

              2.执行save方法前,设置OID将忽略。

              3.如果执行查询,session缓存移除了,在执行save方法,将执行insert

	@Test
	public void demo01(){
		User user = new User();	
		user.setUid(100);
		user.setUsername("jack");
		user.setPassword("1234");
		
		Session session = factory.openSession();
		session.beginTransaction();
		
		
		session.save(user);
		
		
		session.getTransaction().commit();
		session.close();
	}

@Test
	public void demo03(){
		//代理  assigned
		User user = new User();	
		//user.setUid(100);
		user.setUsername("jack");
		user.setPassword("1234");
		
		Session session = factory.openSession();
		session.beginTransaction();
		
		
		session.save(user);
		
		
		session.getTransaction().commit();
		session.close();
	}

l  注意:持久态对象不能修改OID的值

Hibernate一级缓存_第6张图片

@Test
	public void demo04(){
		
		Session session = factory.openSession();
		session.beginTransaction();
		
		
		User user = (User) session.get(User.class, 100);
		user.setUid(101);
		
		session.save(user);
		
		session.getTransaction().commit();
		session.close();
	}

l  persist方法:瞬时态 转换 持久态 ,不会立即初始化OID

注意: persist方法不会立即得到ID,所以执行sql语句的时机要靠后.



2、update

l  update:脱管态 转换持久态

       如果OID在数据存放的,将执行update语句

       如果OID不存在将抛异常

@Test
	public void demo01(){
		//自然 assigned
		User user = new User();	
		user.setUid(101);
		user.setUsername("jack1");
		user.setPassword("12345");
		
		Session session = factory.openSession();
		session.beginTransaction();
		
		
		session.update(user);
		
		
		session.getTransaction().commit();
		session.close();
	}

l  注意1:如果数据没有修改,执行save方法,将触发update语句。

       查询速度 比 更新速度快

       通过来设置更新前先查询,如果没有改变就不更新。

Hibernate一级缓存_第7张图片

总结:

       update之后对象 持久态

@Test
	public void demo03(){
		// merge 合并
		User user = new User();	
		user.setUid(1);
		user.setUsername("jack3");
		user.setPassword("12345");
		
		Session session = factory.openSession();
		session.beginTransaction();
		
		
		// 1 oid =1 持久态对象
		User user2 = (User) session.get(User.class, 1);
		
//		session.update(user);
		session.merge(user);
		
		
		session.getTransaction().commit();
		session.close();
	}



3、saveOrUpdate

l  代理主键:

       判断是否有OID

              如果没有OID,将执行insert语句

              如果有OID,将执行update语句。
@Test
	public void demo02(){
		// 代理 native
		User user = new User();	
//		user.setUid(2);
		user.setUsername("jack2");
		user.setPassword("12345");
		
		Session session = factory.openSession();
		session.beginTransaction();
		
		
		session.saveOrUpdate(user);
		
		
		session.getTransaction().commit();
		session.close();
	}

l  自然主键:

       先执行select语句,查询是否存放

       如果不存在,将执行insert

       如果存在,将执行update

@Test
	public void demo02(){
		// 自然 assigned
		User user = new User();	
		user.setUid(2);
		user.setUsername("jack2333");
		user.setPassword("12345333");
		
		Session session = factory.openSession();
		session.beginTransaction();
		
		
		session.saveOrUpdate(user);
		
		
		session.getTransaction().commit();
		session.close();
	}

l  注意1:native下,默认OID是否存在,使用默认值。例如:Integer 默认null

       通过 修改使用默认值,如果设置1进行insert语句。此内容提供hibernate使用的,录入到数据库后,采用自动增长。

Hibernate一级缓存_第8张图片


4、delete

总结:

PO对象状态:瞬时态、持久态、脱管态

Hibernate一级缓存_第9张图片

case:
其他的api:
package com.itheima.d_api;

import java.util.List;

import org.hibernate.Session;
import org.junit.Test;

import com.itheima.domain.User;
import com.itheima.utils.HibernateUtils;
//其他API (大部分都是了解)
public class Demo1 {
	@Test
	//1. evict 将缓存中的对象移除.
	//2. clear 清空1级缓存 
	public void fun1(){
		Session session = HibernateUtils.openSession();
		session.beginTransaction();
		//------------------------------------------------
		User u1 = (User) session.get(User.class, 1);
		
		session.clear();
		
		User u2 = (User) session.get(User.class, 1);
		
		//------------------------------------------------
		session.getTransaction().commit();
		session.close(); // 游离状态
	}
	@Test
	//3 refresh 刷新 => 强制刷新缓存中的对象 => (可以用来解决缓存与数据库数据不同步的问题)
	public void fun2(){
		Session session = HibernateUtils.openSession();
		session.beginTransaction();
		//------------------------------------------------
		User u1 = (User) session.get(User.class, 1);
		
		session.refresh(u1); //将缓存中的对象立刻与数据库同步,会再发送一个sql语句
		//------------------------------------------------
		session.getTransaction().commit();
		session.close(); // 游离状态
	}
	@Test
	//4 flush 对比快照,并提交缓存对象
	public void fun3(){
		Session session = HibernateUtils.openSession();
		session.beginTransaction();
		//------------------------------------------------
		User u1 = (User) session.get(User.class, 1);
		
		u1.setName("zhangsan");
		
		session.flush();// 立刻提交session缓存中的对象到数据库
		
		//------------------------------------------------
		session.getTransaction().commit();
		session.close(); // 游离状态
	}
	
	@Test
	// 代理主键=> native
	//5.1 saveOrUpdate方法
	//saveOrUpdate 可以同时完成保存或更新操作
	//主键为空=>save
	//主键有值=> update
	public void fun4(){
		Session session = HibernateUtils.openSession();
		session.beginTransaction();
		//------------------------------------------------
		User u = new User();
		u.setId(99);
		u.setName("jack");
		u.setPassword("1234");
		
		session.saveOrUpdate(u);
		//------------------------------------------------
		session.getTransaction().commit();
		session.close(); // 游离状态
	}
	
	// 自然主键=> assigned
	//5 update 与 saveOrUpdate方法
		//saveOrUpdate 可以同时完成保存或更新操作
		//主键为空=> 报错,因为无论是save还是update 都必须指定id
		//主键有值=> 先会根据主键查询数据库.
				// 数据库中存在=> 执行update
				// 数据库中不存在=> 执行insert
	@Test
		public void fun5(){
			Session session = HibernateUtils.openSession();
			session.beginTransaction();
			//------------------------------------------------
			User u = new User();
			u.setId(88);
			u.setName("jack01");
			u.setPassword("1234");
			
			session.saveOrUpdate(u);
			//------------------------------------------------
			session.getTransaction().commit();
			session.close(); // 游离状态
		}
	
	
	@Test
	//在我们使用Hibernate时候,注意要避免出现,两个相同的ID对象.放入一级缓存的情况.
	public void fun6(){
		Session session = HibernateUtils.openSession();
		session.beginTransaction();
		//------------------------------------------------
		User u = (User) session.get(User.class, 1);// 持久化,缓存中存在
		
		session.evict(u); // 游离态,缓存中不存在
		
		User u2 = (User) session.get(User.class, 1);// 持久化,缓存中存在
		
		session.update(u); // 将U重新变为持久化状态,缓存中存在
		//------------------------------------------------
		session.getTransaction().commit();
		session.close(); // 游离状态
	}
}






你可能感兴趣的:(JavaEE,hibernate)