工作中,需要学习一下MyBatis sqlSession的产生过程,翻看了mybatis-spring的源码,阅读了一些mybatis的相关doc,对mybatis sqlSession有了一些认知和理解,这里简单的总结和整理一下。

首先, 通过翻阅源码,我们来整理一下mybatis进行持久化操作时重要的几个类:

  • SqlSessionFactoryBuilder:build方法创建SqlSessionFactory实例。

  • SqlSessionFactory:创建SqlSession实例的工厂。

  • SqlSession:用于执行持久化操作的对象,类似于jdbc中的Connection。

  • SqlSessionTemplate:MyBatis提供的持久层访问模板化的工具,线程安全,可通过构造参数或依赖注入SqlSessionFactory实例。

Hibernate是与MyBatis类似的orm框架,这里与Hibernate进行一下对比,Hibernate中对于connection的管理,是通过以下几个重要的类:

  • SessionFactory:创建Session实例的工厂,类似于MyBatis中的SqlSessionFactory。

  • Session:用来执行持久化操作的对象,类似于jdbc中的Connection。

  • HibernateTemplate:Hibernate提供的持久层访问模板化的工具,线程安全,可通过构造参数或依赖注入SessionFactory实例。

在日常的开发中,我们经常需要这样对MyBatis和Spring进行集成,把sqlSessionFactory交给Spring管理,通常情况下,我们这样配置:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
</bean>

通过上面的配置,Spring将自动创建一个SqlSessionFactory对象,其中使用到了org.mybatis.spring.SqlSessionFactoryBean,其 是MyBatis为Spring提供的用于创建SqlSessionFactory的类,将在Spring应用程序的上下文建议一下可共享的 MyBatis SqlSessionFactory实例,我们可以通过依赖注入将SqlSessionFactory传递给MyBatis的一些接口。

如果通过Spring进行事务的管理,我们需要增加Spring注解的事务管理机制,如下配置:

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>
 
<tx:annotation-driven/>

这样,我们就可以使用Spring @Transactional注解,进行事务的控制,表明所注释的方法应该在一个事务中运行。 Spring将在事务成功完成后提交事务,在事务发生错误时进行异常回滚,而且,Spring会将产生的MyBatis异常转换成适当的 DataAccessExceptions,从而提供具体的异常信息。

下面,我们通过分析SqlSessionUtils中getSession的源码,来详细的了解一下sqlSession的产生过程,源码如下:

public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
 
  notNull(sessionFactory, "No SqlSessionFactory specified");
  notNull(executorType, "No ExecutorType specified");
 
  SqlSessionHolder holder = (SqlSessionHolder) getResource(sessionFactory);
 
  if (holder != null && holder.isSynchronizedWithTransaction()) {
    if (holder.getExecutorType() != executorType) {
      throw new TransientDataAccessResourceException("Cannot change the ExecutorType when there is an existing transaction");
    }
 
    holder.requested();
 
    if (logger.isDebugEnabled()) {
      logger.debug("Fetched SqlSession [" + holder.getSqlSession() + "] from current transaction");
    }
 
    return holder.getSqlSession();
  }
 
  if (logger.isDebugEnabled()) {
    logger.debug("Creating a new SqlSession");
  }
 
  SqlSession session = sessionFactory.openSession(executorType);
 
  // Register session holder if synchronization is active (i.e. a Spring TX is active)
  //
  // Note: The DataSource used by the Environment should be synchronized with the
  // transaction either through DataSourceTxMgr or another tx synchronization.
  // Further assume that if an exception is thrown, whatever started the transaction will
  // handle closing / rolling back the Connection associated with the SqlSession.
  if (isSynchronizationActive()) {
    Environment environment = sessionFactory.getConfiguration().getEnvironment();
 
    if (environment.getTransactionFactory() instanceof SpringManagedTransactionFactory) {
      if (logger.isDebugEnabled()) {
        logger.debug("Registering transaction synchronization for SqlSession [" + session + "]");
      }
 
      holder = new SqlSessionHolder(session, executorType, exceptionTranslator);
      bindResource(sessionFactory, holder);
      registerSynchronization(new SqlSessionSynchronization(holder, sessionFactory));
      holder.setSynchronizedWithTransaction(true);
      holder.requested();
    } else {
      if (getResource(environment.getDataSource()) == null) {
        if (logger.isDebugEnabled()) {
          logger.debug("SqlSession [" + session + "] was not registered for synchronization because DataSource is not transactional");
        }
      } else {
        throw new TransientDataAccessResourceException(
            "SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization");
      }
    }
  } else {
    if (logger.isDebugEnabled()) {
      logger.debug("SqlSession [" + session + "] was not registered for synchronization because synchronization is not active");
    }
  }
 
  return session;
}

上面的getSession方法,会从Spring的事务管理器中获取一个SqlSession或创建一个新的SqlSession,将试图从当前事务中得到一个SqlSession,然后,如果配置有事务管理器的工厂并且Spring 的事务管理器是活跃的,它将会锁定当前事务的SqlSession,保证同步。主要是通过以下几个步骤进行SqlSession的创建:

  1. 它会首先获取SqlSessionHolder,SqlSessionHolder用于在TransactionSynchronizationManager中保持当前的SqlSession。

  2. 如果holder不为空,并且holder被事务锁定,则可以通过holder.getSqlSession()方法,从当前事务中获取sqlSession,即 Fetched SqlSession from current transaction。

  3. 如果不存在holder或没有被事务锁定,则会创建新的sqlSession,即 Creating a new SqlSession,通过sessionFactory.openSession()方法。

  4. 如果当前线程的事务是活跃的,将会为SqlSession注册事务同步,即 Registering transaction synchronization for SqlSession。

关于MyBatis sqlSession的一点整理的更多相关文章

  1. mybatis 一点整理

    mapper指定对应的接口 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper ...

  2. MyBatis sqlsession 简化 使用工具类创建

    2019-04-09 @Test public void Test() throws Exception { // 1.读取配置文件 String resource = "mybatis-c ...

  3. mybatis SqlSession事务

    mybatis版本:3.4.6. mybatis默认的SqlSessionFactory是DefaultSqlSessionFactory,它openSession()的源码是: public Sql ...

  4. mybatis使用的一点小结:session运行模式及批量提交(转)

    mybatis的执行器有三种类型: ExecutorType.SIMPLE 这个类型不做特殊的事情,它只为每个语句创建一个PreparedStatement. ExecutorType.REUSE 这 ...

  5. mybatis sqlsession与sqlsquery、transaction、connection

    sqlsession和connection 一个sqlsession一般对应一个connection,并且mybatis默认每次获取session都会开启一个事务,且不自动提交事务.如果更新操作完成后 ...

  6. mybatis中的一点优化问题(数据库连接分开,别名,日志打印)

    一:数据的链接 1.目录 2.新建一个db.properties driver=com.mysql.jdbc.Driver url=jdbc:mysql://127.0.0.1:3308/mybati ...

  7. Spring Transaction + MyBatis SqlSession事务管理机制[marked]

  8. 关于Java IO InputStream 的一点整理!

    程序的开发其中一直在用文件的读写.可是对于java其中输入流以及输出流仅仅是会用不理解,一直以来想搞清楚其,可是一直没有运行(悲剧).今天早上抽出半个小时通过JDK API1.6.0中文版帮助逐步的了 ...

  9. IBatis 2.x 和 MyBatis 3.0.x 的区别(从 iBatis 到 MyBatis)

    从 iBatis 到 MyBatis,你准备好了吗? 对于从事 Java EE 的开发人员来说,iBatis 是一个再熟悉不过的持久层框架了,在 Hibernate.JPA 这样的一站式对象 / 关系 ...

随机推荐

  1. php实现简单算法2

    php实现简单算法2 去弄php手册,里面有数据结构,有数据结构就好办了,我的算法基础那么好. 而且的话有数据结构的话再配合我脑中的那些算法了,我就都ok啦. 在手册里面搜索php数据结构就好 路径如 ...

  2. hdoj--5053--the Sum of Cube(水)

    the Sum of Cube Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Tot ...

  3. matlab 常用机器学习算法的实现

    1. KNN 分类 load fisheriris X = meas; Y = species; % 3 分类问题 % 通过训练集进行训练 Mdl = fitcknn(X, Y, 'NumNeighb ...

  4. 25.Detours劫持技术

    Detours可以用来实现劫持,他是微软亚洲研究院开发出来的工具,要实现它首先需要安装Detours. 安装地址链接:https://pan.baidu.com/s/1eTolVZs 密码:uy8x ...

  5. OPENCV(6) —— 角点检测

    图像特征的类型通常指边界.角点(兴趣点).斑点(兴趣区域).角点就是图像的一个局部特征,应用广泛.harris角点检测是一种直接基于灰度图像的角点提取算法,稳定性高,尤其对L型角点检测精度高,但由于采 ...

  6. ES6学习笔记(六)数组的扩展

    1.扩展运算符 1.1含义 扩展运算符(spread)是三个点(...).它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列. console.log(...[1, 2, 3]) // ...

  7. opengl绘制三维人物luweiqi

    素材中有四个.bmp格式的纹理文件和一个.txt的模型参数文件 文件格式说明: 纹理文件数量 纹理文件1(字符串)//.bmp 纹理文件2(字符串) 纹理文件3(字符串) . . . 材质数量 amb ...

  8. make---GNU编译工具

    make命令是GNU的工程化编译工具,用于编译众多相互关联的源代码问价,以实现工程化的管理,提高开发效率. 知识扩展 无论是在linux 还是在Unix环境 中,make都是一个非常重要的编译命令.不 ...

  9. Android学习总结(1)——好的 Android 开发习惯

    Android编码规范 java代码中不出现中文,最多注释中可以出现中文: 局部变量命名.静态成员变量命名:只能包含字母,单词首字母出第一个都为大写,其他字母都为小写: 常量命名:只能包含字母和 ,字 ...

  10. 记真实自己,炫精彩人生---《爱记》app使用体验

    真的有款神器吗,能找到合适的Ta,能秀出自己的新生活,能让自己的心情舒爽,有,体验了下.就是爱记.果粉的福利. [爱记]是集心情记录.分享.评价与交流于一体的工具,TA是你心灵休憩的港湾,也是你记忆放 ...