一、Hibernate中的对象状态

  1.1、瞬时态(临时态)

    没有与Hibernate产生关联

    与数据库中的记录没有产生关联(有关联就是与数据库中表的id相对应)   

      获得:一般都只直接创建(new)
      瞬时态 转换 持久态
        一般操作:save方法、saveOrUpdate
      瞬时态 转换 脱管态
        一般操作:通过setId方法设置数据

   1.2、持久态

    Hibernate有关联

    对象有id

      获得:
        查询操作:get、loat、createQuery、createCriteria 等 获得都是持久态【】
        执行save之后持久态
        执行update之后持久态
      持久态 转换 瞬时态
        官方规定执行delete() --民间:删除态
      持久态 转换 脱管态
        session没有记录
        session.close () 关闭
        session.clear() 清除所有
        session.evict(obj) 清除指定的PO对象

  1.3、游离态(脱管态)

    没有与Hibernate产生关联

    对象有ID

      获得:
        创建、并设置OID的
        通过api获得
      脱管态 转换 瞬时态
        手动去除OID,设置成默认值
      脱管态 转换 持久态
        一般操作:update()、saveOrUpdate

  1.4、在代码中去查看三种状态

    

  1.5、三种状态的相互转换

    1.5.1、瞬时转化为持久

    

      注意:如果主键生成策略中value是assigned需要自己指定主键,不指定会报错。

    1.5.2、瞬时转化为游离  

        在数据库中id=1中已经存在有

        

        

    1.5.3、持久转化为瞬时

      

      方式二:

          

    1.5.4、持久转化为游离

      

    1.5.5、游离转化为瞬时

      

    1.5.6、游离转化为持久

      

  1.6、三种状态有什么用处?

    持久状态,我们使用Hibernate主要是为了持久化我们的数据.

    对于对象的状态,我们期望我们需要同步到数据库的数据,都被装换成持久状态

    持久化状态特点: Hibernate会自动将持久化状态对象的变化同步到数据库中.  

    

二、一级缓存

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

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

  在Hibernate中存在两种缓存:一是线程级别的缓存(session缓存)二是进程级别的缓存(二级缓存)

  缓存:用来提高效率的

    session缓存:就是session对象中存在的缓存,缓存中存在的是(持久化)对象。

  2.1、证明session缓存的存在

    

    我们用图形来理解:

      

  2.2、一级缓存快照

        在从数据库取数据时,会将数据一式两份,一份作为缓存中的对象,一份作为快照,在session提交时做对比。

      快照:与一级缓存一样的存放位置,对一级缓存数据备份。保证数据库的数据与 一级缓存的数据必须一致。如果一级缓存修改了,

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

        

 

          

    举例:

      

    我们画图来分析一下: 

          

        

      持久化状态: 本质就是存在缓存中的对象,就是持久化状态.

  2.3、感受一级缓存带来的效率

      感受一:

    

      从上面这三行代码中,我们u1执行需要执行一条sql语句,我们执行得到u2和u3时,发现不会去再次查询,而是从缓存中找。

      感受二:

        

        从上面代码还在那个我们知道,第一个u1中会执行select语句。当事务还没有提交的时候,只会在缓存中进行。

        所以总的只会产生两条sql语句。

  2.4、一级缓存中的细节问题

    问题一:保存对象时,可以使用save方法和persist方法,他们之间有区别吗?

        没有区别,功能上是一样的。但persist(持久) 方法 来自于JPA 接口。而save(保存) 方法来自于Hibernate。

    问题二:HQL查询是否会使用一级缓存?

        HQL不会使用一级缓存.

    

    问题三:HQL语句批量查询时,查询结果是否会进入缓存?

        查询结果会放入缓存中

    

    问题四:SQL查询 结果会不会放入1级缓存中?

        如果把查询结果封装到对象中,对象会放入一级缓存

      

    问题五:SQL查询 结果会不会放入1级缓存中?

        没有把查询结果封装到对象中,对象不会放入一级缓存

          

    问题六:criteria  会将查询结果放入一级缓存. 但是查询不会使用一级缓存. 与Hql查询结论一致.    

三、session中的其他API

    evict()方法:将缓存中的对象删除

    clear()方法:清空一级缓存

    refresh方法:刷新,强制刷新缓存中的对象 => (可以用来解决缓存与数据库数据不同步的问题)

    

    flush方法:对比快照,并提交缓存对象

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 aveOrUpdate方法
    //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(); // 游离状态
    }
}
testSessionApi