网上大多数解释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