Spring整合mybatis, @MapperScan 原理(spring-mybatis)

@MapperScan("com.lz.springboot.mybatis.springbootmybatis.mapper") 定义mapper接口扫面位置

     @Import(MapperScannerRegistrar.class) mapper扫描注册器 扫描目标包下的mapper接口

            MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware 覆盖 registerBeanDefinitions 方法使用JDK动态代理创建代理对象,并加入spring ioc容器中

                  ClassPathMapperScanner 注册 basePackage 中的 mapper

                          MapperFactoryBean 工厂bean方式返回具体的代理对象

@Override
public T getObject() throws Exception {
  return getSqlSession().getMapper(this.mapperInterface);
}

MapperProxyFactory 利用JDK动态代理创建对象

protected T newInstance(MapperProxy mapperProxy) {
  return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}

 

spring整合mybatis时一级缓存失效问题:

1、需要访问数据

2、spring检查到了这种需求,于是去申请一个mybatis的sqlsession,并将申请到的sqlsession与当前线程绑定,放入threadlocal里面

3、template从threadlocal获取到sqlsession,去执行查询

4、查询结束,清空threadlocal中与当前线程绑定的sqlsession,释放资源

5、又需要访问数据

6、返回到步骤2

sqlsession会不断更新,所以一级缓存失效

 

 

代码大致实现:

 

1、MapperFactoryBean getSqlSession

public class MapperFactoryBean extends SqlSessionDaoSupport implements FactoryBean

@Override

public T getObject() throws Exception {

// SqlSessionDaoSupport getSqlSession()

return getSqlSession().getMapper(this.mapperInterface);

}

 

 

2、返回 SqlSessionTemplate

public abstract class SqlSessionDaoSupport extends DaoSupport

public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {

if (!this.externalSqlSession) {

this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);

}

}

3、执行具体的 selectOne、selectMap、update等使用的是 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());

}

4、动态代理 SqlSessionInterceptor 获取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 {

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) {

.......

5、SqlSessionUtils 注册 使用 TransactionSynchronizationManager.bindResource 绑定 在ThreadLocal

public final class SqlSessionUtils {



getSqlSession() {

...........

registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);

}





TransactionSynchronizationManager.bindResource(sessionFactory, holder);



public abstract class TransactionSynchronizationManager {



private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);



private static final ThreadLocal> resources =

new NamedThreadLocal<>("Transactional resources");



private static final ThreadLocal> synchronizations =

new NamedThreadLocal<>("Transaction synchronizations");



private static final ThreadLocal currentTransactionName =

new NamedThreadLocal<>("Current transaction name");



private static final ThreadLocal currentTransactionReadOnly =

new NamedThreadLocal<>("Current transaction read-only status");



private static final ThreadLocal currentTransactionIsolationLevel =

new NamedThreadLocal<>("Current transaction isolation level");



private static final ThreadLocal actualTransactionActive =

new NamedThreadLocal<>("Actual transaction active");

 

 

 

 

 

 

你可能感兴趣的:(Spring,源码分析,mybatis)