mybatis--MapperProxy事务
上篇 详细分析了org.mybatis.spring.mapper.MapperScannerConfigurer 和 org.mybatis.spring.SqlSessionFactoryBean的作用,可以直接看最后的总结
MapperFactoryBean是mapper接口的入口,它包含了sqlSessionFactory的封装SqlSessionTemplate,而sqlSessionFactory又包含了mapper xml的组装Configuration对象
从SqlSessionTemplate的
public <T> T getMapper(Class<T> type) {
return this.getConfiguration().getMapper(type, this);
}
开始,进入Configuration的getMapper(type,sqlsession)
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return this.mapperRegistry.getMapper(type, sqlSession);
}
进入MapperRegistry
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
MapperProxyFactory mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
if(mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
} else {
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception var5) {
throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
}
}
}
由MapperProxyFactory生成代理MapperProxy
protected T newInstance(MapperProxy<T> mapperProxy) {
return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
MapperProxy mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
return this.newInstance(mapperProxy);
}
所以最终的调用会进入MapperProxy,接下来几步在 mybatis缓存 中有介绍,会调用sqlSession(实际是SqlSessionTemplate)中的方法,看构造方法:
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
Assert.notNull(sqlSessionFactory, "Property \'sqlSessionFactory\' is required");
Assert.notNull(executorType, "Property \'executorType\' is required");
this.sqlSessionFactory = sqlSessionFactory;
this.executorType = executorType;
this.exceptionTranslator = exceptionTranslator;
this.sqlSessionProxy = (SqlSession)Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionTemplate.SqlSessionInterceptor());
}
会对SqlSessionFactory生成代理,实际调用这个代理的方法
public <T> T selectOne(String statement) {
return this.sqlSessionProxy.selectOne(statement);
}
1. 进入SqlSessionTemplate.SqlSessionInterceptor
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = SqlSessionUtils.getSqlSession(SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
......
Object t = method.invoke(sqlSession, args);
......
}
看SqlSessionUtils.getSqlSession方法:
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
Assert.notNull(sessionFactory, "No SqlSessionFactory specified");
Assert.notNull(executorType, "No ExecutorType specified");
SqlSessionHolder holder = (SqlSessionHolder)TransactionSynchronizationManager.getResource(sessionFactory);
if(holder != null && holder.isSynchronizedWithTransaction()) {
if(holder.getExecutorType() != executorType) {
throw new TransientDataAccessResourceException("Cannot change the ExecutorType when there is an existing transaction");
} else {
holder.requested();
if(logger.isDebugEnabled()) {
logger.debug("Fetched SqlSession [" + holder.getSqlSession() + "] from current transaction");
}
return holder.getSqlSession();
}
} else {//进入这里呀呀呀
if(logger.isDebugEnabled()) {
logger.debug("Creating a new SqlSession");
}
//step 1.1
SqlSession session = sessionFactory.openSession(executorType);
if(TransactionSynchronizationManager.isSynchronizationActive()) {
Environment environment = sessionFactory.getConfiguration().getEnvironment();
if(environment.getTransactionFactory() instanceof SpringManagedTransactionFactory) {
if(logger.isDebugEnabled()) {
logger.debug("Registering transaction synchronization for SqlSession [" + session + "]");
}
//step 1.2
holder = new SqlSessionHolder(session, executorType, exceptionTranslator);
TransactionSynchronizationManager.bindResource(sessionFactory, holder);
TransactionSynchronizationManager.registerSynchronization(new SqlSessionUtils.SqlSessionSynchronization(holder, sessionFactory));
holder.setSynchronizedWithTransaction(true);
holder.requested();
} else {
if(TransactionSynchronizationManager.getResource(environment.getDataSource()) != null) {
throw new TransientDataAccessResourceException("SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization");
}
if(logger.isDebugEnabled()) {
logger.debug("SqlSession [" + session + "] was not registered for synchronization because DataSource is not transactional");
}
}
} else if(logger.isDebugEnabled()) {
logger.debug("SqlSession [" + session + "] was not registered for synchronization because synchronization is not active");
}
return session;
}
}
1.1 进入DefaultSqlSessionFactory openSession方法:
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
DefaultSqlSession var8;
try {
Environment e = this.configuration.getEnvironment();
//springManagedTransactionFactory
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(e);
tx = transactionFactory.newTransaction(e.getDataSource(), level, autoCommit);
Executor executor = this.configuration.newExecutor(tx, execType, autoCommit);
var8 = new DefaultSqlSession(this.configuration, executor);
} catch (Exception var12) {
this.closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12);
} finally {
ErrorContext.instance().reset();
}
return var8;
}
进入SpringManagedTransactionFactory的
newTransaction(e.getDataSource(), level, autoCommit);
返回
return new SpringManagedTransaction(dataSource);
这个SpringManagedTransaction比较特别,因为
private void openConnection() throws SQLException {
this.connection = DataSourceUtils.getConnection(this.dataSource);
this.autoCommit = this.connection.getAutoCommit();
this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);
if(this.logger.isDebugEnabled()) {
this.logger.debug("JDBC Connection [" + this.connection + "] will" + (this.isConnectionTransactional?" ":" not ") + "be managed by Spring");
}
}
因为它的连接来自DataSourceUtils
public static Connection doGetConnection(DataSource dataSource) throws SQLException {
Assert.notNull(dataSource, "No DataSource specified");
ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(dataSource);
if(conHolder == null || !conHolder.hasConnection() && !conHolder.isSynchronizedWithTransaction()) {
logger.debug("Fetching JDBC Connection from DataSource");
Connection con = dataSource.getConnection();
if(TransactionSynchronizationManager.isSynchronizationActive()) {
logger.debug("Registering transaction synchronization for JDBC Connection");
ConnectionHolder holderToUse = conHolder;
if(conHolder == null) {
holderToUse = new ConnectionHolder(con);
} else {
conHolder.setConnection(con);
}
holderToUse.requested();
TransactionSynchronizationManager.registerSynchronization(new DataSourceUtils.ConnectionSynchronization(holderToUse, dataSource));
holderToUse.setSynchronizedWithTransaction(true);
if(holderToUse != conHolder) {
TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
}
}
return con;
} else {
conHolder.requested();
if(!conHolder.hasConnection()) {
logger.debug("Fetching resumed JDBC Connection from DataSource");
conHolder.setConnection(dataSource.getConnection());
}
return conHolder.getConnection();
}
}
这一步就和 spring--事务原理 中分析的对接了!!!connection连接对象来自当前线程绑定的ConnectionHolder中的connection对象
最终 DefaultSqlSession-》Executor-》Transaction-》当前线程绑定的ConnectionHolder中的connection对象
1.2 构建SqlSessionHolder-》DefaultSqlSession,并绑定到当前线程<sessionFactory,session holder>
2. DefaultSqlSession的执行见 mybatis缓存
mybatis--MapperProxy事务的更多相关文章
- spring boot配置mybatis和事务管理
spring boot配置mybatis和事务管理 一.spring boot与mybatis的配置 1.首先,spring boot 配置mybatis需要的全部依赖如下: <!-- Spri ...
- Mybaits 源码解析 (十二)----- Mybatis的事务如何被Spring管理?Mybatis和Spring事务中用的Connection是同一个吗?
不知道一些同学有没有这种疑问,为什么Mybtis中要配置dataSource,Spring的事务中也要配置dataSource?那么Mybatis和Spring事务中用的Connection是同一个吗 ...
- Spring Boot -- Spring Boot之@Async异步调用、Mybatis、事务管理等
这一节将在上一节的基础上,继续深入学习Spring Boot相关知识,其中主要包括@Async异步调用,@Value自定义参数.Mybatis.事务管理等. 本节所使用的代码是在上一节项目代码中,继续 ...
- SpringMVC+MyBatis整合——事务管理
项目一直没有做事务管理,这几天一直在想着解决这事,今天早上终于解决了.接下来直接上配置步骤. 我们项目采用的基本搭建环境:SpringMVC.MyBatis.Oracle11g.WebLogic10. ...
- myBatis之事务管理
1. myBatis单独使用时,使用SqlSession来处理事务: public class MyBatisTxTest { private static SqlSessionFactory sql ...
- MyBatis+Spring 事务管理
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://kinglixing.blog.51cto.com/34 ...
- spring学习总结(mybatis,事务,测试JUnit4,日志log4j&slf4j,定时任务quartz&spring-task,jetty,Restful-jersey等)
在实战中学习,模仿博客园的部分功能.包括用户的注册,登陆:发表新随笔,阅读随笔:发表评论,以及定时任务等.Entity层设计3张表,分别为user表(用户),essay表(随笔)以及comment表( ...
- Spring 与 mybatis整合---事务管理
MyBatis与Spring整合前后事务管理有所区别 整合前:通过 session = sessionFactory.openSession(true); //或者是false 设置事务是否自动提交: ...
- mybatis+spring事务
http://www.mybatis.org/spring/zh/transactions.html 第四章 事务 一个使用 MyBatis-Spring 的主要原因是它允许 MyBatis 参与到 ...
- Spring+JTA+Atomikos+mybatis分布式事务管理
我们平时的工作中用到的Spring事务管理是管理一个数据源的.但是如果对多个数据源进行事务管理该怎么办呢?我们可以用JTA和Atomikos结合Spring来实现一个分布式事务管理的功能.了解JTA可 ...
随机推荐
- java获取数据库的所有列名和对应的数据库类型
/** * 连接数据库 * @param driver 数据库的驱动类 * @param url 数据库的地址 * @param userName 数据库的用户名 ...
- 【待补】java开发Web Service
Java中WebService实例 http://blog.csdn.net/kardelpeng/article/details/6321019 java 调用webservice的各种方法总结 h ...
- libevent库的使用方法
接写一个很简单的 Time Server 来当作例子:当你连上去以后 Server 端直接提供时间,然后结束连线.event_init() 表示初始化 libevent 所使用到的变数.event_s ...
- android 小知识点
小知识点总结 1. android中MotionEvent.ACTION_CANCEL事件如何被触发? 对于这个问题,android文档的说明很简短,想看明白很难.国外一网页说的还比较详细,写在这里分 ...
- Openfire开发配置,Openfire源代码配置,OpenFire二次开发配置(eclipse)
首先去官网把openfire的源码下下来: http://www.igniterealtime.org/downloads/source.jsp 1.下载后放到你的workspace当中,我的woek ...
- Android Fragment详解
一.什么是Fragment Android在3.0中引入了fragments的概念,主要目的是用在大屏幕设备上--例如平板电脑上,支持更加动态和灵活的UI设计.平板电脑的屏幕要比手机的大得多,有更多的 ...
- 企业应用架构模式阅读笔记 - Martin Fowler
1. 数据读取
- 【MongoDB】mongoimport and mongoexport of data (一)
In the software development, we usually are faced with a common question of exporting or importing d ...
- 【JavaScript】理解与使用Javascript中的回调函数
在Javascript中,函数是第一类对象,这意味着函数可以像对象一样按照第一类管理被使用.既然函数实际上是对象:它们能被“存储”在变量中,能作为函数参数被传递,能在函数中被创建,能从函数中返回. 因 ...
- iOS开发——实用技术OC篇&8行代码教你搞定导航控制器全屏滑动返回效果
8行代码教你搞定导航控制器全屏滑动返回效果 前言 如果自定了导航控制器的自控制器的leftBarButtonItem,可能会引发边缘滑动pop效果的失灵,是由于 self.interactivePop ...