Mybatis 的核心配置文件包含了控制 Mybatis 行为的属性信息。

顶层结构

配置文档的顶层结构如下:

  • configuration:配置根元素
    • properties:属性
    • settings:设置
    • typeAliases:类型别名
    • typeHandlers:类型处理器
    • objectFactory:对象工厂
    • plugins:插件
    • environments:环境配置
      • environment:环境变量
        • transactionManager:事务管理器
        • dataSource:数据源
    • databaseldProvider:数据库厂商标识
    • mappers: 引入映射配置文件

接下来我们详细介绍这些配置项。

属性 (properties)

properties 元素用于自定义属性变量,作用等同于 Java 的 .properties 配置文件。实际开发中,我们往往将数据源的配置信息单独抽取成一个 properties 文件,再通过 properties 元素加载。例如创建以下属性配置文件:

  jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://${host}/${url}:${port}/mybatis_db
jdbc.username=root
jdbc.password=123456
  

再通过 properties 元素引入即可:

  <!--引入 properties 配置文件-->
<properties resource="jdbc.properties">
    <property name="username" value="root"/>
    <property name="password" value="123456"/>
</properties>
  

如果一个属性在多个地方进行了配置,那么 MyBatis 将按照下面的顺序来加载:

  • 首先读取在 properties 元素体内 property 元素指定的属性。
  • 然后根据 properties 元素中的 resource 属性读取 classpath 下的属性文件,或根据 url 属性指定的路径读取属性文件,并覆盖之前读取过的同名属性。
  • 最后读取作为方法参数传递的属性,并覆盖之前读取过的同名属性。

因此,通过方法参数传递的属性具有最高优先级,resource/url 属性中指定的配置文件次之,最低优先级的则 properties 元素中指定的属性。

设置 (settings)

settings 元素是 MyBatis 中极为重要的配置调整项,它们会改变 MyBatis 的运行时行为。下表描述了设置中各项设置的含义、默认值等。一个配置完整的 settings 元素的示例如下:

  <settings>
    <!--全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。
        默认值:true-->
    <setting name="cacheEnabled" value="true"/>
    <!--延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。
          特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。
        默认值:false-->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!--开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 
          否则,每个延迟加载属性会按需加载(参考 lazyLoadTriggerMethods)。
        默认值:false(在 3.4.1 及之前的版本中默认为 true)-->
    <setting name="aggressiveLazyLoading" value="true"/>
    <!--是否允许单个语句返回多结果集(需要数据库驱动支持)。
        默认值:true-->
    <setting name="multipleResultSetsEnabled" value="true"/>
    <!--使用列标签代替列名。实际表现依赖于数据库驱动,具体可参考数据库驱动的相关文档,或通过对比测试来观察。 
        默认值:true-->
    <setting name="useColumnLabel" value="true"/>
    <!--允许 JDBC 支持自动生成主键,需要数据库驱动支持。
          如果设置为 true,将强制使用自动生成主键。
          尽管一些数据库驱动不支持此特性,但仍可正常工作。
        默认值:false-->
    <setting name="useGeneratedKeys" value="false"/>
    <!--指定 MyBatis 应如何自动映射列到字段或属性。 
        - NONE 表示关闭自动映射;
        - PARTIAL 只会自动映射没有定义嵌套结果映射的字段;
        - FULL 会自动映射任何复杂的结果集(无论是否嵌套)。
        默认值:PARTIAL-->
    <setting name="autoMappingBehavior" value="PARTIAL"/>
    <!--指定发现自动映射目标未知列(或未知属性类型)的行为。
        - NONE: 不做任何反应
        - WARNING: 输出警告日志('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior' 的日志等级必须设置为 WARN)
        - FAILING: 映射失败 (抛出 SqlSessionException)
        默认值:NONE-->
    <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
    <!--配置默认的执行器。
        - SIMPLE 使用普通的执行器;
        - REUSE 执行器会重用预处理语句(PreparedStatement);
        - BATCH 执行器不仅重用语句还会执行批量更新。
        默认值:SIMPLE-->
    <setting name="defaultExecutorType" value="SIMPLE"/>
    <!--设置超时时间,它决定数据库驱动等待数据库响应的秒数。
        默认值:未设置 (null)-->
    <setting name="defaultStatementTimeout" value="25"/>
    <!--为驱动的结果集获取数量(fetchSize)设置一个建议值。此参数只可以在查询设置中被覆盖。
        默认值:未设置 (null)-->
    <setting name="defaultFetchSize" value="100"/>
    <!--指定语句默认的滚动策略。(新增于 3.5.2)
        - FORWARD_ONLY
        - SCROLL_SENSITIVE
        - SCROLL_INSENSITIVE
        - DEFAULT(等同于未设置 null)
        默认值:未设置 (null)-->
    <setting name="defaultResultSetType" value="DEFAULT">
    <!--是否允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为 false。
        默认值:false-->
    <setting name="safeRowBoundsEnabled" value="false"/>
    <!--是否允许在嵌套语句中使用结果处理器(ResultHandler)。如果允许使用则设置为 false。
        默认值:true-->
    <setting name="safeResultHandlerEnabled" value="true"/>
    <!--是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。
        默认值:false-->
    <setting name="mapUnderscoreToCamelCase" value="false"/>
    <!--MyBatis 利用本地缓存机制(Local Cache)防止循环引用和加速重复的嵌套查询。
        - 默认值为 SESSION,会缓存一个会话中执行的所有查询。
        - 若设置值为 STATEMENT,本地缓存将仅用于执行语句,对相同 SqlSession 的不同查询将不会进行缓存。-->
    <setting name="localCacheScope" value="SESSION"/>
    <!--当没有为参数指定特定的 JDBC 类型时,设置的默认 JDBC 类型。
        某些数据库驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可。
        常用值:NULL、VARCHAR 或 OTHER。-->
    <setting name="jdbcTypeForNull" value="OTHER"/>
    <!--指定对象的哪些方法触发一次延迟加载。
        用逗号分隔的方法列表。
        例如:equals,clone,hashCode,toString-->
    <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
    <!--指定动态 SQL 生成使用的默认脚本语言。
        配置值为一个类型别名或全限定类名-->
    <setting name="defaultScriptingLanguage" value="org.apache.ibatis.scripting.xmltags.XMLLanguageDriver"/>
    <!--指定 Enum 使用的默认 TypeHandler 。(新增于 3.4.5)
        配置值为一个类型别名或全限定类名-->
    <setting name="defaultEnumTypeHandler" value="org.apache.ibatis.type.EnumTypeHandler"/>
    <!--指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这在依赖于 Map.keySet() 或 null 值进行初始化时比较有用。注意基本类型(int、boolean 等)是不能设置成 null 的。
        默认值:false-->
    <setting name="callSettersOnNulls" value="false"/>
    <!--当返回行的所有列都是空时,MyBatis 默认返回 null。
        当开启这个设置时,MyBatis 会返回一个空实例。 
        请注意,它也适用于嵌套的结果集(如集合或关联)。(新增于 3.4.2)
        默认值:false-->
    <setting name="returnInstanceForEmptyRow" value="false"/>
    <!--指定 MyBatis 增加到日志名称的前缀。
        默认未设置-->
    <setting name="logPrefix" value="exampleLogPreFix_"/>
    <!--指定 MyBatis 所用日志的具体实现,未指定时将自动查找。
        默认未设置-->
    <setting name="logImpl" value="SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING"/>
    <!--指定 Mybatis 创建可延迟加载对象所用到的代理工具。
        可选值:CGLIB (3.5.10 起废弃) | JAVASSIST
        默认值:JAVASSIST (MyBatis 3.3 以上)-->
    <setting name="proxyFactory" value="CGLIB | JAVASSIST"/>
    <!--指定 VFS 的实现
        自定义 VFS 的实现的类全限定名,以逗号分隔。
        默认未设置-->
    <setting name="vfsImpl" value="me.iling.example.YourselfVfsImpl"/>
    <!--允许使用方法签名中的名称作为语句参数名称。
        为了使用该特性,项目必须采用 Java 8 编译,并且加上 -parameters 选项。(新增于 3.4.1)
        默认值:true-->
    <setting name="useActualParamName" value="true"/>
    <!--指定一个提供 Configuration 实例的类。
        这个被返回的 Configuration 实例用来加载被反序列化对象的延迟加载属性值。 
        这个类必须包含一个签名为 static Configuration getConfiguration() 的方法。(新增于 3.2.3)
        默认未设置-->
    <setting name="configurationFactory" value="me.iling.example.ConfigurationFactory"/>
    <!--从 SQL 中删除多余的空格字符。请注意,这也会影响 SQL 中的文字字符串。 (新增于 3.5.5)
        默认值:false-->
    <setting name="shrinkWhitespacesInSql" value="false"/>
    <!--为 'foreach' 标签的 'nullable' 属性指定默认值。(新增于 3.5.9)
        默认值:false-->
    <setting name="nullableOnForEach" value="false"/>
    <!--当应用构造器自动映射时,参数名称被用来搜索要映射的列,而不再依赖列的顺序。(新增于 3.5.10)
        默认值:false-->
    <setting name="argNameBasedConstructorAutoMapping" value="false"/>
</settings>
  

类型别名 (typeAliases)

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:

  <typeAliases>
    <typeAliase type="me.iling.dao.User" alias="User"/>
    <typeAliase type="me.iling.dao.Tag" alias="Tag"/>
</typeAliases>
  

当这样配置时,User 可以用在任何使用 me.iling.dao.User 的地方。也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:

  <typeAliases>
    <package name="me.iling.dao"/>
</typeAliases>
  
  • 每一个在包 me.iling.dao 下的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。比如 me.iling.dao.User 的别名为 user
  • 若有注解,则别名为其注解值。示例如下:
      @Alias("user")
    public class User {
        ...
    }
      

除了通过上述方法自定义的别名,Mybatis 还为我们预定义了一些常用的别名:

预设别名映射的类型
_bytebyte
_char (since 3.5.10)、
_character (since 3.5.10)
char
_longlong
_shortshort
_int、_integerint
_doubledouble
_floatfloat
_booleanboolean
stringString
byteByte
char (since 3.5.10)、
character (since 3.5.10)
Character
longLong
shortShort
int、integerInteger
doubleDouble
floatFloat
booleanBoolean
dateDate
decimal、bigdecimalBigDecimal
bigintegerBigInteger
objectObject
decimal[]BigDecimal[]
bigdecimal[]BigDecimal[]
biginteger[]BigInteger[]
object[]Object[]
mapMap
hashmapHashMap
listList
arraylistArrayList
collectionCollection
iteratorIterator

类型处理器 typeHandlers

MyBatis 在设置预处理语句 (PreparedStatement) 中的参数或从结果集中取出一个值时,会用 typeHandler 将获取到的值以合适的方式转换成 Java 类型。以下是一些默认的类型处理器:

类型处理器Java 类型JDBC 类型
BooleanTypeHandlerjava.lang.Boolean, boolean数据库兼容的 BOOLEAN
ByteTypeHandlerjava.lang.Byte, byte数据库兼容的 NUMERICBYTE
ShortTypeHandlerjava.lang.Short, short数据库兼容的 NUMERICSMALLINT
IntegerTypeHandlerjava.lang.Integer, int数据库兼容的 NUMERICINTEGER
LongTypeHandlerjava.lang.Long, long数据库兼容的 NUMERICBIGINT
FloatTypeHandlerjava.lang.Float, float数据库兼容的 NUMERICFLOAT
DoubleTypeHandlerjava.lang.Double, double数据库兼容的 NUMERICDOUBLE
BigDecimalTypeHandlerjava.math.BigDecimal数据库兼容的 NUMERICDECIMAL
StringTypeHandlerjava.lang.StringCHAR, VARCHAR
LocalDateTypeHandlerjava.time.LocalDateDATE
LocalTimeTypeHandlerjava.time.LocalTimeTIME
OffsetDateTimeTypeHandlerjava.time.OffsetDateTimeTIMESTAMP
OffsetTimeTypeHandlerjava.time.OffsetTimeTIME

详情请参考 官方文档🔗

除了上述预定义 typeHandler,我们还可以通过实现 org.apache.ibatis.type.TypeHandler 接口,或继承便利类 org.apache.ibatis.type.BaseTypeHandler 来自定义转换器。

对象工厂 objectFactory

每当 MyBatis 创建结果对象的新实例时,它都会借助一个对象工厂 (ObjectFactory) 实例来完成实例化的工作。默认的对象工厂所需执行的操作十分简单,即实例化目标类,可以通过默认的无参构造方法或者利用已存在的参数映射调用带有参数的构造方法。如果有意对对象工厂的默认行为进行改写,可以通过自行创建自己的对象工厂来实现这一目标。示例如下:

  public class ExampleObjectFactory extends DefaultObjectFactory {
  @Override
  public <T> T create(Class<T> type) {
    return super.create(type);
  }

  @Override
  public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
    return super.create(type, constructorArgTypes, constructorArgs);
  }

  @Override
  public void setProperties(Properties properties) {
    super.setProperties(properties);
  }

  @Override
  public <T> boolean isCollection(Class<T> type) {
    return Collection.class.isAssignableFrom(type);
  }
}
  

然后通过 objectFactory 元素配置自定义工厂:

  <!-- mybatis-config.xml -->
<objectFactory type="me.iling.example.ExampleObjectFactory">
  <property name="someProperty" value="100"/>
</objectFactory>
  

ObjectFactory 接口很简单,它包含两个创建实例用的方法,一个是处理默认无参构造方法的,另外一个是处理带参数的构造方法的。 另外,setProperties 方法可以被用来配置 ObjectFactory,在初始化我们的 ObjectFactory 实例后, objectFactory 元素体中定义的属性会被传递给 setProperties 方法。

插件 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", // 拦截 Executor 中的 update
  args = {MappedStatement.class,Object.class})}
)
public class ExamplePlugin implements Interceptor {
  private Properties properties = new Properties();

  @Override
  public Object intercept(Invocation invocation) throws Throwable {
    // implement pre processing if need
    Object returnObject = invocation.proceed();
    // implement post processing if need
    return returnObject;
  }

  @Override
  public void setProperties(Properties properties) {
    this.properties = properties;
  }
}
  

然后通过 plugins 元素配置插件:

  <!-- mybatis-config.xml -->
<plugins>
  <plugin interceptor="me.iling.example.ExamplePlugin">
    <property name="someProperty" value="100"/>
  </plugin>
</plugins>
  

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

环境配置 environments

在实际开发过程中,我们经常需要配置多个不同的环境,如测试、预发、生产等,由于这些环境所需的配置往往各不相同,因此可以利用 environments 属性来适应多种环境。示例如下:

  <!--加载外部文件-->
<properties resource="jdbc.properties"></properties>

<environments default="dev"> <!--指定默认的环境名称-->
    <environment id="dev"> <!--指定当前的环境名称-->
        <transactionManager type="JDBC"/> <!--指定事务管理类型是 JDBC-->
        <dataSource type="POOLED"> <!--指定当前数据源类型是连接池-->
            <!--指定数据源配置信息-->
            <property name="driver" value="${jdbc.driver}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        </dataSource>
    </environment>
    <environment id="pub"> <!--正式环境-->
        <!--...-->
    </environment>
</environments>
  

尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。如果想连接多个数据库,就需要创建多个 SqlSessionFactory 实例,每个数据库对应一个。

事物管理器 (transactionManager)

transactionManager 类型有 JDBCMANAGED 两种:

  • JDBC:直接使用 JDBC 的提交和回滚设置,它依赖于从数据源 (dataSource) 得到的连接来管理事务作用域;
  • MANAGED:什么都不做,从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 J2EE 应用服务器的上下文)。 默认情况下它会关闭连接,然而一些容器并不希望这样,因此需要将 closeConnection 属性设置为 false 来阻止它默认的关闭行为。示例如下:
      <transactionManager type="MANAGED">
        <property name="closeConnection" value="false"/>
    </transactionManager>
      

如果使用的是 Spring + MyBatis,则没有必要配置 transactionManager,因为 Spring 模块会使用自带的管理器来覆盖这里的配置。

数据源 (dataSource)

dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。MyBatis 支持以下三种内建的数据源类型:

  • UNPOOLED:不使用连接池,每次请求时打开和关闭连接,该类型的数据源支持配置以下六种属性:
    • driver – 这是 JDBC 驱动的 Java 类全限定名(并不是 JDBC 驱动中可能包含的数据源类)。
    • url – 这是数据库的 JDBC URL 地址。
    • username – 登录数据库的用户名。
    • password – 登录数据库的密码。
    • defaultTransactionIsolationLevel – 默认的连接事务隔离级别。
    • defaultNetworkTimeout – 等待数据库操作完成的默认网络超时时间(单位:毫秒)。
  • POOLED:使用连接池管理连接,除了上述几种属性,POOLED 还支持以下配置:
    • poolMaximumActiveConnections – 在任意时间可存在的活动(正在使用)连接数量,默认值:10
    • poolMaximumIdleConnections – 任意时间可能存在的空闲连接数。
    • poolMaximumCheckoutTime – 在被强制返回之前,池中连接被检出(checked out)时间,默认值:20000 毫秒(即 20 秒)
    • poolTimeToWait – 这是一个底层设置,如果获取连接花费了相当长的时间,连接池会打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直失败且不打印日志),默认值:20000 毫秒(即 20 秒)。
    • poolMaximumLocalBadConnectionTolerance – 这是一个关于坏连接容忍度的底层设置, 作用于每一个尝试从缓存池获取连接的线程。 如果这个线程获取到的是一个坏的连接,那么这个数据源允许这个线程尝试重新获取一个新的连接,但是这个重新尝试的次数不应该超过 poolMaximumIdleConnectionspoolMaximumLocalBadConnectionTolerance 之和。 默认值:3(新增于 3.4.5)
    • poolPingQuery – 发送到数据库的侦测查询,用来检验连接是否正常工作并准备接受请求。默认是“NO PING QUERY SET”,这会导致多数数据库驱动出错时返回恰当的错误消息。
    • poolPingEnabled – 是否启用侦测查询。若开启,需要设置 poolPingQuery 属性为一个可执行的 SQL 语句(最好是一个速度非常快的 SQL 语句),默认值:false。
    • poolPingConnectionsNotUsedFor – 配置 poolPingQuery 的频率。可以被设置为和数据库连接超时时间一样,来避免不必要的侦测,默认值:0(即所有连接每一时刻都被侦测 — 当然仅当 poolPingEnabled 为 true 时适用)
  • JNDI:这个数据源的实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。这种数据源配置只需要两个属性:
    • initial_context – 这个属性用来在 InitialContext 中寻找上下文(即,initialContext.lookup(initial_context))。这是个可选属性,如果忽略,那么将会直接从 InitialContext 中寻找 data_source 属性。
    • data_source – 这是引用数据源实例位置的上下文路径。提供了 initial_context 配置时会在其返回的上下文中进行查找,没有提供时则直接在 InitialContext 中查找。

映射器配置 mappers

定义完 MyBatis 的行为,接下来就要定义 SQL 映射语句了,MyBatis 可以通过 mappers 属性指定映射配置文件路径。我们可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:/// 形式的 URL),或类名和包名等。例如:

  <!-- 使用相对于类路径的资源引用 -->
<mappers>
  <mapper resource="me/iling/builder/AuthorMapper.xml"/>
  <mapper resource="me/iling/builder/BlogMapper.xml"/>
  <mapper resource="me/iling/builder/PostMapper.xml"/>
</mappers>
  
  <!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
  <mapper class="me.iling.builder.AuthorMapper"/>
  <mapper class="me.iling.builder.BlogMapper"/>
  <mapper class="me.iling.builder.PostMapper"/>
</mappers>
  
  <!-- 将包内的映射器接口全部注册为映射器 -->
<mappers>
  <package name="me.iling.builder"/>
</mappers>