Mybatis

核心对象

  1. SqlSessionFactoryBean: 实现InitializingBean接口,在初始化过程中读取配置文件mybatis-config.xml并创建SqlSessionFactory
  2. MapperScannerConfigurer: 实现BeanDefinitionRegistryPostProcessor接口,实现自定义的Bean对象注册 - MapperFactoryBean<*Mapper>对象
  3. SqlSessionTemplate: 持有SqlSessionProxy对象,对SqlSessionProxy对象的操作都会经过SqlSessionInterceptor.invoke()方法,在invoke()内部获取sqlSession进行SQL语句执行
  4. MapperFactoryBean对象: getObject()方法返回Mapper的代理对象,底层实现依赖MapperProxyFactory对象:MapperProxyFactory.newInstance(SqlSessionTemplate);
    mybatis-spring整合

Spring配置文件

<beans>
    <!-- Spring包扫描路径 -->
    <context:component-scan base-package="top.kiqi.spring"/>

    <bean id="jdbc" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations" value="classpath*:db.properties"/>
    </bean>

    <!-- c3p0连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${dataSource.driver}" />
        <property name="jdbcUrl" value="${dataSource.url}" />
        <property name="user" value="${dataSource.username}" />
        <property name="password" value="${dataSource.password}" />
    </bean>

    <!-- 在Spring启动时创建 sqlSessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="configLocation" value="classpath:spring-mybatis-config.xml"></property>
        <property name="mapperLocations" value="classpath:mapping/*iMapper.xml"></property>
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 配置扫描器,将mybatis的接口实现加入到 IOC容器中  -->
    <mybatis-spring:scan base-package="top.kiqi.mybatis.dao" />

    <!--开启事务控制-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
</beans>

SqlSessionFactoryBean

// 注册到IOC容器中,用于获取SqlSessionFactory对象
public class SqlSessionFactoryBean
    implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
  // (init)生命周期切入点
  @Override
  public void afterPropertiesSet() throws Exception {
    notNull(dataSource, "Property 'dataSource' is required");
    notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");

    state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
        "Property 'configuration' and 'configLocation' can not specified with together");

    // MS1 : 通过SqlSessionFactoryBean对象的生命周期切入点,实现配置读取和SqlSessionFactory对象创建
    this.sqlSessionFactory = buildSqlSessionFactory();
  }

  // MS : 实现配置文件解析,并返回sqlSessionFactory对象。
  protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
     Configuration targetConfiguration  = xmlConfigBuilder.getConfiguration();
     xmlConfigBuilder.parse();
     xmlMapperBuilder.parse();
     return this.sqlSessionFactoryBuilder.build(targetConfiguration);
  }

  // IOC容器调用FactoryBean<T>对象的getObject()方法获取真实bean
  public SqlSessionFactory getObject() throws Exception {
    if (this.sqlSessionFactory == null) {
      afterPropertiesSet();
    }

    return this.sqlSessionFactory;
  }

MapperScannerConfigurer

// 用于扫描mybatis mapper接口,并注册到IOC容器中,其BeanDefinition中的class为MapperFactoryBeanClass,通过getObject()获取Mapper代理对象
public class MapperScannerConfigurer
    implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
 
  // 通过该后置处理器,可以实现对未实例化的BeanDefinition进行修改
  @Override
  public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    if (this.processPropertyPlaceHolders) {
      processPropertyPlaceHolders();
    }

    // 配置扫描参数
    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
    scanner.setAddToConfig(this.addToConfig);
    scanner.setAnnotationClass(this.annotationClass);
    scanner.setMarkerInterface(this.markerInterface);
    scanner.setSqlSessionFactory(this.sqlSessionFactory);
    scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
    scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
    scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
    scanner.setResourceLoader(this.applicationContext);
    scanner.setBeanNameGenerator(this.nameGenerator);
    scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
    if (StringUtils.hasText(lazyInitialization)) {
      scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
    }
    scanner.registerFilters();

    // MS : 快进到 ClassPathMapperScanner.scan方法,读取到beanDefinitions定义后将class替换为MapperFactoryBean<T>对象
    //      最后注册到容器中的为MapperFactoryBean<T>对象,通过getObject方法获得mapper
    scanner.scan(
        StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
  }
}

public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
  @Override
  public Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);

    if (beanDefinitions.isEmpty()) {
      LOGGER.warn(() -> "No MyBatis mapper was found in '" + Arrays.toString(basePackages)
          + "' package. Please check your configuration.");
    } else {
      // 修改BeanDefinition的定义,将class对象替换为mapperFactoryBeanClass。
      processBeanDefinitions(beanDefinitions);
    }

    return beanDefinitions;
  }

// MapperScannerConfigurer#postProcessBeanDefinitionRegistry()
//   definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
//   definition.setBeanClass(this.mapperFactoryBeanClass);
}

getMapper()

// IOC容器调用 MapperFactoryBean.getObject() 获取beanname为*Mapper的对象
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
  // 实际调用sqlSessionTemplate.sqlSessionFactory.configuration.mapperRegistry.getMapper(type, sqlSession);
  @Override
  public T getObject() throws Exception {
    return getSqlSession().getMapper(this.mapperInterface);
  }

  public SqlSession getSqlSession() {
    return this.sqlSessionTemplate;
  }
}

// MapperRegistry 中存放了`Type-MapperProxyFactory`的映射,由MapperProxyFactory创建代理对象和invocationHandler对象(MapperProxy)
// 由于传入参数为sqlSessionTemplate,因此由sqlSessionTemplate实现线程安全控制
public class MapperRegistry {
    private final Configuration config;
    private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap();

    public MapperRegistry(Configuration config) {
        this.config = config;
    }

    public <T> T getMapper(Class<T> type, SqlSession sqlSessionTemplate) {
        MapperProxyFactory<T> 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(sqlSessionTemplate);
            } catch (Exception var5) {
                throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
            }
        }
    }

SqlSessionTemplate

-> mapper代理对象方法 -> SqlSessionTemplate方法 -> sqlSessionProxy方法 -> SqlSessionInterceptor.invoke()
-> SqlSessionUtils.getSqlSession() -> TransactionSynchronizationManager事务资源管理

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;

    // SqlSessionTemplate持有一个SqlSessionProxy对象,对sqlSessionProxy的操作都会经过SqlSessionInterceptor.invoke()方法
    this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(),
        new Class[] { SqlSession.class }, new SqlSessionInterceptor());
}

// SqlSessionProxy - InvocationHandler对象
  private class SqlSessionInterceptor implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      // MS : 此处获取SqlSession(--- 具体逻辑与Spring的TransactionSynchronizationManager有关,通过ThreadLocal获取当前线程已有sqlSession)
      SqlSession sqlSession = getSqlSession(SqlSessionTemplate.this.sqlSessionFactory,
          SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
      try {
        Object result = method.invoke(sqlSession, args);
        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) {
          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
        }
      }
    }
  }
}

由Spring TransactionSynchronizationManager对象 - 实现SqlSession线程相关

  1. 从TransactionSynchronizationManager中获取SqlSessionHolder对象(底层为ThreadLocal数据结构,线程相关)
  • 如果存在,则返回SqlSessionHolder对象持有的SqlSession
  • 如果不存在,则session = sessionFactory.openSession(executorType),包装成SqlSessionHolder并注册
SqlSessionUtils#registerSessionHolder()
        // 将session包装成SqlSessionHolder对象
        holder = new SqlSessionHolder(session, executorType, exceptionTranslator);

        // 将SqlSessionHolder对象注册到TransactionSynchronizationManager的ThreadLocal中
        TransactionSynchronizationManager.bindResource(sessionFactory, holder);

        // 将SqlSessionSynchronization对象注册到TransactionSynchronizationManager的ThreadLocal中,该对象可以实现Spring事务管理前后置代码切入
        TransactionSynchronizationManager
            .registerSynchronization(new SqlSessionSynchronization(holder, sessionFactory));
        holder.setSynchronizedWithTransaction(true);
  1. TransactionSynchronizationAdapter对象 - Spring提供的事务管理前后置代码切入点
  private static final class SqlSessionSynchronization extends TransactionSynchronizationAdapter{}
public abstract class TransactionSynchronizationAdapter implements TransactionSynchronization, Ordered {
    public TransactionSynchronizationAdapter() {}

    public int getOrder() {
        return 2147483647;}

    public void suspend() {}

    public void resume() {}

    public void flush() {}

    public void beforeCommit(boolean readOnly) {}

    public void beforeCompletion() {}

    public void afterCommit() {}

    public void afterCompletion(int status) {}
}

Spring实现MyBatis事务管理

  1. SqlSessionFactoryBean在解析配置文件时,会将SpringManagedTransactionFactory配置为Mybatis的事务管理工厂
  2. sqlSessionFactory.openSession()获取链接时,会与SpringManagedTransactionFactory中创建的SpringManagedTransaction绑定
  3. Connection conn = springManagedTransaction.getConnection()
  4. 实际上,Spring通过 DataSourceUtils.getConnection(this.dataSource);获得链接,如此,链接由Spring进行控制
    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 = fetchConnection(dataSource);
            if (TransactionSynchronizationManager.isSynchronizationActive()) {
                try {
                    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);
                    }
                } catch (RuntimeException var4) {
                    releaseConnection(con, dataSource);
                    throw var4;
                }
            }

            return con;
        } else {
            conHolder.requested();
            if (!conHolder.hasConnection()) {
                logger.debug("Fetching resumed JDBC Connection from DataSource");
                conHolder.setConnection(fetchConnection(dataSource));
            }

            return conHolder.getConnection();
        }
    }

欢迎疑问、期待评论、感谢指点 -- kiqi,愿同您为友

-- 星河有灿灿,愿与之辉

原文地址:https://www.cnblogs.com/kiqi/p/14368108.html