Session 缓存和持久化生命周期以及Session 基本操作3

Session缓存原理

为了能够在控制台更好的看到我们的hibernate干了些什么,可以在hibernate.cfg.xml文件中写入如下配置: 

<!-- print all generated SQL to the console -->
        <property name="hibernate.show_sql">true</property>
        
        <!-- format SQL in log and console -->
        <property name="hibernate.format_sql">true</property>
在上一篇中,我们就曾说:Session在hibernate中被称为一级缓存,Session接口的原理:
  1. 当应用程序调用Session的CRUD方法、以及调用查询接口的list()、iterate()或filter()方法时,如果在Session缓存中还不存在相应的对象,Hibernate就会把该对象加入到第一级缓存中
  2. 当清理缓存时,Hibernate会根据缓存中对象的状态变化来同步更新数据库。
Session缓存的作用:
  1. 减少访问数据库的频率
  2. 保证缓存中的对象与数据库中的对象同步
  3. 当缓存中的持久化对象之间存在循环关联关系时,Session会保证不出现访问对象图的死循环,以及由死循环引起的JVM堆栈溢出异常
Session缓存的应用:
  1. 当应用程序调用Transaction的commit方法时,commit方法会清理缓存,然后再向数据库提交事务 ,这里使用一个例子来简单说明一下

  目前数据库表中数据有:

QQ截图20150804152751

使用JUnit测试下面的这个方法:

@Test
    public void get(){
        Configuration cfg=new Configuration().configure();
        StandardServiceRegistryBuilder ssrb=new StandardServiceRegistryBuilder().applySettings(cfg.getProperties());
        ServiceRegistry service= ssrb.build();
        SessionFactory factory=cfg.buildSessionFactory(service);
        Session session= factory.openSession();
        Transaction tx=session.beginTransaction();
        try {
            Student stu=(Student)session.get(Student.class, 1);
            stu.setName("lisi");
            tx.commit();
        } catch (Exception e) {
            // TODO: handle exception
            tx.rollback();
        }finally {
            session.close();
        }
        
    }

运行时,我们可以在控制台看到:

QQ截图20150804153235

再次看看数据库表中的数据:

QQ截图20150804153455

透过这个案例,我们可以看到调用commit()方法时,hibernate进行了事务提交并把数据永久地保存到了数据库中,变为持久态。

  1. 当应用程序中显示调用session的flush方法时,通过session的setFlushMode(FlushMode fm)方法来设定清理缓存的时间点。

(1)FlushMode.ALWAYS:在session执行查询、commit方法以及flush方法时都会清理缓存;

(2)FlushMode.AUTO:在session执行查询、commit方法以及flush方法时都会清理缓存,这与第一种在本质上没有区别;

(3)FlushMode.COMMIT:在session执行commit方法以及flush方法时都会清理缓存;

(4)FlushMode.MANUAL:只有显示地调用flush方法时才会清理缓存,其他情况都不会清理缓存;

session缓存对象的生命周期:

首先来说一说session缓存对象都有哪些状态吧:

  1. 瞬时(Transient)状态
  2. 持久化(Persistent)状态
  3. 脱管(detached)状态
  4. 移除(removed)状态

这里我们用一个图来说明:

图片1

Session的基本操作 

在项目的测试包中,新建一个StudentTest2.java文件。

Session接口:

Session接口是Hibernate向应用程序提供的操作数据库的最主要的接口,它提供了基本的保存、查询、更新和删除等方法。

save()方法:

使一个瞬时状态的对象转变为持久化状态的对象。

图片2

使用JUnit测试下面的方法:

@Test
    public void add() {
        Configuration cfg = new Configuration().configure();
        // 如果是hibernate4.0以前的版本,使用如下的方式创建SessionFactory对象
        // SessionFactory factory=cfg.buildSessionFactory();
        StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder().applySettings(cfg.getProperties());
        ServiceRegistry service = ssrb.build();
        SessionFactory factory = cfg.buildSessionFactory(service);
        Session session = factory.openSession();
        Transaction tx = session.beginTransaction();
        
        try {
            //new 一个Student类的对象,在未执行session.save(stu1)方法时,它是瞬时对象
            Student stu1 = new Student();
            stu1.setName("yu zhiping");
            stu1.setAge(22);
            session.save(stu1);
            tx.commit();
        } catch (Exception e) {
            // TODO: handle exception
            tx.rollback();
        } finally {
            session.close();
        }

    }

运行,查看控制台的输出信息:

QQ截图20150804155044

此时,stu1就由一个瞬时状态对象变为了一个持久化状态的对象,并由session来管理,位于session的缓存中。如果在save()方法后再对stu1进行操作,就是对缓存中的数据进行操作,那当我们再次提交事务的时候会清理缓存,session会把缓存中的数据与数据库中的数据进行同步的更新,我们在上面的代码中,位于session.save(stu1);后添加��

stu1.setAge(22);

再次运行该方法,控制台的输出信息是:

QQ截图20150804160332

执行了两条SQL语句,这说明在调用save()方法后,stu1的确由瞬时态变为了持久态。

get()和load()方法:

都是根据给定的OID,加载一个持久化对象。

图片3图片4 

get()方法和load()方法的异同点:

  1. 都是先根据OID从缓存中获取,存在就直接返回
  2. get()方法:执行SQL从数据库获取
  3. load()方法:返回一个代理对象(延迟加载、懒加载)
  4. 如果数据库中不存在给定OID对应的记录:get()方法返回null;load()方法跑出ObjectNotFoundException异常

get()方法:

@Test
    public void get(){
        Configuration cfg=new Configuration().configure();
        StandardServiceRegistryBuilder ssrb=new StandardServiceRegistryBuilder().applySettings(cfg.getProperties());
        ServiceRegistry service= ssrb.build();
        SessionFactory factory=cfg.buildSessionFactory(service);
        Session session= factory.openSession();
        Transaction tx=session.beginTransaction();
        try {
            Student stu=(Student)session.get(Student.class, 1);
            System.out.println(stu.getId());
            tx.commit();
        } catch (Exception e) {
            // TODO: handle exception
            tx.rollback();
        }finally {
            session.close();
        }
        
    }

执行的结果是:

QQ截图20150804162245

查询了数据库表,再看看load()方法:

@Test
    public void load(){
        Configuration cfg=new Configuration().configure();
        StandardServiceRegistryBuilder ssrb=new StandardServiceRegistryBuilder().applySettings(cfg.getProperties());
        ServiceRegistry service= ssrb.build();
        SessionFactory factory=cfg.buildSessionFactory(service);
        Session session= factory.openSession();
        Transaction tx=session.beginTransaction();
        try {
            Student stu=(Student)session.load(Student.class, 1);
            System.out.println(stu.getId());
            tx.commit();
        } catch (Exception e) {
            // TODO: handle exception
            tx.rollback();
        }finally {
            session.close();
        }
        
    }
 

执行的结果:

QQ截图20150804161557

为什么没有在数据库中查询呢?这就是load()方法的特点:懒加载、延迟加载,只有访问非对象关系表示符OID属性以外的其他属性时load()方法才会发起select语句,我们把上面的方法稍微修改一下:

Student stu=(Student)session.load(Student.class, 1);
            System.out.println(stu.getName());//获取name属性
            tx.commit();

在次执行,看看控制台的信息:

QQ截图20150804162651

特别注意,在使用load()方法时,千万不要在session关闭后对非对象关系表示符属性以外的其他属性的访问,否则会跑出异常。

delete()方法

使一个持久化对象变成移除状态,从数据库中移除它的持久化状态。

图片1

看看delete()方法的定义:

@Test
    public void delete(){
        Configuration cfg=new Configuration().configure();
        StandardServiceRegistryBuilder ssrb=new StandardServiceRegistryBuilder().applySettings(cfg.getProperties());
        ServiceRegistry service= ssrb.build();
        SessionFactory factory=cfg.buildSessionFactory(service);
        Session session= factory.openSession();
        Transaction tx=session.beginTransaction();
        try {
            Student stu=(Student)session.load(Student.class, 1);
            session.delete(stu);
            tx.commit();
        } catch (Exception e) {
            // TODO: handle exception
            tx.rollback();
        }finally {
            session.close();
        }
        
    }

测试该方法,看看控制台的输出信息:

QQ截图20150804163731

可以看到,有两条sql语句,第一条就是get()方法的select语句,第二条就是delete()的删除语句。

update()方法

使一个脱管对象重附到新的session中,成为持久化对象。

图片2

看看update()方法的代码:

@Test
    public void update(){
        Configuration cfg=new Configuration().configure();
        StandardServiceRegistryBuilder ssrb=new StandardServiceRegistryBuilder().applySettings(cfg.getProperties());
        ServiceRegistry service= ssrb.build();
        SessionFactory factory=cfg.buildSessionFactory(service);
        Session session= factory.openSession();
        Transaction tx=session.beginTransaction();
        try {
            Student stu=(Student)session.load(Student.class, 2);
            stu.setAge(50);
            session.update(stu);
            tx.commit();
        } catch (Exception e) {
            // TODO: handle exception
            tx.rollback();
        }finally {
            session.close();
        }
        
    }

执行本方法,可以看到如下结果:

QQ截图20150804164403

在使用update()方法时,如果操作的是托管对象,它也依然会把托管对象变为持久化对象,然后再执行update语句,当清理缓存的时候,再把缓存中的数据同步更新到数据库。

merge()方法

将给定实例的状态复制到具有相同标识符的持久化实例上,并返回这个持久化实例;

常用来代替update()方法、saveOrUpdate()方法。

图片3

先看看使用merge()方法操作瞬时态对象:

@Test
    public void merge(){
        Configuration cfg=new Configuration().configure();
        StandardServiceRegistryBuilder ssrb=new StandardServiceRegistryBuilder().applySettings(cfg.getProperties());
        ServiceRegistry service= ssrb.build();
        SessionFactory factory=cfg.buildSessionFactory(service);
        Session session= factory.openSession();
        Transaction tx=session.beginTransaction();
        try {
            Student stu=new Student();
            stu.setName("wangwu");
            stu.setAge(22);
            session.merge(stu);
            tx.commit();
        } catch (Exception e) {
            // TODO: handle exception
            tx.rollback();
        }finally {
            session.close();
        }
        
    }

看看执行的结果:

QQ截图20150804165500

可以看出,它执行了一条insert语句,向数据库中添加了一条语句,再看看操作持久化状态的对象,又会是怎样的结果呢?

@Test
    public void merge(){
        Configuration cfg=new Configuration().configure();
        StandardServiceRegistryBuilder ssrb=new StandardServiceRegistryBuilder().applySettings(cfg.getProperties());
        ServiceRegistry service= ssrb.build();
        SessionFactory factory=cfg.buildSessionFactory(service);
        Session session= factory.openSession();
        Transaction tx=session.beginTransaction();
        try {
            Student stu=(Student)session.get(Student.class, 3);
            stu.setAge(23);
            session.merge(stu);
            tx.commit();
        } catch (Exception e) {
            // TODO: handle exception
            tx.rollback();
        }finally {
            session.close();
        }
        
    }

控制台打印的信息如下:

QQ截图20150804170109

可以看出,使用merge()方法时,它会根据对象的状态来确定是执行insert语句还是update语句,至此,session的几个基本的方法就搞定了。好累好累,弄了一个下午!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在使用 Redis 作为 .NET 应用程序的会话存储时,可以使用 Redis 的持久化功能来确保会话数据不会因为服务器重启或意外崩溃而丢失。Redis 提供了两种持久化方式:RDB 和 AOF。 1. RDB 持久化 RDB 持久化是将 Redis 内存中的数据定期写入到磁盘上,即在指定的时间间隔内将内存中的数据快照写入磁盘中的一个 RDB 文件中。当 Redis 重启时,可以将该文件加载到内存中,以恢复 Redis 数据。 在 .NET 中使用 Redis 的 RDB 持久化需要在 Redis 配置文件中设置: ``` # 开启 RDB 持久化 save 900 1 save 300 10 save 60 10000 ``` 其中,save 命令的三个参数分别表示: - 在 Redis 900 秒之内,如果至少有一个键被修改,则保存快照; - 在 Redis 300 秒之内,如果至少有 10 个键被修改,则保存快照; - 在 Redis 60 秒之内,如果至少有 10000 个键被修改,则保存快照。 2. AOF 持久化 AOF 持久化是将 Redis 执行的每个命令追加到一个磁盘上的文件中,当 Redis 重启时,可以按照文件中的命令顺序重放所有操作,以恢复 Redis 数据。 在 .NET 中使用 Redis 的 AOF 持久化需要在 Redis 配置文件中设置: ``` # 开启 AOF 持久化 appendonly yes # 指定 AOF 文件名 appendfilename "appendonly.aof" # 指定 AOF 文件保存路径 dir /path/to/redis/data ``` 其中,appendonly 指定开启 AOF 持久化,appendfilename 指定 AOF 文件名,dir 指定 AOF 文件保存路径。 综上所述,在 .NET 中使用 Redis 缓存 session 数据,可以通过 RDB 持久化或 AOF 持久化来确保数据的持久化。需要根据实际情况选择适合的持久化方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值