@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