`

Mybatis SqlSessionTemplate 源码解析

 
阅读更多

Mybatis SqlSessionTemplate 源码解析

在使用Mybatis与Spring集成的时候我们用到了SqlSessionTemplate 这个类。

 

    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
          <constructor-arg index="0" ref="sqlSessionFactory" />
    </bean>

 

通过源码我们何以看到 SqlSessionTemplate 实现了SqlSession接口,也就是说我们可以使用SqlSessionTemplate 来代理以往的DefailtSqlSession完成对数据库的操作,但是DefailtSqlSession这个类不是线程安全的,所以这个类不可以被设置成单例模式的。

如果是常规开发模式 我们每次在使用DefailtSqlSession的时候都从SqlSessionFactory当中获取一个就可以了。但是与Spring集成以后,Spring提供了一个全局唯一的SqlSessionTemplate示例 来完成DefailtSqlSession的功能,问题就是:无论是多个dao使用一个SqlSessionTemplate,还是一个dao使用一个SqlSessionTemplate,SqlSessionTemplate都是对应一个sqlSession,当多个web线程调用同一个dao时,它们使用的是同一个SqlSessionTemplate,也就是同一个SqlSession,那么它是如何确保线程安全的呢?让我们一起来分析一下。

(1)首先,通过如下代码创建代理类,表示创建SqlSessionFactory的代理类的实例,该代理类实现SqlSession接口,定义了方法拦截器,如果调用代理类实例中实现SqlSession接口定义的方法,该调用则被导向SqlSessionInterceptor的invoke方法

 

复制代码
 1   public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
 2       PersistenceExceptionTranslator exceptionTranslator) {
 3 
 4     notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
 5     notNull(executorType, "Property 'executorType' is required");
 6 
 7     this.sqlSessionFactory = sqlSessionFactory;
 8     this.executorType = executorType;
 9     this.exceptionTranslator = exceptionTranslator;
10     this.sqlSessionProxy = (SqlSession) newProxyInstance(
11         SqlSessionFactory.class.getClassLoader(),
12         new Class[] { SqlSession.class },
13         new SqlSessionInterceptor());
14   }
复制代码

核心代码就在 SqlSessionInterceptor的invoke方法当中。

复制代码
 1   private class SqlSessionInterceptor implements InvocationHandler {
 2     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 3       //获取SqlSession(这个SqlSession才是真正使用的,它不是线程安全的)
 4       //这个方法可以根据Spring的事物上下文来获取事物范围内的sqlSession
 5       //一会我们在分析这个方法
 6       final SqlSession sqlSession = getSqlSession(
 7           SqlSessionTemplate.this.sqlSessionFactory,
 8           SqlSessionTemplate.this.executorType,
 9           SqlSessionTemplate.this.exceptionTranslator);
10       try {
11         //调用真实SqlSession的方法
12         Object result = method.invoke(sqlSession, args);
13         //然后判断一下当前的sqlSession是否被Spring托管 如果未被Spring托管则自动commit
14         if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
15           // force commit even on non-dirty sessions because some databases require
16           // a commit/rollback before calling close()
17           sqlSession.commit(true);
18         }
19         //返回执行结果
20         return result;
21       } catch (Throwable t) {
22         //如果出现异常则根据情况转换后抛出
23         Throwable unwrapped = unwrapThrowable(t);
24         if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
25           Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
26           if (translated != null) {
27             unwrapped = translated;
28           }
29         }
30         throw unwrapped;
31       } finally {
32         //关闭sqlSession
33         //它会根据当前的sqlSession是否在Spring的事物上下文当中来执行具体的关闭动作
34         //如果sqlSession被Spring管理 则调用holder.released(); 使计数器-1
35         //否则才真正的关闭sqlSession
36         closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
37       }
38     }
39   }
复制代码

在上面的invoke方法当中使用了俩个工具方法 分别是

SqlSessionUtils.getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator)

SqlSessionUtils.closeSqlSession(SqlSession session, SqlSessionFactory sessionFactory)

那么这个俩个方法又是如何与Spring的事物进行关联的呢?

复制代码
 1 public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {     
 2     //根据sqlSessionFactory从当前线程对应的资源map中获取SqlSessionHolder,当sqlSessionFactory创建了sqlSession,就会在事务管理器中添加一对映射:key为sqlSessionFactory,value为SqlSessionHolder,该类保存sqlSession及执行方式 
 3     SqlSessionHolder holder = (SqlSessionHolder) getResource(sessionFactory); 
 4  //如果holder不为空,且和当前事务同步 
 5     if (holder != null && holder.isSynchronizedWithTransaction()) { 
 6       //hodler保存的执行类型和获取SqlSession的执行类型不一致,就会抛出异常,也就是说在同一个事务中,执行类型不能变化,原因就是同一个事务中同一个sqlSessionFactory创建的sqlSession会被重用 
 7       if (holder.getExecutorType() != executorType) { 
 8         throw new TransientDataAccessResourceException("Cannot change the ExecutorType when there is an existing transaction"); 
 9       } 
10       //增加该holder,也就是同一事务中同一个sqlSessionFactory创建的唯一sqlSession,其引用数增加,被使用的次数增加 
11       holder.requested(); 
12    //返回sqlSession 
13       return holder.getSqlSession(); 
14     } 
15  //如果找不到,则根据执行类型构造一个新的sqlSession 
16     SqlSession session = sessionFactory.openSession(executorType); 
17  //判断同步是否激活,只要SpringTX被激活,就是true 
18     if (isSynchronizationActive()) { 
19    //加载环境变量,判断注册的事务管理器是否是SpringManagedTransaction,也就是Spring管理事务 
20       Environment environment = sessionFactory.getConfiguration().getEnvironment(); 
21       if (environment.getTransactionFactory() instanceof SpringManagedTransactionFactory) { 
22   //如果是,则将sqlSession加载进事务管理的本地线程缓存中 
23         holder = new SqlSessionHolder(session, executorType, exceptionTranslator); 
24   //以sessionFactory为key,hodler为value,加入到TransactionSynchronizationManager管理的本地缓存ThreadLocal<Map<Object, Object>> resources中 
25         bindResource(sessionFactory, holder); 
26   //将holder, sessionFactory的同步加入本地线程缓存中ThreadLocal<Set<TransactionSynchronization>> synchronizations 
27         registerSynchronization(new SqlSessionSynchronization(holder, sessionFactory)); 
28         //设置当前holder和当前事务同步 
29   holder.setSynchronizedWithTransaction(true); 
30   //增加引用数 
31         holder.requested(); 
32       } else { 
33         if (getResource(environment.getDataSource()) == null) { 
34         } else { 
35           throw new TransientDataAccessResourceException( 
36               "SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization"); 
37         } 
38       } 
39     } else { 
40     } 
41     return session; 
42   } 
复制代码
复制代码
 1 public static void closeSqlSession(SqlSession session, SqlSessionFactory sessionFactory) { 
 2  //其实下面就是判断session是否被Spring事务管理,如果管理就会得到holder  
 3     SqlSessionHolder holder = (SqlSessionHolder) getResource(sessionFactory); 
 4     if ((holder != null) && (holder.getSqlSession() == session)) { 
 5    //这里释放的作用,不是关闭,只是减少一下引用数,因为后面可能会被复用 
 6       holder.released(); 
 7     } else { 
 8    //如果不是被spring管理,那么就不会被Spring去关闭回收,就需要自己close 
 9       session.close(); 
10     } 
11   } 
复制代码

其实通过上面的代码我们可以看出 Mybatis在很多地方都用到了代理模式,这个模式可以说是一种经典模式,其实不紧紧在Mybatis当中使用广泛,Spring的事物,AOP ,连接池技术 等技术都使用了代理技术。在后面的文章中我们来分析Spring的抽象事物管理机制。

 

 转载自:http://www.cnblogs.com/daxin/p/3544188.html

分享到:
评论

相关推荐

    mybatis-plus源码

    在MyBatis-Plus源码中,我们可以看到如何实现这些功能,例如,条件构造器是如何通过反射和OGNL表达式解析来动态构建SQL的,BaseMapper和BaseService是如何协同工作的,以及如何通过AutoFillMetaObjectHandler自动...

    mybatis-3.5.0源码

    在分析MyBatis-3.5.0源码时,我们可以深入了解其内部工作原理,例如如何解析配置文件、如何构建SqlSessionFactory、如何执行SQL语句、以及如何处理结果映射等。这对于理解和优化MyBatis的应用,以及学习数据库访问的...

    spring mvc mybatis项目源码

    在Spring MVC和MyBatis整合的项目中,通常会使用Spring的`@Autowired`注解来注入MyBatis的SqlSessionTemplate或SqlSessionFactory,这样可以在Controller中直接调用Mapper接口的方法进行数据操作。同时,Spring的...

    【新技术】java框架源码springmvc+mybatisJava源码

    【新技术】Java框架源码分析:SpringMVC与MyBatis深度解析 SpringMVC与MyBatis是Java开发中最常用的两大开源框架,它们在Web应用程序的开发中扮演着核心角色。SpringMVC作为Spring框架的一部分,负责处理HTTP请求,...

    源码分析专题之Mybatis课程一之源码分析与实现.pdf

    根据提供的文件内容,我们可以展开关于Mybatis源码分析的详细知识点介绍。Mybatis是一个流行的Java持久层框架,它用于简化与数据库交互的复杂性。源码分析是理解框架内部工作原理的绝佳方式,同时也能够加深对设计...

    mybatis3.4.1jar包及框架源码

    通过Spring的`SqlSessionFactoryBean`和`SqlSessionTemplate`,可以轻松地将MyBatis集成到Spring应用中,实现DAO的自动装配和事务管理。 在实际项目中,下载MyBatis 3.4.1的jar包和源码有助于理解和学习MyBatis的...

    springMVC+mybatis+mysql项目源码

    【SpringMVC+MyBatis+MySQL项目源码解析】 在现代Web开发中,SpringMVC、MyBatis和MySQL的组合是常见的技术栈,它们各自承担着不同的职责,共同构建了一个高效、灵活的后端架构。SpringMVC作为Spring框架的一部分,...

    mybatis mybatis-spring source jar

    源码解析可以帮助我们理解如何配置数据源、读取配置文件以及构建会话工厂。 4. **Executor**: 执行器是 MyBatis 执行 SQL 的核心组件,包括 SimpleExecutor、ReuseExecutor 和 BatchExecutor。源码中可以研究它们的...

    java-mybatis、springmvc 整合demo源码(druid-demo)

    整合的核心在于Spring对MyBatis的管理,包括SqlSessionFactory的创建、Mapper接口的扫描以及SqlSessionTemplate或SqlSessionDaoSupport的使用。通常,我们会创建一个配置类,如`MybatisConfig`,在其中配置数据源、...

    Mybatis源代码+jar包

    这个版本在当时是最新版,提供了解析XML配置、动态SQL等功能,使得开发者能更好地控制SQL执行。 源代码部分: Mybatis的源代码对于开发者来说是一份宝贵的资源,可以深入理解其内部工作原理。通过阅读源码,我们...

    源码分析专题之Mybatis课程一之源码分析与实现2

    MyBatis 与 Spring 集成时,会使用 mybatis-spring 库,它提供了 SqlSessionTemplate 和 SqlSessionDaoSupport 等组件,使得 MyBatis 可以无缝集成到 Spring 的事务管理中。 源码分析的设计理念是通过理解现有的...

    Spring+SpringMVC+Mybatis框架整合源码下载(SSM)

    6. **Spring与Mybatis整合**:通过`@Autowired`注解将Mybatis的SqlSessionTemplate或SqlSessionDaoSupport注入到Spring管理的bean中。 **总结** SSM框架整合提供了强大的企业级应用开发能力,Spring管理业务逻辑和...

    【新技术】java框架源码springmvc+mybatisJava实用源码整理learns

    【新技术】Java框架源码分析:SpringMVC与MyBatis深度解析 SpringMVC与MyBatis是Java开发中最常用的两大框架,它们在企业级应用中占据着核心地位。SpringMVC作为Spring框架的一部分,提供了强大的MVC设计模式实现,...

    mybatis学习总结:mybatis和spring, spring boot的集成

    6. **源码解析** - 理解MyBatis-Spring的源码有助于深入掌握其实现原理,例如SqlSessionTemplate如何执行SQL,MapperFactoryBean如何创建Mapper实例等。 通过上述集成,开发者可以充分利用Spring的便利性和MyBatis...

    Spring boot + Mybatis + Freemarker

    - 创建视图解析器:Spring Boot默认已经配置了FreeMarkerViewResolver,可以自定义视图解析路径。 - 模板文件:创建FTL(FreeMarker Template Language)模板文件,其中可以使用FreeMarker语法进行动态内容生成。 - ...

    spring4+springMVC+Mybatis3.2整合源码

    6. **集成Mybatis与Spring**:通过Spring的Mybatis-Spring库,将Mybatis的SqlSessionTemplate或SqlSessionDaoSupport注入到Service层,实现DAO层与Service层的解耦。 7. **测试**:编写JUnit测试用例,验证各组件的...

    maven+springmvc4+mybatis源代码

    通过配置`mybatis-config.xml`,开发者可以定义SQL映射文件的位置,`@Mapper`注解用于标记映射接口,而Spring的`SqlSessionTemplate`或`SqlSessionFactoryBean`则用于执行SQL语句。 **源代码结构** 在名为`web_app`...

    源码分析专题之Mybatis课程一之源码分析与实现21

    这是MyBatis与Spring集成的库,它使得MyBatis可以无缝地工作在Spring环境中,提供了诸如SqlSessionFactoryBean、SqlSessionTemplate和MapperFactoryBean等组件,简化了事务管理、依赖注入和Mapper的注册。...

    spring+mybatis 企业应用实战源码(2-10章)

    3. **第4章**:Spring与Mybatis的整合,主要涉及如何将Mybatis的SqlSessionTemplate或SqlSessionDaoSupport集成到Spring的IoC容器中,实现数据访问的事务管理。此外,可能会讲解Mybatis的动态SQL功能,如if、choose...

    mybatis-spring-1.0.1-bundle.zip

    《MyBatis-Spring 1.0.1 框架深度解析》 MyBatis-Spring 是一个轻量级的框架,它将 MyBatis 和 Spring 进行了无缝集成,使得在 Spring 应用中使用 MyBatis 变得更加简单。这个名为 "mybatis-spring-1.0.1-bundle....

Global site tag (gtag.js) - Google Analytics