关于Mybatis与Spring整合之后SqlSession与mapper对象之间数量的问题。 1,sqlsession的真实类型和数量 2,Mapper接口对应的bean在容器中的数量

由于使用spring管理bean,当我们在代码中需要使用这个bean的时候,会首先去容器中找,第一次需要调用MapperFactoryBean的getObject方法获取一个bean,并保存到容器中。

MapperFactoryBean的getObject方法如下:

 关于Mybatis与Spring整合之后SqlSession与mapper对象之间数量的问题。
1,sqlsession的真实类型和数量
2,Mapper接口对应的bean在容器中的数量

由于每个MapperFactoryBean对象初始化的时候,都会创建一个sqlSession,代码在MapperFactoryBean类的父类SqlSessionDaoSupport中,当spring向MapperFactoryBean对象中注入SqlSessionFactory时就创建了SqlSession:

 关于Mybatis与Spring整合之后SqlSession与mapper对象之间数量的问题。
1,sqlsession的真实类型和数量
2,Mapper接口对应的bean在容器中的数量

【结论1】:一个MapperFactoryBean对象拥有一个sqlSession对象。类型是org.mybatis.spring.SqlSessionTemplate

重要:spring整合mybatis使用的sqlSession类型是org.mybatis.spring.SqlSessionTemplate

那么整合后的mybatis是怎么执行的呢?

首先查看SqlSessionTemplate类可以看到,所有的数据库执行都被一个动态代理的sqlsession对象代理了。

 关于Mybatis与Spring整合之后SqlSession与mapper对象之间数量的问题。
1,sqlsession的真实类型和数量
2,Mapper接口对应的bean在容器中的数量

在构造方法中查看该代理对象的构造

关于Mybatis与Spring整合之后SqlSession与mapper对象之间数量的问题。
1,sqlsession的真实类型和数量
2,Mapper接口对应的bean在容器中的数量

使用JDK动态代理,实现InvocationHandler的类是SqlSessionIntercepteor,查看它的invoke方法如下:

 关于Mybatis与Spring整合之后SqlSession与mapper对象之间数量的问题。
1,sqlsession的真实类型和数量
2,Mapper接口对应的bean在容器中的数量

可以看到,方法开始就直接创建了一个新的sqlsession对象,这个对象就是被代理的对象。

再看getSqlSession方法,它是SqlSessionUtils中的一个静态方法,如下:

 关于Mybatis与Spring整合之后SqlSession与mapper对象之间数量的问题。
1,sqlsession的真实类型和数量
2,Mapper接口对应的bean在容器中的数量

第一句话和事务有关,如果它返回空,则直接使用sessionFactory创建一个新的session

【结论】spring整合mybatis后,非事务环境下,每次操作数据库都使用新的sqlSession对象。因此mybatis的一级缓存无法使用(一级缓存针对同一个sqlsession有效)

下面两段代码:

(1)不整合spring,如下代码的输出可以看出,使用了一级缓存

 关于Mybatis与Spring整合之后SqlSession与mapper对象之间数量的问题。
1,sqlsession的真实类型和数量
2,Mapper接口对应的bean在容器中的数量

结果:查询过程只执行了一次。

 关于Mybatis与Spring整合之后SqlSession与mapper对象之间数量的问题。
1,sqlsession的真实类型和数量
2,Mapper接口对应的bean在容器中的数量

(2)整合spring,

 关于Mybatis与Spring整合之后SqlSession与mapper对象之间数量的问题。
1,sqlsession的真实类型和数量
2,Mapper接口对应的bean在容器中的数量

输出结果如下:

 关于Mybatis与Spring整合之后SqlSession与mapper对象之间数量的问题。
1,sqlsession的真实类型和数量
2,Mapper接口对应的bean在容器中的数量

两次的输出表示没有使用一级缓存。

2,Mapper接口对应的bean在容器中的数量

通过getObject返回的对象是单利的,从MapperFactoryBean的isSingleton()可以得出

 关于Mybatis与Spring整合之后SqlSession与mapper对象之间数量的问题。
1,sqlsession的真实类型和数量
2,Mapper接口对应的bean在容器中的数量

【结论二】因此,同一个IOC容器中同一个Mapper接口对应的代理类只有一个

例如系统有一个UserMapper接口对应UserMapper.xml

则如下代码返回true

 关于Mybatis与Spring整合之后SqlSession与mapper对象之间数量的问题。
1,sqlsession的真实类型和数量
2,Mapper接口对应的bean在容器中的数量