写在前面

  接口: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. python基础===python自带idle的快捷键

    Ctrl + [ Ctrl + ]   缩进代码Alt+3 Alt+4 注释.取消注释代码行Alt+5 Alt+6 切换缩进方式 空格<=>TabAlt+/ 单词完成,只要文中出现过,就可 ...

  2. ssh -o 常用选项

    ssh -o ConnectTimeout=3 -o ConnectionAttempts=5 -o PasswordAuthentication=no -o StrictHostKeyCheckin ...

  3. python 爬图

    利用bs库进行爬取,在下载html时,使用代理user_agent来下载,并且下载次数是2次,当第一次下载失败后,并且http状态码是500-600之间,然后会重新下载一次 soup = Beauti ...

  4. Fiddler Web Session 列表(1)

    Web Session 列表 位置: Web Session 列表 位于Fiddler界面的左侧 ,是Fiddler所抓取到的所有Session会话的列表集合. Web Session 列表 栏名词解 ...

  5. hdu 5468(dfs序+容斥原理)

    Puzzled Elena Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)T ...

  6. 秀尔算法:破解RSA加密的“不灭神话” --zz

    http://netsecurity.51cto.com/art/201508/488766.htm RSA加密曾被视为最可靠的加密算法,直到秀尔算法出现,打破了RSA的不灭神话. RSA加密 VS ...

  7. 关于HTML5 boilerplate 的一些笔记

    最近在研究HTML5 boilerplate的模版,以此为线索可以有条理地学习一些前端的best practice,好过在W3C的文档汪洋里大海捞针……啊哈哈哈…… 开头的IE探测与no-js类是什么 ...

  8. 为什么可以这么快! awk 与python的应用

    这几天刚处理一个排序问题 源文件: 可以看到有11G大小,需要根据最后一列的热度来做一下排序.如果让你来做这样的排序,在linux环境下,你会如何处理呢? xch27@lanzhou:/asrdata ...

  9. python itertools模块练习

    参考 <python标准库> 也可以参考Vamei博客 列表用着很舒服,但迭代器不需要将所有数据同时存储在内存中. 本章练习一下python 标准库中itertools模块 合并 和 分解 ...

  10. Asp.net vNext 学习之路(二)

    View component(视图组件)应该是MVC6 新加的一个东西,类似于分部视图.本文将演示在mvc 6中 怎么添加视图组件以及怎么在视图中注入一个服务. 本文包括以下内容: 1,创建一个新的a ...