mybatis源码分析(8)-----事务(mybatis管理、spring管理)
写在前面
接口: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管理)的更多相关文章
- MyBatis源码分析(六):Spring整合分析
一.Mybatis-Spring源码结构 二.Myabtis交给Spring管理的组件 1. dataSource 数据源 配置一个数据源,只要是实现了javax.sql.DataSource接口就可 ...
- MyBatis源码分析-IDEA新建MyBatis源码工程
MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...
- mybatis源码分析(2)——事务概述
这篇文章主要对mybatis中的事务做一简单的分析,帮助读者理清一些概念. 先来看看在JAVA事务的相关技术,在JAVA中有两类事务,JDBC事务和JTA事务,如果是JDBC类型的事务,则是由Conn ...
- MyBatis源码分析-SQL语句执行的完整流程
MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...
- Mybatis源码分析
MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...
- MyBatis源码分析-MyBatis初始化流程
MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...
- MyBatis源码分析(5)——内置DataSource实现
@(MyBatis)[DataSource] MyBatis源码分析(5)--内置DataSource实现 MyBatis内置了两个DataSource的实现:UnpooledDataSource,该 ...
- MyBatis源码分析(4)—— Cache构建以及应用
@(MyBatis)[Cache] MyBatis源码分析--Cache构建以及应用 SqlSession使用缓存流程 如果开启了二级缓存,而Executor会使用CachingExecutor来装饰 ...
- Mybatis源码分析-BaseExecutor
根据前文Mybatis源码分析-SqlSessionTemplate的简单分析,对于SqlSession的CURD操作都需要经过Executor接口的update/query方法,本文将分析下Base ...
- MyBatis 源码分析 - 缓存原理
1.简介 在 Web 应用中,缓存是必不可少的组件.通常我们都会用 Redis 或 memcached 等缓存中间件,拦截大量奔向数据库的请求,减轻数据库压力.作为一个重要的组件,MyBatis 自然 ...
随机推荐
- Linux kernel学习-内存管理
转自:https://zohead.com/archives/linux-kernel-learning-memory-management/ 本文同步自(如浏览不正常请点击跳转):https://z ...
- uboot makefile构建分析-续
前言 这篇博文是 uboot makefile构建分析的续篇,继续分析uboot构建u-boot.bin的过程 构建u-boot.bin过程分析 makefile一开始,就是确定链接脚本.在构建ubo ...
- WebClient vs HttpClient vs HttpWebRequest
转载:http://www.diogonunes.com/blog/webclient-vs-httpclient-vs-httpwebrequest/ Just when I was startin ...
- yolo回归型的物体检测
本弱又搬了另外一个博客的讲解: 缩进YOLO全称You Only Look Once: Unified, Real-Time Object Detection,是在CVPR2016提出的一种目标检测算 ...
- strptime和strptime函数理解
#include <stdio.h> #include <time.h> int main() { struct tm tm; char buf[255]; strptime( ...
- [Ext JS 4] MVC 应用程序框架
前言 大型客户端应用程序总是很难编写,很难组织和很难维护.随着功能的增加和更多的开发人员加入项目,对项目的控制也越来越困难了.Ext JS 4 提供了一个新的应用程序框架帮助组织代码. 模型 - 一组 ...
- linux抓包工具tcpdump基本使用
tcpdump 是一款灵活.功能强大的抓包工具,能有效地帮助排查网络故障问题. tcpdump 是一个命令行实用工具,允许你抓取和分析经过系统的流量数据包.它通常被用作于网络故障分析工具以及安全工具. ...
- 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 ...
- 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 ...
- 洛谷 P1202 [USACO1.1]黑色星期五Friday the Thirteenth 题解
题目传送门 这道题暴力就能解决. #include<bits/stdc++.h> using namespace std; int xi; ,ans[]; int main() { int ...