写在前面

  接口:MyBatis的事务Transaction的接口有一下实现类

    JdbcTransaction 由jdbc管理的事务(即利用Connection对象完成对事务的提交(commit())、回滚(rollback())、关闭(close())等)

    ManagedTransaction 由容器管理事务 (这种机制MyBatis自身不会去实现事务管理,而是让程序的容器如(JBOSS,Weblogic)来实现对事务的管理)

     SpringManagedTransaction(位于mybatis-spring包中) 由spring来管理事务 myBatis单独为spring的事务集成,设计的类。本文章也是重要讲解此类的原理。

  设计:工厂模式

   Transaction---TransactionTransactionFactory

    JdbcTransaction ---JdbcTransactionFactory

    ManagedTransaction ---ManagedTransactionFactory

      SpringManagedTransaction---SpringManagedTransactionFactory

   持有者:

    Executor(执行器)即对于事务的所有操作,都是由执行器来调度

      Transaction

   Transaction接口

public interface Transaction {
//获取链接
Connection getConnection() throws SQLException;
//提交
void commit() throws SQLException;
//回滚
void rollback() throws SQLException;
//关闭
void close() throws SQLException;
}

  TransactionFactory接口

public interface TransactionFactory {
//相关属性设置
void setProperties(Properties props);
//通过链接开启获取一个事务对象
Transaction newTransaction(Connection conn);
//通过datasource获取一个事务对象
Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);
}

spring事务相关

  TransactionSynchronizationManager: spring 管理事务线程的抽象类,所有属性都是threadlocal和当前线程相关

public abstract class TransactionSynchronizationManager {
   private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal<Map<Object, Object>>("Transactional resources");
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations = new NamedThreadLocal<Set<TransactionSynchronization>>("Transaction synchronizations");
private static final ThreadLocal<String> currentTransactionName = new NamedThreadLocal<String>("Current transaction name");
private static final ThreadLocal<Boolean> currentTransactionReadOnly = new NamedThreadLocal<Boolean>("Current transaction read-only status");
private static final ThreadLocal<Integer> currentTransactionIsolationLevel = new NamedThreadLocal<Integer>("Current transaction isolation level");
private static final ThreadLocal<Boolean> actualTransactionActive = new NamedThreadLocal<Boolean>("Actual transaction active");
}

  

  当 spring开启事务管理(声明式事务、注解式事务):会初始化一个synchronizations,初始化一个空的Set<TransactionSynchronization>集合存放在当前线程中。

    public static void initSynchronization() throws IllegalStateException {
if (isSynchronizationActive()) {
throw new IllegalStateException("Cannot activate transaction synchronization - already active");
}
logger.trace("Initializing transaction synchronization");
synchronizations.set(new LinkedHashSet<TransactionSynchronization>());
}

  

  spring判断synchronizations是否存在,暴露的API

    public static boolean isSynchronizationActive() {
return (synchronizations.get() != null);
}

myBatis单独管理

  前提假设myBatis 和spring集成,且满足spring没有开启事务管理(声明式事务、注解式事务)

   在获取sqlSession的时候,会判断TransactionSynchronizationManager中的synchronizations是否存在:

    如果不存在,则不会注册SqlSessionHolder到resources中,也不会将SqlSessionSynchronization(myBatis对于TransactionSynchronization接口的实现类)注册到synchronizations中。

  private static void registerSessionHolder(SqlSessionFactory sessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator, SqlSession session) {
SqlSessionHolder holder;
//判断spring是否管理事务,即synchronizations是否存在值
if (TransactionSynchronizationManager.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);
//将SqlSessionFactory和SqlSessionHolder 绑定,注册到TransactionSynchronizationManager.resources中
TransactionSynchronizationManager.bindResource(sessionFactory, holder);
//注册sqlSessionSynchronization到TransactionSynchronizationManager.synchronizations中
TransactionSynchronizationManager.registerSynchronization(new SqlSessionSynchronization(holder, sessionFactory));
holder.setSynchronizedWithTransaction(true);
holder.requested();
} else {
if (TransactionSynchronizationManager.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");
}
}

  sqlSession调用Executor-->statmentHandler 执行sql的流程后,判断是否commit,已经sqlSession是否关闭。

  private class SqlSessionInterceptor implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = getSqlSession(
SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType,
SqlSessionTemplate.this.exceptionTranslator);
try {
//sqlSession目标方法执行
Object result = method.invoke(sqlSession, args);
//判断resources中是否存在绑定的sqlSession、sqlSessionFactory。不存在直接提交commit
if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
// force commit even on non-dirty sessions because some databases require
// a commit/rollback before calling close()
sqlSession.commit(true);
}
return result;
} catch (Throwable t) {
Throwable unwrapped = unwrapThrowable(t);
if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
// release the connection to avoid a deadlock if the translator is no loaded. See issue #22
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
sqlSession = null;
Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
if (translated != null) {
unwrapped = translated;
}
}
throw unwrapped;
} finally {
if (sqlSession != null) {
//改方法中会判断resources中是否存在绑定的sqlSession、sqlSessionFacotory。如果不存在,关闭sqlSession
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
}
}
}
}
  public static void closeSqlSession(SqlSession session, SqlSessionFactory sessionFactory) {
notNull(session, NO_SQL_SESSION_SPECIFIED);
notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED); SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
if ((holder != null) && (holder.getSqlSession() == session)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Releasing transactional SqlSession [" + session + "]");
}
holder.released();
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Closing non transactional SqlSession [" + session + "]");
}
session.close();
}
}

mybatis交由spring管理事务

   如果myBatis和spring集成,且spring开启了事务管理(声明式事务、注解式事务)

   myBatis会将sqlSession交给spring来管理。会在一个可能的事务方法中,将sqlSession交由spring管理。

  public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {

    notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);
notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);

//每一次获取sqlSession。都提前从resources中获取sqlSessionHolder
SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory); SqlSession session = sessionHolder(executorType, holder);
//如果spring管理了事务,则直接获取sqlSession
if (session != null) {
return session;
} if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Creating a new SqlSession");
}
//通过sqlSessionFactory 创建新的事务
session = sessionFactory.openSession(executorType);
registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);
return session;
}

mybatis源码分析(8)-----事务(mybatis管理、spring管理)的更多相关文章

  1. MyBatis源码分析(六):Spring整合分析

    一.Mybatis-Spring源码结构 二.Myabtis交给Spring管理的组件 1. dataSource 数据源 配置一个数据源,只要是实现了javax.sql.DataSource接口就可 ...

  2. MyBatis源码分析-IDEA新建MyBatis源码工程

    MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...

  3. mybatis源码分析(2)——事务概述

    这篇文章主要对mybatis中的事务做一简单的分析,帮助读者理清一些概念. 先来看看在JAVA事务的相关技术,在JAVA中有两类事务,JDBC事务和JTA事务,如果是JDBC类型的事务,则是由Conn ...

  4. MyBatis源码分析-SQL语句执行的完整流程

    MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...

  5. Mybatis源码分析

    MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...

  6. MyBatis源码分析-MyBatis初始化流程

    MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...

  7. MyBatis源码分析(5)——内置DataSource实现

    @(MyBatis)[DataSource] MyBatis源码分析(5)--内置DataSource实现 MyBatis内置了两个DataSource的实现:UnpooledDataSource,该 ...

  8. MyBatis源码分析(4)—— Cache构建以及应用

    @(MyBatis)[Cache] MyBatis源码分析--Cache构建以及应用 SqlSession使用缓存流程 如果开启了二级缓存,而Executor会使用CachingExecutor来装饰 ...

  9. Mybatis源码分析-BaseExecutor

    根据前文Mybatis源码分析-SqlSessionTemplate的简单分析,对于SqlSession的CURD操作都需要经过Executor接口的update/query方法,本文将分析下Base ...

  10. MyBatis 源码分析 - 缓存原理

    1.简介 在 Web 应用中,缓存是必不可少的组件.通常我们都会用 Redis 或 memcached 等缓存中间件,拦截大量奔向数据库的请求,减轻数据库压力.作为一个重要的组件,MyBatis 自然 ...

随机推荐

  1. Linux kernel学习-内存管理

    转自:https://zohead.com/archives/linux-kernel-learning-memory-management/ 本文同步自(如浏览不正常请点击跳转):https://z ...

  2. uboot makefile构建分析-续

    前言 这篇博文是 uboot makefile构建分析的续篇,继续分析uboot构建u-boot.bin的过程 构建u-boot.bin过程分析 makefile一开始,就是确定链接脚本.在构建ubo ...

  3. WebClient vs HttpClient vs HttpWebRequest

    转载:http://www.diogonunes.com/blog/webclient-vs-httpclient-vs-httpwebrequest/ Just when I was startin ...

  4. yolo回归型的物体检测

    本弱又搬了另外一个博客的讲解: 缩进YOLO全称You Only Look Once: Unified, Real-Time Object Detection,是在CVPR2016提出的一种目标检测算 ...

  5. strptime和strptime函数理解

    #include <stdio.h> #include <time.h> int main() { struct tm tm; char buf[255]; strptime( ...

  6. [Ext JS 4] MVC 应用程序框架

    前言 大型客户端应用程序总是很难编写,很难组织和很难维护.随着功能的增加和更多的开发人员加入项目,对项目的控制也越来越困难了.Ext JS 4 提供了一个新的应用程序框架帮助组织代码. 模型 - 一组 ...

  7. linux抓包工具tcpdump基本使用

    tcpdump 是一款灵活.功能强大的抓包工具,能有效地帮助排查网络故障问题. tcpdump 是一个命令行实用工具,允许你抓取和分析经过系统的流量数据包.它通常被用作于网络故障分析工具以及安全工具. ...

  8. LeetCode862. Shortest Subarray with Sum at Least K

    Return the length of the shortest, non-empty, contiguous subarray of A with sum at least K. If there ...

  9. LeetCode解题报告—— Best Time to Buy and Sell Stock

    Best Time to Buy and Sell Stock Say you have an array for which the ith element is the price of a gi ...

  10. 洛谷 P1202 [USACO1.1]黑色星期五Friday the Thirteenth 题解

    题目传送门 这道题暴力就能解决. #include<bits/stdc++.h> using namespace std; int xi; ,ans[]; int main() { int ...