上一节我们讲到了Hibernate的测试,并且给出了测试代码,刚开始看见这个测试代码的同学估计是一头雾水把,所以这一节我们来讲一下测试代码。 本节主要内容:
首先我们再来看一下上一节的测试代码:
//加载配置文件
Configuration config = new Configuration().configure();
//根据配置文件创建会话工厂
SessionFactory factory = config.buildSessionFactory();
//根据会话工厂创建会话
Session session = factory.getCurrentSession();
//创建一个事物对象
Transaction tx = session.beginTransaction();
//new 一个学生对象
Student student = new Student("小三‰",19,99);
//将对象持久化到数据表中
session.save(student);
//提交事务
tx.commit();
//关闭会话
session.close();
//关闭工厂
factory.close();
首先是Configuration,它是用来解析我们配置的一个类,它加载配置的时候使用了这段代码:
Configuration config = new Configuration().configure();
看到这段代码的第一感觉是为啥还要在后面加一个方法,直接new一个Configuration不就行了吗,为啥还加了一个configure方法。 我们来打开源码瞧瞧:
public Configuration configure() throws HibernateException {
return configure( StandardServiceRegistryBuilder.DEFAULT_CFG_RESOURCE_NAME );
}
看到了没,configure方法返回了一个有参的方法,且参数为:
StandardServiceRegistryBuilder.DEFAULT_CFG_RESOURCE_NAME
我们跟进去会发现这个参数是StandardServiceRegistryBuilder类定义的一个名字叫hibernate.config.xml的成员变量。
所以我们可以得出一个结论:如果你采用以下段代码来加载配置文件那么你的主配置文件名字必须叫作hibernate.config.xml
Configuration config = new Configuration().configure();
当然你也可以自定义,例如这样随意指定:
Configuration config = new Configuration().configure("xxx.xml');
但是我们建议使用hibernate指定的配置文件名。
这里我们只介绍这些,所以对于Configuration我们仅需要知道它是用来加载配置文件即可,以后具体分析,现在我们先将hibernate的基本原理讲明白就好。
SessionFactory factory = config.buildSessionFactory();
我们知道主配置文件里面最外面的便是<hibernate-configuration>
接下来就是<session-factory>
,所以通过Configuration实例对象的buildSessionFactory可以根据我们的配置文件建立会话工厂。值得注意的是SessionFactory是一个重量级的组件,是一个单例的,线程安全的。按理说单例对象一定是被共享的是线程不安全的,我们将它的实现类SessionFactoryimpl打开看发现它的大多数的成员变量都是final的,所以它是线程安全的。
一般SessionFactory实例都不进行关闭(开销太大),而是在应用结束的时候自动将其销毁。
session由SessionFactory的getCurrentSession()或者openSession()进行创建,在web应用中,每当有一个用户访问时就会为这个用户创建一个Session,所以Session是多例的,它包含了许多非final变量,对同一个用户可能会产生多个事务,若多事务同时对Session的同一个变量进行访问就会引起并发的问题从而导致线程不安全。
上面提到了Session的两种获取方式,接下来我们说一下两种方式的区别: getCurrentSession无论执行多少次只要是在同一个线程中它获取到的都是同一个Session对象,使用这个方法获取的Session对象是由ThreadLocal变量存储的(ThreadLocal在我的多线程文章里面有介绍),它的底层是一个Map,key就为线程的名字,所以用这个方法创建的Session对象是线程唯一的。 它创建Session对象的时候会进行判断,判断线程是是否已经存在session,如果不存在便进行创建。以下便是它的实现源码(有源码有真相):
public Session getCurrentSession() throws HibernateException {
if ( currentSessionContext == null ) {
throw new HibernateException( "No CurrentSessionContext configured!" );
}
return currentSessionContext.currentSession();
}
如果不存在那么久进行创建,底层也是通过openSession创建:
protected Session buildOrObtainSession() {
return baseSessionBuilder()
.autoClose( isAutoCloseEnabled() )
.connectionReleaseMode( getConnectionReleaseMode() )
.flushBeforeCompletion( isAutoFlushEnabled() )
.openSession();//就是这里
}
具体的逻辑太多,不方便一直跟下去,所以有兴趣的可以一直跟下去。 openSession进行创建时,每执行一次便会创建一个Session对象,所以需要我们手动关闭,而getCurrentSession不用关闭。
getCurrentSession获得的Session对象不用注册便能够使用而openSession无需注册。
getCurrentSession获得的session对象一定要在事务里面执行,而openSession获得的对象可以不在事务里面执行。 以上就是对两种获取方式的简单总结。