代码改变世界

3-mybatis-xml配置

2019-08-25 01:23  张紫荣  阅读(255)  评论(0编辑  收藏  举报

 

配置文件主要在官网文档是已有详细说明。

1  properties 在上一节中已经有说明。

2 settings MyBatis中的调整设置。

 

<settings>
  <!--全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存 -->
  <setting name="cacheEnabled" value="true"/>
  <!-- 延迟加载的全局开关,当开启时所有关联对象都会延迟加载。 -->
  <setting name="lazyLoadingEnabled" value="true"/>
  <!-- 是否允许单一语句返回多结果集 -->
  <setting name="multipleResultSetsEnabled" value="true"/>
  <!-- 使用列标签代替列名 -->
  <setting name="useColumnLabel" value="true"/>
  <!-- 允许JDBC自动生成主健 -->
  <setting name="useGeneratedKeys" value="false"/>
  <!-- 指定 MyBatis 应如何自动映射列到字段或属性 -->
  <setting name="autoMappingBehavior" value="PARTIAL"/>
  <!-- 指定发现自动映射目标未知列的行为 -->
  <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
  <!-- 配置默认的执行器 SIMPLE普通执行器;REUSE执行器会重用预处理语句;BATCH重用语句并执行指更新 -->
  <setting name="defaultExecutorType" value="SIMPLE"/>
  <!-- 设置超时时间,它决定cqafcl等待数据库响应的秒数 -->
  <setting name="defaultStatementTimeout" value="25"/>
  <setting name="defaultFetchSize" value="100"/>
  <!-- 允许在嵌套语句中使用分页(RowBounds) -->
  <setting name="safeRowBoundsEnabled" value="false"/>
  <!-- 是否开启自动驼峰命名规则 -->
  <setting name="mapUnderscoreToCamelCase" value="false"/>
  <!-- MyBatis利用本地缓存机制防止循环引用和加速重复嵌套查询 SESSION/STATEMENT -->
  <setting name="localCacheScope" value="SESSION"/>
  <!-- 当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。-->
  <setting name="jdbcTypeForNull" value="OTHER"/>
  <!-- 指定哪个对象的方法触发一次延迟加载。 -->
  <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>

 

3 类型别名(typeAliases)

4 类型处理器(typeHandlers)

   IntegerTypeHandler 将数据库中的NUMERIC或SMALLINT转换为 int

  也可以重写类型处理器或创建自己的类型处理器来处理不支持的或非标准和类型。具体做法为:实现org.apache.ibatis.type.TypeHandler接口,或继承一个白立口口 org.apache.ibatis.type.BaseTypeHandler,然后可以选择性地将它映射到一个JDBC类型,如:

@MappedJdbcTypes(JdbcType.VARCHAR)
public class ExampleTypeHandler extends BaseTypeHandler<String>{
... }

<!-- mybatis-config.xml -->
<typeHandlers>
  <typeHandler handler="org.mybatis.example.ExampleTypeHandler"/>
</typeHandlers>

 5 对象工厂 objectFactory

6 插件 plugins

7 环境配置 environments

<environments default="development">
  <environment id="development">
    <transactionManager type="JDBC">
      <property name="..." value="..."/>
    </transactionManager>
    <dataSource type="POOLED">
      <property name="driver" value="${driver}"/>
      <property name="url" value="${url}"/>
      <property name="username" value="${username}"/>
      <property name="password" value="${password}"/>
    </dataSource>
  </environment>
</environments>

transactionManager

  两种事物管理器:

  • JDBC 直接使用了JDBC的提交和回滚设置。
  • MANAGED 让容器来管理事务的整个生命周期

  如果使用spring+mybatis,则没必要配置事务管理器,因为Spring模块会使用自带的管理器来覆盖前面的配置。

数据源 dataSource:

  • UNPOOLED 每次请求时打开和关闭连接。
  • POOLED 利用“池”的概念将JDBC连接对象组织起来。
  • JNDI  这个数据源的实现是为了能在如EJB或应用服务器这类容器中使用。

8 数据库厂商标识 databaseIdProvider

9 mappers

 

XMLConfigBuilder类读取并解析xml配置文件,内部的属性如下:

//是否已解析  
private boolean parsed;
//解析类 在构造方法中new 出
private final XPathParser parser;
//配置文件中的环境名称
  private String environment;
  private final ReflectorFactory localReflectorFactory = new DefaultReflectorFactory();

//-----以下为extends的 BaseBuilder的属性
rotected final Configuration configuration;
protected final TypeAliasRegistry typeAliasRegistry;
protected final TypeHandlerRegistry typeHandlerRegistry;

最终的提供的构造方法:

  public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
    this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
  }

  private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
    super(new Configuration());
    ErrorContext.instance().resource("SQL Mapper Configuration");
    this.configuration.setVariables(props);
    this.parsed = false;
    this.environment = environment;
    this.parser = parser;
  }

 其中new XPathParser时会初始化xml解析类:

  public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
    commonConstructor(validation, variables, entityResolver);
    this.document = createDocument(new InputSource(inputStream));
  }
  private void commonConstructor(boolean validation, Properties variables, EntityResolver entityResolver) {
    this.validation = validation;
    this.entityResolver = entityResolver;
    this.variables = variables;
    XPathFactory factory = XPathFactory.newInstance();
  //使用xpath的方式解析xml dom this.xpath = factory.newXPath(); }
 //初始化解析xml的Document,org.w3c.dom.Document private Document createDocument(InputSource inputSource) { // important: this must only be called AFTER common constructor try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(validation); factory.setNamespaceAware(false); factory.setIgnoringComments(true); factory.setIgnoringElementContentWhitespace(false); factory.setCoalescing(false); factory.setExpandEntityReferences(true); DocumentBuilder builder = factory.newDocumentBuilder(); builder.setEntityResolver(entityResolver); builder.setErrorHandler(new ErrorHandler() { @Override public void error(SAXParseException exception) throws SAXException { throw exception; } @Override public void fatalError(SAXParseException exception) throws SAXException { throw exception; } @Override public void warning(SAXParseException exception) throws SAXException { } }); return builder.parse(inputSource); } catch (Exception e) { throw new BuilderException("Error creating document instance. Cause: " + e, e); } }

 至此 SqlSessionFactoryBuilder中的构造方法会执行下一方法:

  public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        reader.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

 首先调用 XMLCongBuilder的parser方法:

  public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
   //读取xml配置文件中的configuration node  
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }
//解析 configuration node下内容
  private void parseConfiguration(XNode root) {
    try {
      //issue #117 read properties first  
    //保存到configuration顺为的variables属性(类型:properties)
      propertiesElement(root.evalNode("properties"));
    // 读取settings配置内容 
      Properties settings = settingsAsProperties(root.evalNode("settings"));
     //若有配置vfsImpl时,则更新configuration类中vfsImpl 属性值 Class<? extends VFS>
      loadCustomVfs(settings);
     //读取typeAliases
      typeAliasesElement(root.evalNode("typeAliases"));
     //读取plugins 初始化interceptor,添加到configuration中 configuration.addInterceptor(interceptorInstance)
      pluginElement(root.evalNode("plugins"));    
       //读到objectFactory new Instance 调用 configuration.setObjectFatory(factory)
      objectFactoryElement(root.evalNode("objectFactory"));
    //读取objectWrapperFactory, new Intance 调用configuration.setObjectWrapperFactory(factory)
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
     //读到reflectorFactory , new Instance 调用 configuration.setReflectorFactory(factory)
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
     //设置配置到configuration类中,若无,则使用默认值。
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
     //读取environments,读取default 更新全局配置数据 Environment.Builder(包括TransactionFactory与 Datasource) 
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
//解析mappers文件 mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } }
  private void mapperElement(XNode parent) throws Exception {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        if ("package".equals(child.getName())) {
      //加载jar包中的类,读取配置文件 String mapperPackage = child.getStringAttribute("name"); configuration.addMappers(mapperPackage); } else {
      //读取每一个mapper的配置 String resource = child.getStringAttribute("resource"); String url = child.getStringAttribute("url"); String mapperClass = child.getStringAttribute("class"); if (resource != null && url == null && mapperClass == null) { ErrorContext.instance().resource(resource); InputStream inputStream = Resources.getResourceAsStream(resource);
        //使用XMLMapperBuilder加载xml文件 XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments()); mapperParser.parse(); } else if (resource == null && url != null && mapperClass == null) { ErrorContext.instance().resource(url); InputStream inputStream = Resources.getUrlAsStream(url); XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments()); mapperParser.parse(); } else if (resource == null && url == null && mapperClass != null) {
        //加载java文件 读取xml文件 Class<?> mapperInterface = Resources.classForName(mapperClass); configuration.addMapper(mapperInterface); } else { throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one."); } } } }

 

 

 

系统启动时 SqlSessionFactoryBuilder.build->XMLConfigBuilder.parse->XPathParser,读取的xml配置数据保存在 XMLConfigBuilder(包括BaseBuilder):

  • ,主要为typeAliasRegistry, typeHandlerRegistry,
  • configuration(主要内容保存在Configuration类中),如:Environment(Datasource, TransactionFactory)