# Mybatis Sql执行过程

Posted MarlonBrando1998

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了# Mybatis Sql执行过程相关的知识,希望对你有一定的参考价值。

SqlSessionFactory

​ 从SqlSessionFactory说起吧,org.apache.ibatis.session.SqlSessionFactory接口。通过openSession() 可以打开连接操作sql,里面的方法有如下:
在这里插入图片描述

Sql执行的过程

@Component
public class MybatisConfig {

    private static final Logger logger = LoggerFactory.getLogger(MybatisConfig.class);

    @Autowired
    private DataSource dataSource;

    @Bean
    public SqlSessionFactory sqlSessionFactory() {
        SqlSession sqlSession = null;
        try {
            // 采用Mybatis的JDBC事务方式
            TransactionFactory transactionFactory = new JdbcTransactionFactory();
            Environment environment = new Environment("myenverniement", transactionFactory, dataSource);
            // 创建Configuration对象
            Configuration configuration = new Configuration(environment);
            configuration.addMapper(TestMapper.class);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
            sqlSession = sqlSessionFactory.openSession();
            TestMapper testMapper = sqlSession.getMapper(TestMapper.class);
            Map<String, Object> result = testMapper.testOne();
            logger.info("result:{}", result);
            logger.info(LogConstant.LOG_SUCCESS_PREFIX + "SqlSessionFactory配置完成");
            return sqlSessionFactory;
        } catch (Exception e) {
            logger.error(LogConstant.ERROR, e.getMessage());
            return null;
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }
}
定义事务提交方式
// 采用Mybatis的JDBC事务方式
TransactionFactory transactionFactory = new JdbcTransactionFactory();
初始化Mybatis Environment
  • Environment.java源码如下:构造方法参数(事务、数据源)
public final class Environment {
    private final String id;
    // 事务
    private final TransactionFactory transactionFactory;
    // 数据源
    private final DataSource dataSource;
    
    public Environment(String id, TransactionFactory transactionFactory, DataSource dataSource) {
        if (id == null) {
            throw new IllegalArgumentException("Parameter 'id' must not be null");
        } else if (transactionFactory == null) {
            throw new IllegalArgumentException("Parameter 'transactionFactory' must not be null");
        } else {
            this.id = id;
            if (dataSource == null) {
                throw new IllegalArgumentException("Parameter 'dataSource' must not be null");
            } else {
                this.transactionFactory = transactionFactory;
                this.dataSource = dataSource;
            }
        }
    }
}
初始化Configuration

​ MyBatis所有的配置信息都保存在Configuration对象之中,配置文件中的大部分配置都会存储到该类中。构造方法参数是Environment,上面已经说过Environment了。

public Configuration(Environment environment) {
    this();
    this.environment = environment;
}

在这里插入图片描述

  • 可以添加Mapper添加数据接收对象等等。
  • MybatisSpringBoot集成之后,在启动服务的时候,会扫描xml文件、mapper中的接口,将所有的配置信息配置到 Configuration中,之后用dao层操作的时候,拿出相应的sql进行执行。
初始化SqlSessionFactory
// 得到SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
  • build()参数有如下种类,其实都是一样的道理,
得到操作Sql的接口
sqlSession = sqlSessionFactory.openSession();
TestMapper testMapper = sqlSession.getMapper(TestMapper.class);
Map<String, Object> result = testMapper.testOne();
  • openSession()源码:
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;

    DefaultSqlSession var8;
    try {
        Environment environment = this.configuration.getEnvironment();
        // 获取事务提交方式
        TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
        tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
        // 获取执行器
        Executor executor = this.configuration.newExecutor(tx, execType);
        // 返回调用dao 的session对象
        var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
    } catch (Exception var12) {
        this.closeTransaction(tx);
        throw ExceptionFactory.wrapException("Error opening session.  Cause: " + var12, var12);
    } finally {
        ErrorContext.instance().reset();
    }
    return var8;
}
getMapper执行
TestMapper testMapper = sqlSession.getMapper(TestMapper.class);
Map<String, Object> result = testMapper.testOne();
  • 源码:
// 从configuration中获得对应的接口
public <T> T getMapper(Class<T> type) {
    return this.configuration.getMapper(type, this);
}

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return this.mapperRegistry.getMapper(type, sqlSession);
}

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    // mapper 代理
    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(sqlSession);
        } catch (Exception var5) {
            throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
        }
    }
}
  • 根据type类型,从MapperRegistry对象中的knownMappers获取到当前类型对应的代理工厂类,然后通过代理工厂类生成对应Mapper的代理类。
  • 最终获取到我们接口对应的代理类TestMapper对象
    在这里插入图片描述
  • 实现InvocationHandler,使用JDK代理
    在这里插入图片描述
mapperRegistry 中的属性加载时间
  • 在初始化SqlSessionFactory对象的时候,解析xml文件,
    在这里插入图片描述
  • 解析的过程中会解析mapper中用注解标记的方法,解析xml映射文件,还会对Mapper接口中的方法进行解析,并将每个方法的全限定类名作为key存入存入Configuration中的mappedStatements属性。
    在这里插入图片描述

以上是关于# Mybatis Sql执行过程的主要内容,如果未能解决你的问题,请参考以下文章

MyBatis核心源码深度剖析SQL执行过程

MyBatis如何防止SQL注入

MyBatis怎么防止SQL注入

Mybatis之日志工厂

MyBatis:分页的实现

mybatis以及预编译如何防止SQL注入