hibernate入门(二)一级缓存和三种状态解析

 

先理解了hibernate的一级缓存和它的三种状态,才能对后面我要讲解的一对多,一对一、多对多这种映射关系更好的理解.

 

目录:

  1.hibernate的缓存和快照(有些说法没有快照概念)

  2.常用的方法理解 

  3.hibernate的三或四种状态

 

1. session是有一个缓存,又叫hibernate的一级缓存. session缓存是有一系列java集合构成的,当一个对象被加入到session缓存中,对象的引用就加入到java的集合中, 以后即使应用程序的引用变量中不在引用改对象,只要session缓存不被清空,这个对象一直处于生命周期中.

hibernate需要和数据库打交道,是通过session获得缓存中的关联对象,然后拼接成相应的sql再执行.

 

具体过程:

1)、首先session将一个对象加入自己的管理范围内,其实也就是把该对象放入自己的一级缓存中。如,session.get(xxx);这个语句就是将xxx保存在自己的一级缓存中,等待事务提交后,hibernate才真正的发sql语句,操作数据库。

 

2)、在一级缓存中会做些什么事情呢?为什么能够知道是发insert、还是update又或者delete呢?讲讲内部是什么原理。那这里就要提到一个快照的概念了,讲讲内部是什么原理。

 

 

package com.cc8w;

import java.util.Date;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.cc8w.entity.UserEntity;

/**
 * 主要是hibernate缓存的配置
 * @author Administrator
 * session是有一个缓存,又叫hibernate的一级缓存
 * session缓存是有一系列java集合构成的,当一个对象被加入到session缓存中,对象的引用就加入到java的集合中,
 * 以后即使应用程序的引用变量中不在引用改对象,只要session缓存不被清空,这个对象一直处于声明周期中.
 */
public class AppTest {
   
    private Configuration configuration=null;
    private SessionFactory sessionFactory=null;
    private Session session=null;
    private Transaction transaction=null;
    
    @Before
    public void beforeTest() {
        System.out.println("beforeTest");
        
        //1. 加载Hibernate的核心配置文件
        configuration = new Configuration().configure();
        //如果在Hibernate的核心配置文件没有设置加载哪个映射文件,则可手动加载映射文件
        //configuration.addResource("com/cc8w/mapper/UserMapper.hbm.xml");
        
        //2. 创建SessionFactory对象,类似于JDBC中的连接池
        sessionFactory = configuration.buildSessionFactory();
        
        //3. 通过SessionFactory获取到Session对象,类似于JDBC中的Connection
        session = sessionFactory.openSession();
        
        //4. 手动开启事务,(最好是手动开启事务)
        transaction = session.beginTransaction();
        
        //5.执行语句写在测试方法里面
    }
    @After
    public void afterTest() {
        System.out.println("afterTest");
        //6. 事务提交
        transaction.commit();    
        //7. 释放资源
        session.close();
        sessionFactory.close();
    }
    
    @Test
    public void TestCache() {
        UserEntity user = new UserEntity();
        user.setCname("123");
        user.setUserName("李123");
        user.setCreateTime(new Date());
        
        session.save(user);//加入了一级缓存中,提交事务时insert操作
        
        user.setCname("789");
        user.setUserName("李789");//将快照区域的属性值修改,和一级缓存对比,不一样将发起update
        /**
         * 在session将user加入一级缓存时,一级缓存和快照区域是一样的,当user改变自己的username属性时,此时将快照区中的user的username属性改变了,
         * 在事务提交时,会发送insert插入语句,因为使用了session的save语句,将一级缓存中的数据增加到数据库,然后再通过快照区和一级缓存做对比,
         * 如果不一样的地方,那么就会在发送一个update语句更新,(注意,除了id属性外,其他属性改变会发送update语句,id属性改变,就会报异常.)
         */
    }
}

 

 如果没有快照概念这样理解:

如果一个对象以及是持久化状态了,那么此时对该对象进行各种修改,或者调用多次update、save方法时,hibernate都不会发送sql语句,只有当事物提交的时候,此时hibernate才会拿当前这个对象与之前保存在session中的持久化对象进行比较,如果不相同就发送一条update的sql语句,否则就不会发送update语句。

 发送的sql语句:

Hibernate: 
    insert 
    into
        t_admins
        (username, password, cname, email, create_time, last_time) 
    values
        (?, ?, ?, ?, ?, ?)

Hibernate: 
    update
        t_admins 
    set
        username=?,
        password=?,
        cname=?,
        email=?,
        create_time=?,
        last_time=? 
    where
        id=?

 

 session.get()

    @Test
    public void getUser() {
        //发起select查询,并存到session一级缓存,给快照去复制一份
        UserEntity user = session.get(UserEntity.class,6);
        //修改了快照区,会发出update语句。
        user.setCname("李1112");
        
    }

分析图

 sql:

Hibernate: 
    select
        userentity0_.id as id1_0_0_,
        userentity0_.username as username2_0_0_,
        userentity0_.password as password3_0_0_,
        userentity0_.cname as cname4_0_0_,
        userentity0_.email as email5_0_0_,
        userentity0_.create_time as create_t6_0_0_,
        userentity0_.last_time as last_tim7_0_0_ 
    from
        t_admins userentity0_ 
    where
        userentity0_.id=?
afterTest
Hibernate: 
    update
        t_admins 
    set
        username=?,
        password=?,
        cname=?,
        email=?,
        create_time=?,
        last_time=? 
    where
        id=?

 

 2. 通过几个方法来深刻理解下缓存: 

1) session.evict() :会把指定的缓冲对象进行清除;

2) session.flush()的作用就是将session的缓存中的数据与数据库同步。(也就是不用事务提交缓存就刷出来了,就会发sql语句,事务提交也是一个刷出缓存的方法,)

3) session.clear()的作用就是清除session中的缓存数据(不管缓存与数据库的同步)。

4)session.refresh():会强制发送select语句,以使session缓存中对象的状态和数据表中对应的记录保持一致。该方法的有效性需要配置事务的隔离级别为read commited(读已提交)。

 

 

session.evict()

    @Test
    public void testEvict() {
        //发起select查询,并存到session一级缓存,给快照去复制一份
        UserEntity user = session.get(UserEntity.class,6);
        //将user从session一级缓存中移除(快照区域没删)
        session.evict(user);
        
        //这里不会发送update语句(快照区域和缓存对比,发现无此实例,就什么也不做)
        user.setCname("李1118");
        
    }

 

 

 

 3.     Hibernate 的三种实体状态  (下一篇 )

 

 Hibernate有三种实体状态,有瞬时态(transiant),持久态(persistent),游离态(detached)。 简单理解就是,瞬时态指的是刚New 新建的一个对象,没有放在Session时,也没有存储在数据库中。 持久态,指这个对象存储在数据库中,并且存在于Session会话中。 而游离态指的是,这个对象存储在数据库中,但已经不存在于Session会话中。下面是比较官方的说法:

 

 

 

转 参考: https://www.cnblogs.com/whgk/p/6103038.html

 https://www.cnblogs.com/yjhrem/articles/2374818.html

三种状态的解析: https://blog.csdn.net/yjltx1234csdn/article/details/83214978

 

posted @ 2020-12-24 11:30  与f  阅读(152)  评论(0编辑  收藏  举报