Mybatis笔记

思考 https://www.zhihu.com/question/270387939/answer/360487647
https://blog.csdn.net/isea533/category_2092001.html

Mybatis 客户端调用过程

// 加载配置
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
// 构建核心工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, "development");
// 创建会话
SqlSession session = sqlSessionFactory.openSession();
// 动态代理,生成Dao层接口对象
IUser userMapper = session.getMapper(IUser.class);

SqlSessionFactoryBuilder

顾名思义,这是SqlSessionFactory的建造者类;内部通过XmlConfigBuilder去解析mybatis的config配置xml文件得到Configuration对象。

// 构造器
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
    super(new Configuration()); // 创建Configuration对象
    ErrorContext.instance().resource("SQL Mapper Configuration");
    this.configuration.setVariables(props);
    this.parsed = false;
    this.environment = environment;
    this.parser = parser;
}

XMLConfigBuilder中解析config.xml文件方法的具体内容:

private void parseConfiguration(XNode root) {
    try {
      //issue #117 read properties first
      propertiesElement(root.evalNode("properties"));
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(settings);
      loadCustomLogImpl(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

详细的Configuration配置及属性含义可以参考官网 https://mybatis.org/mybatis-3/zh/configuration.html

XmlConfigBuilder内部又会通过XMLMapperBuilder类去解析mapper.xml文件,并补将结果存入Configuration对象中(此处省略)。

  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      final Executor executor = configuration.newExecutor(tx, execType);
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      closeTransaction(tx); // may have fetched a connection so lets call close()
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

上面是SqlSessionFactory创建sqlSesion的过程,因此一旦Configuration对象确定了,SqlSession也就可以生产出来了,根据传参execType选择使用的哪个执行器Executor。

Executor

执行器 定义了如query,update,commit,rollback等数据库操作的基本方法。
Executor是DefaultSqlSession的成员变量,在openSession时创建,可以指定使用哪个Executor的实现类,未指定默认使用ExecutorType.SIMPLE;也可以通过配置settings.defaultExecutorType属性来指定默认执行器

CachingExecutor:二级缓存执行器(settings.cacheEnabled未配置情况下,默认开启);使用装饰器模式,内部引用了BaseExecutor。
BaseExecutor:是SimpleExecutor,ReuseExecutor,BatchExecutor三个执行器的抽象父类。

Plugins

MyBatis 允许你在映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:
Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
ParameterHandler (getParameterObject, setParameters)
ResultSetHandler (handleResultSets, handleOutputParameters)
StatementHandler (prepare, parameterize, batch, update, query)

通过 MyBatis 提供的强大机制,使用插件是非常简单的,只需实现 Interceptor 接口,并指定想要拦截的方法签名即可。

@Intercepts({@Signature(
  type= Executor.class,
  method = "update",
  args = {MappedStatement.class,Object.class})})
public class ExamplePlugin implements Interceptor {
  private Properties properties = new Properties();
  public Object intercept(Invocation invocation) throws Throwable {
    // implement pre processing if need
    Object returnObject = invocation.proceed();
    // implement post processing if need
    return returnObject;
  }
  public void setProperties(Properties properties) {
    this.properties = properties;
  }
}
<!-- mybatis-config.xml -->
<plugins>
  <plugin interceptor="org.mybatis.example.ExamplePlugin">
    <property name="someProperty" value="100"/>
  </plugin>
</plugins>

上面的插件将会拦截在 Executor 实例中所有的 “update” 方法调用, 这里的 Executor 是负责执行底层映射语句的内部对象。

posted @ 2021-07-14 20:47  不文不问  阅读(29)  评论(0编辑  收藏  举报