写在之前
最近在使用Mybatis的时候很是好奇一些实现细节,所以也就多留意了下。 SqlSessionFactory、SqlSessionFactoryBean、SqlSession和SqlSessionTemplate是大家直接使用比较多的。这里我先不说这些类的实现细节,先大致说下它们之间的关系,相信会有同样的人对于它们之间的关系感兴趣。设计者设计这个类的时候肯定是有目的性的,搞清楚目的性再去看实现源码才会有方向性,从而达到事半功倍的效果。我会结合自己的理解,连续通过几篇文章来讲述下它们之间的感情纠葛,并结合生成环境中的常用方式进行实例说明。若是您发现文章有错误的地方,还望不惜笔墨,吾当虚心接受,感激涕零。
正文
1. SqlSession和SqlSessionTemplate
SqlSession实现了Closeable接口,代表SqlSession是可以关闭的,那也就是说SqlSession代表一种可关闭的连接,也正如名字所表达的是Session,Session对于开发人员来说并不陌生。例如:浏览器和服务器之间的会话也是Session,Session用来维护无状态请求之间的状态的信息。所以说SqlSession也是一种会话,数据库连接客户端和数据库Server之间的一种会话,并维护了客户端和数据库Server的一些状态信息。
看源码中的描述:
SqlSession是接口,接口是一种高层次的抽象,你可以认为接口是声明了一种能力。。若是实现了该接口,就拥有了该接口的能力(方法)和特征(属性)。官方的描述是:“你可以通过它执行命令、获取mapper和管理事务”。那也就是说,只要我实现了SqlSession接口,那我就有了同样的能力了。至于它是如何实现发送sql语句,管理事务和获取mapper的,这是后话,后续再说。
我们再来看看,实现了SqlSession的类有哪些?
正如图中所示,DefaultSqlSession是SqlSession接口的默认实现;SqlSessionTemplate也是SqlSession的一种实现。SqlSessionTemplate除了实现了SqlSession接口外,还是实现了下面的接口:
实现了DisposableBean接口,也就代表了SqlSessionTemplate的实例被Bean工厂发现后,会把它们纳入整个生命周期的管理过程中,当BeanFactory被尝试销毁时,Beans的管理者会以回调的方式调用SqlSessionTemplate的destroy()方法。 我们来看看SqlSessionTemplate的destroy()方法的实现:
默认实现是空方法,具体实现你自己可以重写。
2. SqlSessionFactory和SqlSessionFactoryBean
如上图,SqlSessionFactory也是一种抽象定义,其能力(方法 )就是打开一个会话(客户端和数据库Server),而且重载了很多不同的参数,你可以改变这些参数自定义会话过程中的一些默认行为。例如:可以设置自动提交事务或是关闭自动提交;可以设置获取数据库连接的线程的类型(重用,每次新产生等等);也可以获取整个Mybatis的配置信息的Configuration对象实例,关于Configuration的讨论我们下期再说。
SqlSessionFactory的实现也有两种,甚至你可以自定义实现。默认实现是DefaultSqlSessionFactory
DefaultSqlSessionFactory具体实现了SqlSessionFactory接口定义的抽象行为。总而言之,SqlSessionFactory就是生产SqlSession对象的工厂。那也就是说整个Mybatis中,如果只有一个数据库Server要连接,那么只需要一个工厂就够了(只有一个SqlSessionFactory的实例对象),而SqlSession可以自由的被关闭,也就代表SqlSession是需要反复被创建的。上面说到SqlSession是关联到具体数据库连接的,但是如果每次创建和销毁都直接操作物理连接的话,那么这个资源浪费很高,效率很低。请看DefaultSqlSessionFactory的方法:
上图的实现中是有基于连接池技术的。使用数据库连接池时,关闭SqlSession实例 ,其实只是把数据库连接对象(代表物理资源)放回到对象池中,并没有直接销毁,使用连接池技术极大提高了物理资源利用率,缩减了创建物理连接所需的时间、资源等等。
如上图,SqlSessionFactoryBean直接实现了三个接口。实现ApplicationListener代表SqlSessionFactoryBean有能力监控 Application发出的一些事件通知;实现InitializingBean代表SqlSessionFactoryBean中的afterPropertiesSet()方法会在Bean初始化属性完成后立即被调用;实现了FactoryBean代表SqlSessionFactoryBean的实例不再是普通的Bean对象,而是可以产生自己Bean的一种工厂,该工厂产生的Bean同样可以被纳入Spring的生命周期。
正如SqlSessionFactoryBean的名字,它是生产SqlSessionFactory的工厂Bean。
综上所述,SqlSessionFactoryBean是生产SqlSessionFactory的一种工厂Bean;SqlSessionFactory是一种生产SqlSession的工厂;SqlSession是代表数据库连接客户端和数据库Server之间的会话信息;SqlSessionTemplate是SqlSession的一个具体实现。如下图:
说明:图中的蓝色箭头不代表继承的含义。
写在最后
看完上面的大致讲述后,你会不会有些问题要问呢?比如:既然SqlSessionFactory是产生SqlSession的了,那干嘛又搞出来SqlSessionTemplate呢?它到底是干嘛的呢?说到SqlSessionTemplate和SqlSession、SqlSessionFactory之间的纠缠,就不得不说动态代理了。下期我们将讲述SqlSessionTemplate的实现细节,我们的代码中是如何产生Sql语句并发送给数据库Server的,通过进一步的分析让你更加了解Mybatis的实现细节末梢。预知后事如何,且看下回分解。