Mybatis配置文件XML全貌详解,再不懂我也没招了

Posted Javachichi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis配置文件XML全貌详解,再不懂我也没招了相关的知识,希望对你有一定的参考价值。

一、为什么要使用配置文件

试想,如果没有配置文件,我们的应用程序将只能沿着固定的姿态运行,几乎不能做任何动态的调整,那么这不是一套完美的设计,因为我们希望拥有更宽更灵活的操作空间和更多的兼容度,同时也能解决硬编码等问题,所以我们需要有配置文件,对应用程序进行参数预设和设置初始化工作。

那我们为何钟情XML?

首先,当然是 XML 配置文件本身就足够优秀,格式规范,存储小,跨平台,读取快…等等,所谓窈窕淑女,谁人不爱。

其次,也是一个重要影响因素,就是各大领域大佬的支持,像微软、像Java系…等等,世上本无路,只是走的人多了,也就成了路 (
这句话是鲁迅老先生说的)。

所以,Mybatis选择搭配XML配置,实属合理。

二、Mybatis 配置全貌

Mybatis框架本身,理论上就一个配置文件,其实也只需要一个配置文件,即mybatis-config.xml (当然文件名允许自由命名),只不过这个配置文件其中的一个属性mappers(映射器),由于可能产生过多的SQL映射文件,于是我们物理上单独拓展出来,允许使用者定义任意数量的 xxxMapper.xml 映射文件。

把SQL映射文件单独配置,是有好处的,一是灵活度上允许任意拓展,二也避免了其它无需经常变动的属性配置遭遇误改。

我们看看Mybatis官网给出的配置文件层次结构:

  • configuration(配置) properties(属性) settings(设置) typeAliases(类型别名) 三种别名定义方式 typeHandlers(类型处理器) 自定义类型处理器 objectFactory(对象工厂) plugins(插件) environments(环境配置) environment(环境变量) transactionManager(事务管理器) dataSource(数据源) 三种支持数据源与自定义数据源 databaseIdProvider(数据库厂商标识) mappers(映射器)

实际配置文件XML内容如下,除了约束头 <?xml> 与 ,

其余标签元素都是 Mybatis 的核心配置属性 :

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <!-- 1、属性:例如jdbc.properties -->
    <properties resource="jdbc.properties"></properties>

    <!-- 2、设置:定义全局性设置,例如开启二级缓存 -->
    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>

    <!-- 3、类型名称:为一些类定义别名 -->
    <typeAliases>
        <typeAlias type="com.panshenlian.pojo.User" alias="user"></typeAlias>
    </typeAliases>

    <!-- 4、类型处理器:定义Java类型与数据库中的数据类型之间的转换关系 -->
    <typeHandlers></typeHandlers>

    <!-- 5、对象工厂 -->
    <objectFactory type=""></objectFactory>

    <!-- 6、插件:mybatis的插件,支持自定义插件 -->
    <plugins>
        <plugin interceptor=""></plugin>
    </plugins>

    <!-- 7、环境:配置mybatis的环境 -->
    <environments default="development">
        <!-- 环境变量:支持多套环境变量,例如开发环境、生产环境 -->
        <environment id="development">
            <!-- 事务管理器:默认JDBC -->
            <transactionManager type="JDBC" />
            <!-- 数据源:使用连接池,并加载mysql驱动连接数据库 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
                <property name="username" value="root" />
                <property name="password" value="123456" />
            </dataSource>
        </environment>
    </environments>

    <!-- 8、数据库厂商标识 -->
    <databaseIdProvider type=""></databaseIdProvider>

    <!-- 9、映射器:指定映射文件或者映射类 -->
    <mappers>
        <mapper resource="UserMapper.xml" />
    </mappers>
    
</configuration>

必须注意:Mybatis配置文件的属性位置顺序是 固定 的,不允许 颠倒顺序,否则 Mybatis 在解析 XML
文件的时候就会抛出异常,这个与 Mybatis 框架启动加载配置信息顺序有关,后续我们源码分析会讲到。

以上基本能够清晰看明白 Mybatis 配置文件的层次结构关系,我们简单画一张脑图:
​​​​​​在这里插入图片描述

基本是需要我们掌握 9 大顶级元素配置,其中标记 橘红色 的属性配置,由于涉及 插件 和 动态SQL ,插件配置可以应用于分页与功能增强等,动态SQL例如 if 标签、where 标签、foreach标签等,初步理解为应用于SQL语句拼接。这两块属于 Mybatis 的两个特性,我们后续单独详细进行梳理讨论。

三、XML 核心配置

我们的核心配置文件 configuration(配置)作为最顶级节点,其余 9 大属性都必须嵌套在其内,对于内部 9 大节点,我们逐一讲解:

1、properties(属性)

属性标签,显而易见就是提供属性配置,可进行动态替换,一般可以在 Java 属性文件中配置,例如 jdbc.properties 配置文件 ,或通过 properties 元素标签中的子元素 property 来指定配置。

举例我们需要配置数据源信息,采用 property 标签可以这样配置:

<properties>
  <property name="driver" value="com.mysql.jdbc.Driver"/>
  <property name="url" value="jdbc:mysql://127.0.0.1:3306/myDB"/>
  <property name="username" value="user1"/>
  <property name="password" value="123456"/>
</properties>

设置好的属性可以在整个配置文件中用来替换需要动态配置的属性值。比如:

<dataSource type="POOLED">
  <property name="driver" value="${driver}"/>
  <property name="url" value="${url}"/>
  <property name="username" value="${username}"/>
  <property name="password" value="${password}"/>
</dataSource>

或者我们使用 Java 中的属性配置文件,把属性配置元素具体化到一个属性文件中,并且使用属性文件的 key 名作为占位符。例如 jdbc.properties

driver=com.mysql.jdbc.Driver
url=jdbc\\:mysql\\://127.0.0.1\\:3306/myDB
username=root
password=123456

使用时我们把属性文件引入,并使用文件中定义的占位符,例如 db.driver :

<!-- 引入属性配置文件 -->
<properties resource="jdbc.properties"></properties>
    
<dataSource type="POOLED">
  <property name="driver" value="${driver}"/>
  <property name="url" value="${url}"/>
  <property name="username" value="${username}"/>
  <property name="password" value="${password}"/>
</dataSource>

在这里插入图片描述

但是问题来了,当我们既使用 *.properties 配置文件,同时又设置了 property 元素值,Mybatis 会使用哪边配置的属性值呢? 例如这种情况 :

<properties resource="jdbc.properties"> 
  <property name="driver" value="com.mysql.jdbc.Driver"/>
  <property name="url" value="jdbc:mysql://127.0.0.1:3306/myDB"/>
  <property name="username" value="user1"/>
  <property name="password" value="123456"/>
</properties>

这里,如果在 property 标签元素与 jdbc.properties 文件中同时存在相同属性,那么属性文件将会覆盖 property 标签元素的属性,例如最终 username属性值会使用 jdbc.properties 文件中设置的 root,而不会使用属性元素设置的 user1 。这样实际为配置提供了诸多灵活选择。

另外,properties 元素允许配置 resource 属性或 url 属性,只能二选一,要么使用 resource 指定本地的配置文件,要么使用 url 指定远程的配置文件,因为 Mybatis 在加载配置时,如果发现 url 与 resource 同时存在,会抛出异常禁止。

<!-- 配置resource-->
<properties resource="xxx.properties">
    <property name="driver" value="com.mysql.jdbc.Driver"/>
</properties>

<!-- 配置url-->
<properties url="http://xxxx">
    <property name="driver" value="com.mysql.jdbc.Driver"/>
</properties>

还有一种情况,像 Mybatis 在解析配置的时候,也可以在 Java 代码中构建属性 java.util.Properties 属性对象并传递到 SqlSessionFactoryBuilder.build() 方法中,例如:

// 构建属性对象
Properties props = new Properties();
props.setProperty("driver","com.mysql.jdbc.Driver"); 
props.setProperty("url","jdbc:mysql://127.0.0.1:3306/myDB"); 
props.setProperty("username","user1"); 
props.setProperty("password","123456");  

// 传递属性构建 SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, props);
复制代码

那么这三种方式都允许配置,那在属性配置重复的情况下,优先级别是怎样呢?

properties 优先级

1、第一优先级:在 Java 代码中构建的 properties 属性对象;

2、第二优先级:通过属性 resource 或 url 读取到的本地文件或远程文件;

3、第三优先级:直接在 properties 内部子标签元素 property 中设置的属性。

注意,在实际开发中,为了避免给后期维护造成困扰,建议使用单一种配置方式。

2、settings(设置)

settings 标签元素,是 MyBatis 中极为重要的调整设置,它们会动态改变 MyBatis 的运行时行为,这些配置就像 Mybatis 内置的许多功能,当你需要使用时可以根据需要灵活调整,并且 settings 能配置的东西特别多,我们先来一起看看,一个完整的属性配置示例:

<settings>
  <setting name="cacheEnabled" value="true"/>
  <setting name="lazyLoadingEnabled" value="true"/>
  <setting name="multipleResultSetsEnabled" value="true"/>
  <setting name="useColumnLabel" value="true"/>
  <setting name="useGeneratedKeys" value="false"/>
  <setting name="autoMappingBehavior" value="PARTIAL"/>
  <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
  <setting name="defaultExecutorType" value="SIMPLE"/>
  <setting name="defaultStatementTimeout" value="25"/>
  <setting name="defaultFetchSize" value="100"/>
  <setting name="safeRowBoundsEnabled" value="false"/>
  <setting name="mapUnderscoreToCamelCase" value="false"/>
  <setting name="localCacheScope" value="SESSION"/>
  <setting name="jdbcTypeForNull" value="OTHER"/>
  <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
  <... more .../>
</settings>
  • 属性cacheEnabled 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存 支持 true | false 默认 true
  • 属性lazyLoadingEnabled 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 支持 true | false 默认 false
  • 属性 aggressiveLazyLoading 开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 否则,每个延迟加载属性会按需加载(参考 lazyLoadTriggerMethods)。 支持 true | false 默认 false (在 3.4.1 及之前的版本中默认为 true)
  • 属性 multipleResultSetsEnabled 是否允许单个语句返回多结果集(需要数据库驱动支持)。 支持 true | false 默认 true
  • 属性 useColumnLabel 使用列标签代替列名。实际表现依赖于数据库驱动,具体可参考数据库驱动的相关文档,或通过对比测试来观察。 支持 true | false 默认 true
  • 属性 useGeneratedKeys 允许 JDBC 支持自动生成主键,需要数据库驱动支持。如果设置为 true,将强制使用自动生成主键。尽管一些数据库驱动不支持此特性,但仍可正常工作(如 Derby)。 支持 true | false 默认 false
  • 属性 autoMappingBehavior 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示关闭自动映射;PARTIAL 只会自动映射没有定义嵌套结果映射的字段。 FULL 会自动映射任何复杂的结果集(无论是否嵌套)。 支持 NONE, PARTIAL, FULL 默认 PARTIAL
  • 属性 autoMappingUnknownColumnBehavior 指定发现自动映射目标未知列(或未知属性类型)的行为。 NONE: 不做任何反应 WARNING: 输出警告日志( org.apache.ibatis.session.AutoMappingUnknownColumnBehavior 的日志等级必须设置为 WARN) FAILING: 映射失败 (抛出 SqlSessionException) 支持 NONE, WARNING, FAILING 默认 NONE
  • 属性 defaultExecutorType 配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(PreparedStatement); BATCH 执行器不仅重用语句还会执行批量更新。 支持 SIMPLE REUSE BATCH 默认 SIMPLE
  • 属性 defaultStatementTimeout 设置超时时间,它决定数据库驱动等待数据库响应的秒数。 支持 任意正整数 默认 未设置 (null)
  • 属性 defaultFetchSize 动的结果集获取数量(fetchSize)设置一个建议值。此参数只可以在查询设置中被覆盖。 支持 任意正整数 默认 未设置 (null)
  • 属性 defaultResultSetType 指定语句默认的滚动策略。(新增于 3.5.2) 支持 FORWARD_ONLY | SCROLL_SENSITIVE | SCROLL_INSENSITIVE | DEFAULT(等同于未设置) 默认 未设置 (null)
  • 属性 safeRowBoundsEnabled 是否允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为 false。 支持 true | false 默认 false
  • 属性 safeResultHandlerEnabled 是否允许在嵌套语句中使用结果处理器(ResultHandler)。如果允许使用则设置为 false。 支持 true | false 默认 true
  • 属性 mapUnderscoreToCamelCase 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 支持 true | false 默认 false
  • 属性 localCacheScope MyBatis 利用本地缓存机制(Local Cache)防止循环引用和加速重复的嵌套查询。 默认值为 SESSION,会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地缓存将仅用于执行语句,对相同 SqlSession 的不同查询将不会进行缓存。 支持 SESSION | STATEMENT 默认 SESSION
  • 属性 jdbcTypeForNull 当没有为参数指定特定的 JDBC 类型时,空值的默认 JDBC 类型。 某些数据库驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。 JdbcType 常量,常用值:NULL、VARCHAR 或 OTHER。 默认 OTHER

如果你觉得自己学习效率低,缺乏正确的指导,可以加入资源丰富,学习氛围浓厚的技术圈一起学习交流吧!
[Java架构群]
群内有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的JAVA交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。

  • 属性 lazyLoadTriggerMethods 指定对象的哪些方法触发一次延迟加载。 支持 用逗号分隔的方法列表。 默认 equals,clone,hashCode,toString
  • 属性 defaultScriptingLanguage 指定动态 SQL 生成使用的默认脚本语言。 支持 一个类型别名或全限定类名。 默认 org.apache.ibatis.scripting.xmltags.XMLLanguageDriver
  • 属性 defaultEnumTypeHandler 指定 Enum 使用的默认 TypeHandler 。(新增于 3.4.5) 支持 一个类型别名或全限定类名。 默认 org.apache.ibatis.type.EnumTypeHandler
  • 属性 callSettersOnNulls 指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这在依赖于 Map.keySet() 或 null 值进行初始化时比较有用。注意基本类型(int、boolean 等)是不能设置成 null 的。 支持 true | false 默认 false
  • 属性 returnInstanceForEmptyRow 当返回行的所有列都是空时,MyBatis默认返回 null。 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集(如集合或关联)。(新增于 3.4.2) 支持 true | false 默认 false
  • 属性 logPrefix 指定 MyBatis 增加到日志名称的前缀。 支持 任何字符串 默认 未设置
  • 属性 logImpl 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 支持 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING 默认 未设置
  • 属性 proxyFactory 指定 Mybatis 创建可延迟加载对象所用到的代理工具。 支持 CGLIB | JAVASSIST 默认 JAVASSIST (MyBatis 3.3 以上)
  • 属性 vfsImpl 指定 VFS 的实现 支持 自定义 VFS 的实现的类全限定名,以逗号分隔。 默认 未设置
  • 属性 useActualParamName 允许使用方法签名中的名称作为语句参数名称。 为了使用该特性,你的项目必须采用 Java 8 编译,并且加上 -parameters 选项。(新增于 3.4.1) 支持 true | false 默认 true
  • 属性 configurationFactory 指定一个提供 Configuration 实例的类。 这个被返回的 Configuration 实例用来加载被反序列化对象的延迟加载属性值。 这个类必须包含一个签名为static Configuration getConfiguration() 的方法。(新增于 3.2.3) 支持 一个类型别名或完全限定类名。 默认 未设置
  • 属性 shrinkWhitespacesInSql 从SQL中删除多余的空格字符。请注意,这也会影响SQL中的文字字符串。 (新增于 3.5.5) 支持 true | false 默认 false
  • 属性 defaultSqlProviderType 指定一个本身拥查询方法的类( 从 3.5.6 开始 ),这个类可以配置在注解 @SelectProvider 的 type 属性值上。 支持 一个类型别名或完全限定类名。 默认 未设置

settings 支持了特别多功能支持,其实常规开发中使用到的属性项不会特别多,除非项目有特殊要求,所以建议大家把这些设置当做字典即可,不必详记
每一个属性使用,需要时翻阅研读。

3、typeAliases(类型别名)

类型别名可以给 Java 类型设置一个简称。 它仅用于 XML 配置,意在降低冗余的全限定类名书写,因为书写类的全限定名太长了,我们希望有一个简称来指代它。类型别名在 Mybatis 中分为 系统内置 和 用户自定义 两类,Mybatis 会在解析配置文件时把 typeAliases 实例存储进入 Configuration 对象中,需要使用时直接获取。

一般我们可以自定义别名,例如:

<typeAliases>
  <typeAlias alias="Author" type="domain.blog.Author"/>
  <typeAlias alias="Blog" type="domain.blog.Blog"/> 
</typeAliases>

像这样配置时,我们就可以在任何需要使用 domain.blog.Author 的地方,直接使用别名 author 。

但是,如果遇到项目中特别多 Java 类需要配置别名,怎么更快的设置呢?

可以指定一个包名进行扫描,MyBatis 会在包名下面扫描需要的 Java Bean,比如:

<typeAliases>
  <package name="domain.blog"/>
</typeAliases>

每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author;若有 注解 ,则别名为其自定义的注解值。见下面的例子:

@Alias("myAuthor")
public class Author {
    ...
}

Mybatis 已经为许多常见的 Java 类型内建了相应的类型别名。下面就是一些为常见的 Java 类型内建的类型别名。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格,可以发现 基本类型 的别名前缀都有下划线 ‘_’,而基本类型的 包装类 则没有,这个需要注意:

  • 别名 _byte,对应的类型是:byte
  • 别名 _long,对应的类型是:long
  • 别名 _short,对应的类型是:short
  • _int,对应的类型是:int
  • 别名 _integer,对应的类型是:int
  • 别名 _double,对应的类型是:double
  • 别名 _float,对应的类型是:float
  • 别名 _boolean,对应的类型是:boolean
  • 别名 string,对应的类型是:String
  • 别名 byte,对应的类型是:Byte
  • long,对应的类型是:Long
  • 别名 short,对应的类型是:Short
  • 别名 int,对应的类型是:Integer
  • 别名 integer,对应的类型是:Integer
  • 别名 double,对应的类型是:Double
  • 别名 float,对应的类型是:Float
  • 别名 boolean,对应的类型是:Boolean
  • 别名 date,对应的类型是:Date
  • 别名 decimal,对应的类型是:BigDecimal
  • 别名 bigdecimal,对应的类型是:BigDecimal
  • 别名 object,对应的类型是:Object
  • 别名 map,对应的类型是:Map
  • 别名 hashmap,对应的类型是:HashMap
  • 别名 list,对应的类型是:List
  • 别名 arraylist,对应的类型是:ArrayList
  • 别名 collection,对应的类型是:Collection
  • 别名 iterator,对应的类型是:Iterator

我们可以通过源码查看内置的类型别名的注册信息。

具体源码路径在 org.apache.ibatis.type.TypeAliasRegistry # TypeAliasRegistry() :

public TypeAliasRegistry() {
    registerAlias("string", String.class);

    registerAlias("byte", Byte.class);
    registerAlias("long", Long.class);
    registerAlias("short", Short.class);
    registerAlias("int", Integer.class);
    registerAlias("integer", Integer.class);
    registerAlias("double", Double.class);
    registerAlias("float", Float.class);
    registerAlias("boolean", Boolean.class);

    registerAlias("byte[]", Byte[].class);
    registerAlias("long[]", Long[].class);
    registerAlias("short[]", Short[].class);
    registerAlias("int[]", Integer[].class);
    registerAlias("integer[]", Integer[].class);
    registerAlias("double[]", Double[].class);
    registerAlias("float[]", Float[].class);
    registerAlias("boolean[]", Boolean[].class);

    registerAlias("_byte", byte.class);
    registerAlias("_long", long.class);
    registerAlias("_short", short.class);
    registerAlias("_int", int.class);
    registerAlias("_integer", int.class);
    registerAlias("_double", double.class);
    registerAlias("_float", float.class);
    registerAlias("_boolean", boolean.class);

    registerAlias("_byte[]", byte[].class);
    registerAlias("_long[]", long[].class);
    registerAlias("_short[]", short[].class);
    registerAlias("_int[]", int[].class);
    registerAlias("_integer[]", int[].class);
    registerAlias("_double[]", double[].class);
    registerAlias("_float[]", float[].class);
    registerAlias("_boolean[]", boolean[].class);

    registerAlias("date", Date.class);
    registerAlias("decimal", BigDecimal.class);
    registerAlias("bigdecimal", BigDecimal.class);
    registerAlias("biginteger", BigInteger.class);
    registerAlias("object", Object.class);

    registerAlias("date[]", Date[].class);
    registerAlias("decimal[]", BigDecimal[].class);
    registerAlias("bigdecimal[]", BigDecimal[].class);
    registerAlias("biginteger[]", BigInteger[]以上是关于Mybatis配置文件XML全貌详解,再不懂我也没招了的主要内容,如果未能解决你的问题,请参考以下文章

MyBatis之Mapper XML 文件详解-缓存配置

Mybatis-config.xml配置文件详解

笔记:MyBatis XML配置详解

[转] MyBatis的XxxMapper.xml 映射器的详解

mybatis-config.xml文件详解

mybatis系列-05-SqlMapConfig.xml详解