@MapperScan注册:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
public @interface MapperScan {//默认会生成MapperFactoryBean注册到容器中,下文重点分析Class<? extends MapperFactoryBean> factoryBean() default MapperFactoryBean.class;}//MapperScannerRegistrar
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {private ResourceLoader resourceLoader;/*** {@inheritDoc}*/@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);//...List<String> basePackages = new ArrayList<String>();for (String pkg : annoAttrs.getStringArray("value")) {if (StringUtils.hasText(pkg)) {basePackages.add(pkg);}}for (String pkg : annoAttrs.getStringArray("basePackages")) {if (StringUtils.hasText(pkg)) {basePackages.add(pkg);}}for (Class<?> clazz : annoAttrs.getClassArray("basePackageClasses")) {basePackages.add(ClassUtils.getPackageName(clazz));}scanner.registerFilters();//扫描指定包路径下面的Mybatis接口类,生成BeanDefinition注册到Spring容器。scanner.doScan(StringUtils.toStringArray(basePackages));}
}

ClassPathMapperScanner:

public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {GenericBeanDefinition definition;for (BeanDefinitionHolder holder : beanDefinitions) {definition = (GenericBeanDefinition) holder.getBeanDefinition();//...//可以看到注册的Bean为MapperFactoryBeandefinition.setBeanClass(this.mapperFactoryBean.getClass());definition.getPropertyValues().add("addToConfig", this.addToConfig);//...}}//省略其他代码
}

MapperFactoryBean:

public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {private Class<T> mapperInterface;private boolean addToConfig = true;public MapperFactoryBean() {}public MapperFactoryBean(Class<T> mapperInterface) {this.mapperInterface = mapperInterface;}/*** 返回具体的对象,具体逻辑在父类中实现*/@Overridepublic T getObject() throws Exception {return getSqlSession().getMapper(this.mapperInterface);}/*** {@inheritDoc}*/@Overridepublic Class<T> getObjectType() {return this.mapperInterface;}/*** {@inheritDoc}*/@Overridepublic boolean isSingleton() {return true;}//省略其他代码...
}//父类SqlSessionDaoSupport中生成Mybatis接口对象的具体逻辑
public abstract class SqlSessionDaoSupport extends DaoSupport {private SqlSession sqlSession;private boolean externalSqlSession;public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {if (!this.externalSqlSession) {this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);}}public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {this.sqlSession = sqlSessionTemplate;this.externalSqlSession = true;}public SqlSession getSqlSession() {return this.sqlSession;}}

SqlSessionTemplate:

该类为线程安全的SqlSession,其中提供了接口代理对象的生成逻辑。

public class SqlSessionTemplate implements SqlSession, DisposableBean {public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,PersistenceExceptionTranslator exceptionTranslator) {notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");notNull(executorType, "Property 'executorType' is required");this.sqlSessionFactory = sqlSessionFactory;this.executorType = executorType;this.exceptionTranslator = exceptionTranslator;//通过动态代理生成了一个由Spring托管的SqlSessionthis.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(),new Class[] { SqlSession.class },new SqlSessionInterceptor());}//代理业务类private class SqlSessionInterceptor implements InvocationHandler {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//此处会构造一个DefaultSqlSession,内部使用SpringManagedTransaction作为Exector的事务对象//注意:不是每次都构造,会将SqlSession绑定到线程,以便同一个线程获取的是同一个SqlSessionSqlSession sqlSession = getSqlSession(SqlSessionTemplate.this.sqlSessionFactory,SqlSessionTemplate.this.executorType,SqlSessionTemplate.this.exceptionTranslator);try {//通过代理执行具体的sql逻辑Object result = method.invoke(sqlSession, args);//判断SqlSession是否处于事务中,如果不处于事务中则做一次手动提交,否则交由Spring的事务管理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) {//...} finally {if (sqlSession != null) {closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);}}}}}

SpringManagedTransaction中数据库Connection对象的获取逻辑:

@Override
public Connection getConnection() throws SQLException {if (this.connection == null) {openConnection();}return this.connection;
}/*** Gets a connection from Spring transaction manager and discovers if this* {@code Transaction} should manage connection or let it to Spring.* <p>* It also reads autocommit setting because when using Spring Transaction MyBatis* thinks that autocommit is always false and will always call commit/rollback* so we need to no-op that calls.*/
private void openConnection() throws SQLException {//通过DataSourceUtils对象获取连接this.connection = DataSourceUtils.getConnection(this.dataSource);this.autoCommit = this.connection.getAutoCommit();this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);if (LOGGER.isDebugEnabled()) {LOGGER.debug("JDBC Connection ["+ this.connection+ "] will"+ (this.isConnectionTransactional ? " " : " not ")+ "be managed by Spring");}
}//DataSourceUtils对象中是如何获取连接
public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {try {return doGetConnection(dataSource);}catch (SQLException ex) {throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex);}}public static Connection doGetConnection(DataSource dataSource) throws SQLException {//Spring事务会开启一个Connection并与当前线程绑定ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {conHolder.requested();if (!conHolder.hasConnection()) {logger.debug("Fetching resumed JDBC Connection from DataSource");conHolder.setConnection(dataSource.getConnection());}return conHolder.getConnection();}Connection con = dataSource.getConnection();if (TransactionSynchronizationManager.isSynchronizationActive()) {ConnectionHolder holderToUse = conHolder;if (holderToUse == null) {holderToUse = new ConnectionHolder(con);}else {holderToUse.setConnection(con);}holderToUse.requested();TransactionSynchronizationManager.registerSynchronization(new ConnectionSynchronization(holderToUse, dataSource));holderToUse.setSynchronizedWithTransaction(true);if (holderToUse != conHolder) {TransactionSynchronizationManager.bindResource(dataSource, holderToUse);}}return con;}

总结

Spring事务会开启一个Connection并与当前线程绑定,通过ThreadLocal对象获取同一个线程中绑定的数据库连接,从而保证Mybatis执行的代码都用的是同一个数据库连接。Spring事务是通过TransactionSynchronizationManager对象与Mybatis关联,从而保证被@Transactional声明的方法中的所有Mybatis数据库操作都使用同一个数据库连接,进而保证事务的正确性。

Spring事务如何集成到Mybatis之Mybatis事务相关推荐

  1. Spring+Hibernate+Atomikos集成构建JTA的分布式事务--解决多数据源跨库事务

    一.概念 分布式事务 分布式事务是指事务的参与者.支持事务的服务器.资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上.简言之,同时操作多个数据库保持事务的统一,达到跨库事务的效果. JT ...

  2. 深入浅出MyBatis:MyBatis与Spring集成及实用场景

    为什么80%的码农都做不了架构师?>>>    本系列是「深入浅出MyBatis:技术原理与实践」书籍的总结笔记. 本篇是「深入浅出MyBatis」系列的最后一篇,主要介绍与Spri ...

  3. spring和mybatis整合进行事务管理

    1.声明式实现事务管理 XML命名空间定义,定义用于事务支持的tx命名空间和AOP支持的aop命名空间: <beans xmlns="http://www.springframewor ...

  4. 【Spring从入门到出家】6 -声明式事务(完整项目版-整合Mybatis)

    文章目录 11 声明式事务 11.1 建立测试环境 10.2 Spring配置声明式事务 10.3 事务转播特性 11 声明式事务 11.1 建立测试环境 我们要建立如下的项目结构 数据库spring ...

  5. Insight Mybatis JdbcTemplate 混合事务控制的实现

    混合使用的背景 最近项目中需要引入工作流引擎,实现业务和流程设计.流转的解耦. 工作流流引擎选用的是snaker,轻量.易上手.可定制.访问数据库用的是JdbcTemplate . 项目中原有的持久层 ...

  6. Mybatis 中的事务

    1. Mybaits中的事务接口Transaction public interface Transaction {Connection getConnection() throws SQLExcep ...

  7. Spring-09 整合mybatis声明式事务

    声明式事务 回顾事务 事务在项目开发过程非常重要,涉及到数据的一致性的问题,不容马虎!事务管理是企业级应用程序开发中必备技术,用来确保数据的完整性和一致性. 事务就是把一系列的动作当成一个独立的工作单 ...

  8. Mybatis深入:事务隔离级别和管理

    Mybatis事务管理 我们前面已经讲解了如何让Mybatis与Spring更好地融合在一起,通过将对应的Bean类型注册到容器中,就能更加方便的去使用Mapper,那么现在,我们接着来看Spring ...

  9. 详解 MyBatis 事务管理,彻底颠覆你对事务的理解!

    来源:https://my.oschina.net/zudajun/blog/666764 前言 说到数据库事务,人们脑海里自然不自然的就会浮现出事务的四大特性.四大隔离级别.七大传播特性.四大还好说 ...

  10. Spring源码分析【8】-MyBatis注解方法不能重载

    代码如下: 这是不可以的,会报错: 2016-08-18 11:36:00,267 [main] ERROR [org.mybatis.spring.mapper.MapperFactoryBean] ...

最新文章

  1. 初等数论--整除--判断一个数是否是素数
  2. AndroidLinker与SO加壳技术之下篇
  3. Redis 如何保持和MySQL数据一致【一】
  4. VTK:命名颜色用法实战
  5. Linux加密框架中的算法和算法模式
  6. 读ImageCropper源码
  7. Java一个月学到springboot_Java基础学习路线之SpringBoot入门
  8. 孔板流量计计算公式_带你全面了解各种流量计!
  9. Kicad安装与配置_Windows
  10. Silverlight-Cailburn应用框架
  11. 怎样做小游戏挖金子(VC,源码3)
  12. java中的NIO是什么?
  13. Bugku misc 旋转跳跃wp
  14. Gustafson 定律
  15. allgro显示网络名称_ALLEGRO如何显示网络标号?
  16. 【文本】HTML5 Canvas小项目:为坐标轴添加数字标签(带刻度线)
  17. 2_linux-常用命令-实例
  18. 2020到2021计算机试题,2020广东计算机一级考试试题和答案【2021年整理】-20210715002405.docx-原创力文档...
  19. Log日志(Linux C)
  20. AI|优必选称准备IPO 此前公司机器人曾登上春晚舞台

热门文章

  1. 计算机网络读书笔记DAY4(3)
  2. VB6.0 Select Case语句
  3. 秀米的对话框格子可以变大吗_如何使用秀米进行排版(对外版)课件.ppt
  4. 傻瓜教学——什么是字符串?字符串有哪些概念?
  5. does not have permission to content://包名/external_files/sple/IMG_123123141.jpg
  6. Cesium中的地球坐标系转换:岁差章动计算(XYs)
  7. im即时通讯开发:群聊消息的已读未读功能
  8. 判断一个数是否为质数(素数)
  9. 产品经理必备原型工具Axure RP 8自定义元件库
  10. 生活小窍门——》馒头又白又大