1,sqlsession的真實類型和數量
由於使用spring管理bean,當我們在代碼中需要使用這個bean的時候,會首先去容器中找,第一次需要調用MapperFactoryBean的getObject方法獲取一個bean,並保存到容器中。
MapperFactoryBean的getObject方法如下:
由於每個MapperFactoryBean對象初始化的時候,都會創建一個sqlSession,代碼在MapperFactoryBean類的父類SqlSessionDaoSupport中,當spring向MapperFactoryBean對象中注入SqlSessionFactory時就創建了SqlSession:
【結論1】:一個MapperFactoryBean對象擁有一個sqlSession對象。類型是org.mybatis.spring.SqlSessionTemplate
重要:spring整合mybatis使用的sqlSession類型是org.mybatis.spring.SqlSessionTemplate,
那么整合后的mybatis是怎么執行的呢?
首先查看SqlSessionTemplate類可以看到,所有的數據庫執行都被一個動態代理的sqlsession對象代理了。
在構造方法中查看該代理對象的構造
使用JDK動態代理,實現InvocationHandler的類是SqlSessionIntercepteor,查看它的invoke方法如下:
可以看到,方法開始就直接創建了一個新的sqlsession對象,這個對象就是被代理的對象。
再看getSqlSession方法,它是SqlSessionUtils中的一個靜態方法,如下:
第一句話和事務有關,如果它返回空,則直接使用sessionFactory創建一個新的session
【結論】spring整合mybatis后,非事務環境下,每次操作數據庫都使用新的sqlSession對象。因此mybatis的一級緩存無法使用(一級緩存針對同一個sqlsession有效)
下面兩段代碼:
(1)不整合spring,如下代碼的輸出可以看出,使用了一級緩存
結果:查詢過程只執行了一次。
(2)整合spring,
輸出結果如下:
兩次的輸出表示沒有使用一級緩存。
2,Mapper接口對應的bean在容器中的數量
通過getObject返回的對象是單利的,從MapperFactoryBean的isSingleton()可以得出
【結論二】因此,同一個IOC容器中同一個Mapper接口對應的代理類只有一個
例如系統有一個UserMapper接口對應UserMapper.xml
則如下代碼返回true