复习 - Hibernate的持久化环境

Hibernate的持久化环境

很久没有使用Hibernate了,现在要复习一下, 面试的话这个是必不可少的.

1.Hibernate Session.

session的概念大概是这样:

(1). Session是一块内存,里面存放了Persistent状态的对象, 也就是Persistent Context(持久化环境)

(2). Session里面有一组排着队等着执行的Sql,这些sql的目的本质上都是为了确保缓冲区(session级别的缓存,一级缓存)的内容和数据库保持一致.

关于Persistent Context,注意几点:

(1). 就是存放对象的一块缓存

(2). 你不能通过相关的API来访问它(它就是隐藏在背后的一个神秘人物)

(3). 很明显,一个Hibernate Session对应一个Persistent Context

(4). 对应的是一级缓存,不是可选的,是必须的,而且不能disable.

除了效率的提高(缓存), 缓存还可以给我们带来另外的好处:

(1) 自动脏数据检查.

来个例子:

package com.yxy.test;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.stat.Statistics;

import com.yxy.bean.Student;

public class HibernateStatTest {
	
	public static void main(String[] args){
		
		SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
		
		Statistics stat = sessionFactory.getStatistics();
		
		Session session = sessionFactory.openSession();
		session.getTransaction().begin();
		stat.setStatisticsEnabled(true);
		stat.clear();
		
		Student student = (Student)session.load(Student.class, 1);
		
		student.setName("Hello Hibernate !");
		
		System.out.println(stat.getEntityLoadCount());
		
		stat.setStatisticsEnabled(false);
		session.getTransaction().commit();
		session.close();
	}
}

 并没有调用update方法去更新,但是在事务提交之后是可以自动的将更新同步到数据库中的,控制台中也发出了相关的update语句

Hibernate: 
    /* update
        com.yxy.bean.Student */ update
            student 
        set
            name=?,
            sex=?,
            register_date=? 
        where
            id=?

 原理很简单:

Hibernate会在session中保存一份对象最近从数据库中加载上来的快照(snapshot), 所以在写回到数据库中的时候(比如事务提交),会将当前的对象同快照进行对比,如果有变化,则将变化部分同步到数据库,要注意一点,自动脏数据检查只是针对persistent状态的对象,因为如果是detached状态的话,很明显sesson已经关闭,所以快照都不存在了,还对比什么啊.

得益于自动脏数据检查,Hibernate还有一个延迟写入策略(透明的交易层延迟写入) - Transparent transaction-level write-behind

例子如下:

package com.yxy.test;

import java.util.Date;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.stat.Statistics;

import com.yxy.bean.Student;

public class HibernateWriteBehindTest {
	
	public static void main(String[] args){
		
		SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
		
		Statistics stat = sessionFactory.getStatistics();
		
		/*
		 *  --------------------- Session 1 ---------------------------
		 */
		Session session = sessionFactory.openSession();
		session.getTransaction().begin();
		stat.setStatisticsEnabled(true);
		stat.clear();
		
		Student student = (Student)session.load(Student.class, 1);
		
		student.setName("Hello Hibernate !");
		
		System.out.println(stat.getEntityLoadCount());
		
		stat.setStatisticsEnabled(false);
		session.getTransaction().commit();
		session.close();
		
		/*
		 * 开启另外一个session, 这里的student是一个detached状态对象
		 */
		
		/*
		 *  --------------------- Session 2 ---------------------------
		 */
		student.setName("Another Hibernate Session");
		
		Session anotherSession = sessionFactory.openSession();
		
		anotherSession.getTransaction().begin();
		stat.setStatisticsEnabled(true);
		stat.clear();
		
		/*
		 * update student
		 */
		anotherSession.update(student);
		/*
		 * 打印出flush的次数和修改对象的次数
		 */
		System.out.println("--------------- call  update  ----------------");
		System.out.println(stat.getEntityUpdateCount());
		System.out.println(stat.getFlushCount());
		
		Student student2 = new Student();
		student2.setName("Another Student");
		student2.setRegisterDate(new Date(System.currentTimeMillis()));
		student2.setSex("Man");
		
		/*
		 * save student2
		 */
		anotherSession.save(student2);
		
		/*
		 * 打印出新增对象个数等信息
		 */
		System.out.println("--------------- call  save  ----------------");
		System.out.println(stat.getEntityInsertCount());
		System.out.println(stat.getEntityUpdateCount());
		System.out.println(stat.getFlushCount());		
		
		anotherSession.getTransaction().commit();
		
		System.out.println("--------------- after commit ----------------");
		System.out.println(stat.getEntityInsertCount());
		System.out.println(stat.getEntityUpdateCount());
		System.out.println(stat.getFlushCount());
		
		stat.setStatisticsEnabled(false);
		anotherSession.close();
	}
}

 通过console打印出来的部分信息可以看到:

--------------- call  update  ----------------
0
0
Hibernate: 
    select
        hibernate_sequence.nextval 
    from
        dual
--------------- call  save  ----------------
0
0
0
Hibernate: 
    /* insert com.yxy.bean.Student
        */ insert 
        into
            student
            (name, sex, register_date, id) 
        values
            (?, ?, ?, ?)
Hibernate: 
    /* update
        com.yxy.bean.Student */ update
            student 
        set
            name=?,
            sex=?,
            register_date=? 
        where
            id=?
--------------- after commit ----------------
1
1
1

 当调用update的时候,并不会马上同步到数据库中,同样的调用save方法时也不会马上生成insert并同步到数据库,而是等到事务commit,才会一次性flush. 其实这些没有马上执行的sql会保存在之前提高过的排着队的sql那个队列里面复习 - Hibernate的持久化环境

延迟写入的好处:

(1) 可以减少数据库的负担,不会造成频繁的写数据库,当然也可以间接的提高并发性.

(2) 可以减少数据在网络上传输的开销.

但是也不是什么情况下都等到commit才会一股脑的将所有sql送给数据库去执行.比如说在中途要执行查询操作,这时Hibernate就会把之前的SQL送给数据库去执行了.因为要保证查询到的数据时最新的.

(关于这个问题,我不能试验出来啊,奇怪,看来书上说的还是有点不对,我使用的版本是Hibernate 3.2.0.ga)

在上述例子save student2之后调用:

List students = anotherSession.createSQLQuery("select * from student").list();

 但是产生的统计信息没有变化. 这表示在发出查询操作后并没有把之前的sql交给数据库去处理.

关于Persistent Context的基本概念,就先到这啦.

相关推荐