一、概述
Session 是 Hibernate 向应用程序提供操纵数据的主要接口,它提供了基本的保存、更新、删除和加载 Java 对象的方法。
二、Session 缓存
1.简介
(1)Session 有一个缓存,称为 Hibernate 一级缓存。位于缓存中的对象称为持久化对象,每一个持久化对象与数据库中的一条记录对应。
(2)站在持久化的角度,Hibernate 将对象分为 4 种状态:临时状态、持久化状态、游离状态、删除状态。
2.测试 Session 缓存
(1)准备
①hibernate.cfg.xml 文件请参看上一篇文章。
②SessionFactory、Session、Transaction
private SessionFactory sessionFactory; private Session session; private Transaction transaction; @Before public void init() { Configuration configuration = new Configuration().configure(); ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry(); sessionFactory = configuration.buildSessionFactory(serviceRegistry); session = sessionFactory.openSession(); transaction = session.beginTransaction(); } @After public void destroy() { transaction.commit(); session.close(); sessionFactory.close(); }
说明:使用单元测试类进行测试。因为是测试环境,不存在并发的情况,创建了一个 Session 对象。
(2)测试
@Test public void testSession() { News news = (News) session.get(News.class, 1); System.out.println(news); News news2 = (News) session.get(News.class, 1); System.out.println(news2); System.out.println(news.equals(news2)); }
测试结果:
Hibernate: select news0_.id as id1_0_0_, news0_.title as title2_0_0_, news0_.author as author3_0_0_, news0_.date as date4_0_0_ from hibernate.news news0_ where news0_.id=? News{id=1, title='Title', author='tom', date=2016-09-28} News{id=1, title='Title', author='tom', date=2016-09-28} true
说明:
第一次查询的时候,会将引用赋值给 news,同时向 Session 缓存中存入了一份。
第二次查询的时候,并没有发送 select 语句,而是从 Session 缓存中直接获取的。
3.操纵 Session 缓存
(1)flush() :使数据表中的记录和 Session 缓存中的对象的状态保持一致。
① 在 Transaction 的 commit() 方法中,先调用 session 的 flush 方法,再提交事务。
org.hibernate.engine.transaction.spi.AbstractTransactionImpl#commit
@Override public void commit() throws HibernateException { if ( localStatus != LocalStatus.ACTIVE ) { throw new TransactionException( "Transaction not successfully started" ); } LOG.debug( "committing" ); beforeTransactionCommit(); try { doCommit(); localStatus = LocalStatus.COMMITTED; afterTransactionCompletion( Status.STATUS_COMMITTED ); } catch ( Exception e ) { localStatus = LocalStatus.FAILED_COMMIT; afterTransactionCompletion( Status.STATUS_UNKNOWN ); throw new TransactionException( "commit failed", e ); } finally { invalidate(); afterAfterCompletion(); } }
org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction#beforeTransactionCommit
protected void beforeTransactionCommit() { this.transactionCoordinator().sendBeforeTransactionCompletionNotifications(this); if(this.isDriver && !this.transactionCoordinator().getTransactionContext().isFlushModeNever()) { this.transactionCoordinator().getTransactionContext().managedFlush(); } if(this.isDriver) { this.transactionCoordinator().getTransactionContext().beforeTransactionCompletion(this); } }
② 可能会打印 SQL 语句,但是不会提交事务。
③ 在未提交事务或显式的调用 flush() 方法前,也可能会进行 flush() 操作。
- 执行 HQL 或 QBC 查询,会先进行 flush() 操作,以得到数据表的最新记录。
- 若记录的 ID 是由数据库使用的自增的方式生成的,则在调用 save() 方法时,就会立即发送 INSERT 语句,因为 save 方法后,必须保证对象的 ID 存在。
(2)refresh():会强制发送 SELECT 语句,以使 Session 缓存中对象的状态和数据表中对应的记录保持一致。
1 @Test 2 public void testRefresh() { 3 News news = (News) session.get(News.class, 1); 4 System.out.println(news); 5 session.refresh(news); 6 System.out.println(news); 7 }
我在第5行断点,然后修改数据库中 News 的 `author` 字段,改为 jerry。执行。
两次打印结果相同。
Hibernate: select news0_.id as id1_0_0_, news0_.title as title2_0_0_, news0_.author as author3_0_0_, news0_.date as date4_0_0_ from hibernate.news news0_ where news0_.id=? News{id=1, title='Title', author='tom', date=2016-09-28} Hibernate: select news0_.id as id1_0_0_, news0_.title as title2_0_0_, news0_.author as author3_0_0_, news0_.date as date4_0_0_ from hibernate.news news0_ where news0_.id=? News{id=1, title='Title', author='tom', date=2016-09-28}