一级缓存:又称为session级别的缓存。
当获得一次会话(session),hibernate在session中创建多个集合(map),用于存放操作数据(PO对象),为程序优化服务,
如果之后需要相应的数据,hibernate优先从session缓存中获取,如果有就使用;如果没有再查询数据库。
当session关闭时,一级缓存销毁。
@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();
}
@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();
}
快照:与一级缓存一样的存放位置,对一级缓存数据备份。
保证数据库的数据与 一级缓存的数据必须一致。
如果一级缓存修改了,在执行commit提交时,将自动刷新一级缓存,执行update语句,将一级缓存的数据更新到数据库。
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(); // 游离状态
}
}
过程:
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();
}
@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();
}
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的值
@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语句的时机要靠后.
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语句。
查询速度 比 更新速度快
通过
总结:
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();
}
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
通过
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(); // 游离状态
}
}