一个宁静祥和没有 bug 的下午和 SqlSession 的故事
![一个宁静祥和没有bug的下午和SqlSession的故事](https://static001.geekbang.org/infoq/f2/f2cd37982f237516acaa1eeb7c6a8fe9.jpeg)
作者:马跃
1 背景
这是一个安静祥和没有 bug 的下午。作为一只菜鸡,时刻巩固一下基础还是很有必要的,如此的大好时机,就让我来学习学习 mybatis 如何使用。
![](https://static001.geekbang.org/infoq/60/60df5dcb9ab8ce4eac654e238196a43d.png)
这可和我看到的不一样啊,让我来看看项目里怎么写的。
![](https://static001.geekbang.org/infoq/5f/5f633fc41068314305ec59ebf79eb5fb.png)
我们项目中的 Dao 都继承于 BaseDao,而 BaseDao 继承于 SqlSessionDaoSupport,每次执行 sql 的时候都是直接将这个 sqlSession 返回,然后执行 sql,这难道不是一个实例变量嘛?这和你说的可不一样诶。于是带着这样的疑问,我开始了探索。
2 探索之旅
1)我们都知道,在使用 mybatis 时,sqlSession 都来自于 sqlSessionFactory,而 sqlSessionFactory 可以通过 sqlSessionFactoryBuilder 创建,也可以通过 spring 初始化,而项目中很显然采取了后一种方式。
![](https://static001.geekbang.org/infoq/82/82ca37d4eef0a0b9c2a4d0677e28e1e8.png)
2)那么我们已经得到了 sqlSessionFactory,应该如何去进一步探索 sqlSession 的来源呢,我想到可以通过项目中已经实现的 dao 进行探索。我们随便选取一个 dao 为例。
![](https://static001.geekbang.org/infoq/ff/ffbd7ba8efbc599e9040b17520016d8e.png)
它继承了 BaseDao。
![](https://static001.geekbang.org/infoq/ea/ea038b67cfb609c5cf6ecc5da8688013.png)
而 BaseDao 又继承了 SqlSessionDaoSupport,在 BaseDao 中调用了 getSqlSession 方法,实际上也就是 SqlSessionDaoSupport 的 getSqlSession 方法。
![](https://static001.geekbang.org/infoq/3f/3fd02dbbbe2cdb75018f374b0f9fd32e.png)
而 SqlSessionDaoSupport 的 getSqlSession 方法是直接将自己的成员变量返回去的,截至目前为止,和我的怀疑点是相符合的,即目前的写法和 mybatis 官网的说明是冲突的。
3)反复阅读 SqlSessionDaoSupport 这个类后,终于被我发现了线索,细心的小伙伴应该也早已发现了,就在上图之中的注释中,“用户应该使用这个方法来获得一个 SqlSession 来执行 sql 语句,这个 SqlSession 被 spring 管理,用户不应该提交、回滚或关闭它。因为这些已经被自动执行了。”
同时,这个方法会返回一个线程安全的 SqlSession。
![](https://static001.geekbang.org/infoq/f0/f02b9a5a162db9ee0955909a063b2bf4.png)
那么这个 SqlSession 是从何而来的呢,从上图可以看出,它有两种赋值方式,一种是给他传一个 SqlSessionFactory,生成 SqlSessionTemplate,SqlSessionTemplate 即为 sqlSession。另一种是直接给他传一个 SqlSessionTemplate 作为 SqlSession。根据本类的注释,如果 SqlSessionFactory 和 SqlSessionTemplate 都被定义了,那么 SqlSessionFactory 的方式会失效。至此,我的上述疑问已经解决了,也就是说这个 SqlSession 并不是一个 mybatis 初始的 SqlSession,而是 spring 实现的 SqlSessionTemplate。
4)但是,我又诞生了新的疑问,SqlSessionTemplate 是怎么完成线程安全的呢?
![](https://static001.geekbang.org/infoq/e7/e7dc25814e003aca506669694271868e.png)
于是我进入了 SqlSessionTemplate 的方法执行,发现实际执行语句的都是这个代理类 sqlSessionProxy。
![](https://static001.geekbang.org/infoq/98/98c18bc8e48f7c74ece642802b16f564.png)
而代理工作内容就在 SqlSessionInterceptor 这个 handler 里。
![](https://static001.geekbang.org/infoq/9b/9b229b8d31c410b01505f5f397d3fa89.png)
进入其中,我们终于发现了它的获取和关闭操作。
![](https://static001.geekbang.org/infoq/5f/5f2196e51130ed3409fcbf20cb5dc2b0.png)
![](https://static001.geekbang.org/infoq/71/7132d0c90607d57dfae273cc7f76e03d.png)
也就是说,每次执行,代理都会调用 sessionFactory 的 openSession 方法获得一个新的 session。
3 总结
终于的终于,mybatis,spring,项目以及我的疑问得到了统一,真是一个宁静祥和而又没有 bug 的下午呀。
版权声明: 本文为 InfoQ 作者【京东科技开发者】的原创文章。
原文链接:【http://xie.infoq.cn/article/7aebde539b1bc6bab40228434】。文章转载请联系作者。
评论