工作中,需要学习一下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. [Java开发之路](6)File类的使用

    1. 构造方法 构造方法 描写叙述 File(String pathname) 通过将给定的路径名字符串转换为抽象路径名来创建一个新的文件实例. File(String parent , String ...

  2. HIT 2255 Not Fibonacci(矩阵高速幂)

    #include <iostream> #include <cstdio> #include <cstring> using namespace std; cons ...

  3. UITableView去掉最后切割线的一种方法

    UITableView以style:UITableViewStylePlain方式创建时.仅仅要有cell,就会有一条黑线 哪怕至于一个cell也会有,如图 在网上找了集中方法,都不好使,比方http ...

  4. .net framework tools

    https://docs.microsoft.com/en-us/dotnet/framework/tools/ Resgen.exe (Resource File Generator) Conver ...

  5. HDU2665 kth number 线段树做法

    题意:求区间第k小 思路: 线段树 每个节点上保存 当前区间已经排序好的序列 (归并一下就好了嘛 复杂度 O(l)的) 这样建树的时空复杂度都是 O(nlogn)的 对于 每次询问 二分一个答案 在树 ...

  6. mysql 5.6 安装教程

    首先是下载 mysql-installer-community-5.6.14.0.msi ,大家可以到 mysql 官方网去下载,也可以到笔者所提供的地址去下载,下载方法在这里就不多说了,我想大家都明 ...

  7. Chrome OS 70 发布:这是安卓的私生子吗?

    谷歌于28日正式宣布推出Chrome OS 70.这个最新的Chrome OS系统在一些设计上具备了更多安卓风味,为配备了触摸屏的Chromebook.平板电脑和二合一设备带来了操作界面改善. 据9t ...

  8. 把书《CUDA By Example an Introduction to General Purpose GPU Programming》读薄

    鉴于自己的毕设需要使用GPU CUDA这项技术,想找一本入门的教材,选择了Jason Sanders等所著的书<CUDA By Example an Introduction to Genera ...

  9. java web应用调用python深度学习训练的模型

    之前参见了中国软件杯大赛,在大赛中用到了深度学习的相关算法,也训练了一些简单的模型.项目线上平台是用java编写的web应用程序,而深度学习使用的是python语言,这就涉及到了在java代码中调用p ...

  10. Linux下Oracle的sqlplus中上下左右退格键无法使用

    一.配置yum源并安装readline* 配置本地yum 1.挂载光盘 mount /dev/cdrom /mnt/media 2,新建本地yun源的配置文件 vi /etc/yum.repos.d/ ...