1背景这是一个没有bug的安静祥和的下午。作为菜鸟,还是要时刻夯实基础的。趁着这个好时机,让我学习一下mybatis的使用方法。这和我看到的不一样,让我看看项目里写的是什么。我们项目中的Dao继承自BaseDao,BaseDao继承自SqlSessionDaoSupport。每次执行SQL,直接返回sqlSession,再执行SQL。这不是实例变量吗?这和你说的不一样。于是带着这个疑问,我开始探索。2探索之旅1)我们都知道在使用mybatis的时候,sqlSession来自于sqlSessionFactory,而sqlSessionFactory可以通过sqlSessionFactoryBuilder来创建,也可以通过spring来初始化,而在项目中显然采用了后一种方式。2)然后我们得到了sqlSessionFactory,我们应该如何进一步探究sqlSession的来源,我想可以通过项目中已经实现的dao来探究。我们随机选择一个dao作为例子。它继承了BaseDao。而BaseDao继承了SqlSessionDaoSupport,调用了BaseDao中的getSqlSession方法,其实就是SqlSessionDaoSupport的getSqlSession方法。SqlSessionDaoSupport的getSqlSession方法直接返回自己的成员变量。至此,和我的疑惑是一致的,就是现在的写法和mybatis官网的描述有冲突。3)反复阅读SqlSessionDaoSupport类,终于找到了头绪。细心的朋友应该已经发现了。上图的注释中,“用户应该使用该方法获取一个SqlSession来执行SQL语句,这个SqlSession是spring管理的,用户不要提交,回滚,关闭。因为这些已经自动执行了。”同时,该方法会返回一个线程安全的SqlSession。那么这个SqlSession是从哪里来的呢?从上图可以看出,它有两种赋值方式,一种是给它传一个SqlSessionFactory生成一个SqlSessionTemplate,这个SqlSessionTemplate就是sqlSession。另一种是直接传给他一个SqlSessionTemplate作为SqlSession。根据该类的注释,如果同时定义了SqlSessionFactory和SqlSessionTemplate,那么SqlSessionFactory的方法就会失效。至此,我上面的问题已经解决了,也就是说这个SqlSession不是mybatis的初始SqlSession,而是spring实现的SqlSessionTemplate。4)但是,我有一个新的问题,SqlSessionTemplate是如何实现线程安全的呢?于是进入SqlSessionTemplate的方法执行,发现其实是代理类sqlSessionProxy在执行语句。代理工作的内容在处理程序SqlSessionInterceptor中。走进去,我们终于发现了它的acquire和close操作。也就是说,每次执行时,agent都会调用sessionFactory的openSession方法来获取一个新的session。3总结最后,终于,mybatis,spring,project和我的问题统一了。这真是一个宁静而没有虫子的下午。
