Hibernate中关于session的机制以及一些方法

网上大多数解释session的save()、update()、delete()等方法都是的:

save : 从临时状态 ==》持久化状态
update: 从游离状态 ==》持久化状态
delete: 持久化状态 ==》临时状态

在session中存在的持久化对象是处于持久化状态的。
session关闭后,之前从session中读取的持久化对象即为游离态。
在数据库中不存在的持久化对象为监时态。

 

为了彻底弄懂session这几个方法,必须清楚Hibernate的几种对象状态,于是我查阅了更详细的解释:

Hibernate把对象分为4中状态:持久化状态、临时状态、游离状态、删除状态。

1、临时对象:

  • 在使用代理主键的情况下,OID通常为null
  • 不处于session缓存
  • 在数据库中没有对应的记录

2、 持久化对象:

  • OID不为null
  • 处于session缓存中
  • 数据库中有对应的记录
  • 在同一个session示例的缓存中,数据库中的每条记录只对应唯一的持久化对象

3、游离对象:

  • OID不为null
  • 不处于session缓存中
  • 在数据库中有对应的记录

4、删除对象:

  • 在数据库中没有对应的记录
  • 不再处于session缓存中

这里说明一下什么是代理主键:

       关系数据库主要依靠主键区分不同的记录,主键又有自然主键代理主键之分。

  自然主键:就是充当主键的字段本身具有一定的含义,是构成记录的组成部分,比如学生的学号,除了充当主键之外,同时也是学生记录的重要组成部分。

  代理主键:就是充当主键的字段本身不具有业务意义,只具有主键作用,比如自动增长的ID。

  在Hibernate中应使用代理主键。在Hibernate中,Hibernate依靠对象表示来区分不同的持久化,而对象标识符则可以通过Hibernate内置的表示生成器来产生。

 

Hibernate对象各个状态之间的转换

持久——>持久

//get()将一个ProductUUID对象放入session缓存中,这个对象现在是持久化状态
ProductUUID product=(ProductUUID)session.get(ProductUUID.class,"8a95d1ac6864167f0168641681000000");
product.setName("hello");
//因为该对象的状态并未改变,所以save()没有起作用
session.save(product);
//当事务提交时,hibernate会自动按照一定的策略将session中的持久化对象,
//同步到数据库中,从而自动使数据库的状态和session中的对象状态完全一致。该对象仍处于session中
session.getTransaction().commit();

运行结果:在数据库中更新了id为 8a95d1ac6864167f0168641681000000的记录的name字段值为hello。

临时——>持久

加上clear()清空一下缓存:

        ProductUUID product=(ProductUUID)session.get(ProductUUID.class,"8a95d1ac6864167f0168641681000000");
        //session缓存被清空,该对象不处于session中,但数据库仍有对应记录,为游离态
        session.clear();
        product.setName("hello world");
        //因为该对象的状态已经改变,所以save()起了作用,save()将该对象再一次放入session中。该对象 
        //是游离状态,却用了save,把它当成了临时状态,所以计划调用的sql语句是insert
        session.save(product);
        //当事务提交时,真正执行sql语句,插入了新的记录,该对象仍处于session中
        session.getTransaction().commit();

运行结果:在数据库中插入了一条新的记录,id是新产生的。

游离——>持久

将save方法改成update方法:

        ProductUUID product=(ProductUUID)session.get(ProductUUID.class,"8a95d1ac6864167f0168641681000000");
        //session缓存被清空,该对象不处于session中,但数据库仍有对应记录,为游离态
        session.clear();
        product.setName("hello hello");
        //因为该对象的状态已经改变,所以update()起了作用,将该对象再一次放入session中,所以计划调 
        //用的sql语句是update
        session.update(product);
        //当事务提交时,真正执行sql语句,更新了记录,该对象仍处于session中
        session.getTransaction().commit();

运行结果:数据库更新了id为8a95d1ac6864167f0168641681000000的记录的name值。

持久——>删除

        ProductUUID product=(ProductUUID) session.get(ProductUUID.class,"8a95d1ac6864167f0168641681000000");
        session.delete(product);
        //提交事务后删除数据库记录后,与save和update不同的是,该对象不存在在session中了
        session.getTransaction().commit();

Session的缓存机制

通过上面的代码,我们应该也知道了,session的get、update、save都会把对象放入session缓存中。debug模式下可以看到session缓存中有哪些对象。

既然save、update方法只是把对象放入session缓存中而已,那Hibernate是什么时候提交到数据库的呢?

这里,我们需要先知道一个叫做flush()的方法。 

        ProductUUID product=(ProductUUID)session.get(ProductUUID.class,"8a95d1ac686532830168653284d60000");
        product.setName("hello");
        session.update(product);
        System.out.println("*********");
        session.flush();
        System.out.println("*********");
        session.getTransaction().commit();

控制台打印结果:

Hibernate: select productuui0_.id as id1_0_, productuui0_.name as name1_0_, productuui0_.price as price1_0_ from product productuui0_ where productuui0_.id=?
*********
Hibernate: update product set name=?, price=? where id=?
*********

可以看出来,sql语句是在flush()方法执行的时候执行的。flush()方法执行之前,查看数据库对应的记录并没有更新。flush()方法执行之后,commit()之前,数据库对应的记录也没有更新,但是我们把数据库隔离级别改为读未提交(READ UNCOMMITTED),再查询,就可以看到记录已经更新了,只不过这个更新并不是持久的,如果之后没有commit,程序运行结束后,记录还是原来的状态,因为事务并没有提交。

commit() 和 flush() 方法的区别:flush 执行一系列 sql 语句,但不提交事务;commit 方法先调用flush() 方法,然后提交事务. 意味着提交事务意味着对数据库操作永久保存下来。

清空缓存和清理缓存的区别:clear()是清空session缓存,清空之后,session缓存中就不存在对象了;flush()是清理session缓存,清理意味着会执行sql语句,把session缓存中的对象同步到数据库中,但是并没有提交事务,如果数据库隔离级不是读未提交的话,就看不到数据库记录的变化了。flush()和commit()都不会清空session缓存。

 

特殊情况:上面的例子是当Hibernate生成主键策略为uuid的情况。如果Hibernate生成主键策略是native,那么当调用 Session 的 save() 方法保存对象时, 会立即执行向数据库插入该实体的 insert 语句,和调用了flush()的作用一样。示例:

        Product product=new Product();
        product.setName("你不开心");
        session.save(product);
        System.out.println("*********");
        session.getTransaction().commit();
        System.out.println("*********");

控制台打印结果:

Hibernate: insert into product_ (name, price) values (?, ?)
*********
*********

在save()方法执行完之后,就执行了insert语句,把session中的缓存对象同步到了数据库。不过,同样的,并没有提交事务。

 

参考博客:https://blog.csdn.net/qq_28483283/article/details/51345535

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值