|
我们现在已经有一个DefaultSqlSessionFactory,按照编程式的开发过程,我们接下来就会创建一个SqlSession 的实现类,但是在Spring 里面,我们不是直接使用DefaultSqlSession 的,而是对它进行了一个封装,这个SqlSession 的实现类就是SqlSessionTemplate。这个跟Spring 封装其他的组件是一样的,比如JdbcTemplate,RedisTemplate 等等,也是Spring 跟MyBatis 整合的最关键的一个类。
为什么不用DefaultSqlSession?它是线程不安全的,注意看类上的注解:
Note that this class is not Thread-Safe.
而SqlSessionTemplate 是线程安全的。
* Thread safe, Spring managed, {@code SqlSession} that works with Spring
回顾一下SqlSession 的生命周期:
| 对象 | 生命周期 | | SqlSessionFactoryBuiler | 方法局部(method) | | SqlSessionFactory(单例) | 应用级别(application) | | SqlSession | 请求和操作(request/method) | | Mapper | 方法(method) |
在编程式的开发中,SqlSession 我们会在每次请求的时候创建一个,但是Spring里面只有一个SqlSessionTemplate(默认是单例的),多个线程同时调用的时候怎么保证线程安全?
思考:为什么SqlSessionTemplate 是线程安全的?
思考:在编程式的开发中,有什么方法保证SqlSession 的线程安全?
SqlSessionTemplate 里面有DefaultSqlSession 的所有的方法:selectOne()、selectList()、insert()、update()、delete(),不过它都是通过一个代理对象实现的。这个代理对象在构造方法里面通过一个代理类创建:
this.sqlSessionProxy = (SqlSession) newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[] { SqlSession.class },
new SqlSessionInterceptor());
所有的方法都会先走到内部代理类SqlSessionInterceptor 的invoke()方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = getSqlSession(
SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType,
SqlSessionTemplate.this.exceptionTranslator);
try {
Object result = method.invoke(sqlSession, args);
首先会使用工厂类、执行器类型、异常解析器创建一个sqlSession,然后再调用sqlSession 的实现类,实际上就是在这里调用了DefaultSqlSession 的方法。
|