简单分析SqlSessionTemplate、sqlSessionFactory、sqlSessionFactoryBean、SqlSessionManager等区别和作用

最近分析mybatis的mapper时,研究源码时,这些概念理清如下:
在这里插入图片描述

  • sqlSessionFactoryBean,主要作用是通过getObject得到sqlSessionFactory,同时可以设置数据源,mybatis基本配置等。
public class SqlSessionFactoryBean
    implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
  private Configuration configuration;

  private Resource[] mapperLocations;

  private DataSource dataSource;

  private TransactionFactory transactionFactory;

  private Properties configurationProperties;

  private SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

  private SqlSessionFactory sqlSessionFactory;
 //...

  @Override
  public SqlSessionFactory getObject() throws Exception {
    if (this.sqlSessionFactory == null) {
      afterPropertiesSet();
    }

    return this.sqlSessionFactory;
  }
}
  • sqlSessionFactory,用于创建sqlSession的工厂方法。
public interface SqlSessionFactory {

  SqlSession openSession();

  SqlSession openSession(boolean autoCommit);
  //...
  }
  • sqlSession,执行sql命令的会话。
public interface SqlSession extends Closeable {
  <T> T selectOne(String statement, Object parameter);
  <E> List<E> selectList(String statement);
  //...
}

在这里插入图片描述

  • SqlSessionTemplate是sqlSession的实现类,是线程安全的。里面有一个动态代理的SqlSession sqlSessionProxy;代理sqlSessionProxy执行invoke方法的时候,每次invoke方法都是新生成一个SqlSession来执行,这样就保持了线程安全。
    还有一个点,getMapper()方法是得到一个mapper接口的代理对象,且会传入this即本sqlSessionTemplate,最终调用sql语句的时候还是使用代理的sqlSessionProxy(实际还是invoke的新的SqlSession)。【记住,2个动态代理】
public class SqlSessionTemplate implements SqlSession, DisposableBean {

  private final SqlSessionFactory sqlSessionFactory;

  private final SqlSession sqlSessionProxy;

  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;
    this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(),
        new Class[] { SqlSession.class }, new SqlSessionInterceptor());//【注意这个sqlSessionProxy ,和SqlSessionInterceptor的invoke方法】
  }
  //获取代理mapper对象,且一直传入this即本sqlSessionTemplate对象,执行sql语句的时候使用的代理sqlSessionProxy,它又使用invoke方法的新的sqlSession
  @Override
  public <T> T getMapper(Class<T> type) {
    return getConfiguration().getMapper(type, this);
  }

  private class SqlSessionInterceptor implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //【新的sqlSession 】
      SqlSession sqlSession = getSqlSession(SqlSessionTemplate.this.sqlSessionFactory,
          SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
         //...
    }
     //...

}
  • SqlSessionManager是sqlSession的实现类,是线程安全的。里面也有一个动态代理的SqlSession sqlSessionProxy;同时维护一个ThreadLocal localSqlSession,所以代理sqlSessionProxy执行invoke方法的时候,就是拿各自线程的ThreadLocal的SqlSession。
public class SqlSessionManager implements SqlSessionFactory, SqlSession {
  private final SqlSessionFactory sqlSessionFactory;
  private final SqlSession sqlSessionProxy;
  private final ThreadLocal<SqlSession> localSqlSession = new ThreadLocal<>();
  private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
    this.sqlSessionFactory = sqlSessionFactory;
    this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
        SqlSessionFactory.class.getClassLoader(),
        new Class[]{SqlSession.class},
        new SqlSessionInterceptor());
  }
  //也是代理
  @Override
  public <T> T getMapper(Class<T> type) {
    return getConfiguration().getMapper(type, this);
  }
  private class SqlSessionInterceptor implements InvocationHandler {
    public SqlSessionInterceptor() {
        // Prevent Synthetic Access
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();
      //...
      }
   }
}

  • DefaultSqlSession是sqlSession的实现类,普通的一次请求,不安全的。

  • MapperFactoryBean,创建mapper的工厂类,getObject()得到mapper接口的动态代理生成的代理类,它继承SqlSessionDaoSupport来间接操作SqlSessionTemplate。即getObject()->getMapper()

public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
private Class<T> mapperInterface;//这就是实际的mapper接口
  @Override
  public T getObject() throws Exception {
    return getSqlSession().getMapper(this.mapperInterface);
  }
}

public abstract class SqlSessionDaoSupport extends DaoSupport {
  private SqlSessionTemplate sqlSessionTemplate;
 }
  public SqlSession getSqlSession() {
    return this.sqlSessionTemplate;
  }
  • @MapperScan,会扫描目标目录的所有Mapper接口,并名字定义成mapper接口名,但是class类名是MapperFactoryBean,里面的有一个属性是mapper的权限名。如此启动项目,加载单例bean到上下文容器的时候,调用getObject会调用SqlSessionTemplate的getMapper(),得到代理mapper对象。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)//关注MapperScannerRegistrar
@Repeatable(MapperScans.class)
public @interface MapperScan {
}


		scanner.doScan(StringUtils.toStringArray(basePackages));


      // the mapper interface is the original class of the bean
      // but, the actual class of the bean is MapperFactoryBean
      definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue #59
      definition.setBeanClass(this.mapperFactoryBean.getClass());
      
      //注解版
      <bean id="roleMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
		<property name="mapperInterface" value="com.qsm.dao.RoleMapper"/>
		<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
	</bean>
  • @Mapper,若没有使用@MapperScan【@ConditionalOnMissingBean({ MapperFactoryBean.class, MapperScannerConfigurer.class })】,而使用@Mapper,原理也类似,会扫描主启动类目录下的所有标注了@Mapper的mapper接口文件
@org.springframework.context.annotation.Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class })
public class MybatisAutoConfiguration implements InitializingBean {




  @org.springframework.context.annotation.Configuration
  @Import(AutoConfiguredMapperScannerRegistrar.class)
  @ConditionalOnMissingBean({ MapperFactoryBean.class, MapperScannerConfigurer.class })
  public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {

    @Override
    public void afterPropertiesSet() {
      logger.debug(
          "Not found configuration for registering mapper bean using @MapperScan, MapperFactoryBean and MapperScannerConfigurer.");
    }

  }
}

若仔细理解上面的知识点,则下面的题目就应该知道答案了。

1、Mybatis的mapper接口文件原理是什么
2、SqlSessionTemplate是如何保持线程安全的
3、SqlSessionTemplate与SqlSessionManager区别
4、@MapperScan和@Mapper从源码角度是怎么工作的

知道的小伙伴也可以评论一下答案,也许就能帮助其他小伙伴哦

【完,喜欢就点个赞呗】

正在去往BAT的路上修行

  • 16
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
SqlSessionFactoryBean 是 MyBatis 框架中的一个类,它的作用是创建并配置 SqlSessionFactory 对象。SqlSessionFactory 是 MyBatis 的核心接口,它负责管理数据库连接会话和执行 SQL 语句。SqlSessionFactoryBean 是一个工厂 Bean,它通过配置数据源和其他相关属性,创建并配置一个 SqlSessionFactory 对象,然后将其作为一个单例 Bean 注册到 Spring 容器中,供其他组件使用。 SqlSessionFactoryBean 和 SqlSessionFactory区别在于: 1. SqlSessionFactoryBean 是一个 Spring 的 FactoryBean,它实现了 FactoryBean 接口,可以通过配置和编程方式创建 SqlSessionFactory 实例,并将其作为一个 Bean 注册到 Spring 容器中。而 SqlSessionFactory 是 MyBatis 的接口,它是由 SqlSessionFactoryBuilder 根据配置文件或者配置对象创建的。 2. SqlSessionFactoryBean 可以通过 Spring 的依赖注入和属性配置,更加方便地与其他 Spring 组件集成,如数据源、事务管理器等。而 SqlSessionFactory 则是 MyBatis 框架的核心接口,独立于 Spring,用于管理数据库连接和执行 SQL 语句。 3. SqlSessionFactoryBean 可以对 SqlSessionFactory 进行更多的自定义配置,例如设置插件、类型别名、映射器等。而 SqlSessionFactory 可以直接用于创建 SqlSession 对象,执行数据库操作。 总之,SqlSessionFactoryBean 是一个用于创建并配置 SqlSessionFactory 的 Spring FactoryBean,而 SqlSessionFactory 是 MyBatis 的核心接口,用于管理数据库连接和执行 SQL 语句。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值