JavaWeb进阶之路:MyBatis-配置解析

607 阅读8分钟

1. 核心配置文件

MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 Mybatis 的配置文件一般命名为 mybatis-config.xml

mybatis-config.xml 配置文件的结构如下,它有先后顺序的,如果顺序不对会报错:

  • configuration(配置)
    • properties(属性)
    • settings(设置)
    • typeAliases(类型别名)
    • typeHandlers(类型处理器)
    • objectFactory(对象工厂)
    • plugins(插件)
    • environments(环境配置)
      • environment(环境变量)
        • transactionManager(事务管理器)
        • dataSource(数据源)
    • databaseIdProvider(数据库厂商标识)
    • mappers(映射器)
<?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>
    <properties></properties>
    <settings></settings>
    <typeAliases></typeAliases>
    <typeHandlers></typeHandlers>
    <objectFactory></objectFactory>
    <plugins></plugins>
    <environments></environments>
    <databaseIdProvider></databaseIdProvider>
    <mappers></mappers>
</configuration>

2. environments(环境配置)

MyBatis 可以配置成适应多种环境。例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射。

注意:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。每个数据库对应一个 SqlSessionFactory 实例

environments 元素定义了如何配置环境。

<environments default="development">
    <!-- default可切换development环境或relase环境 -->
    <environment id="development">
        <!-- 有两种事务管理器,JDBC|MANAGED -->
        <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>
    <environment id="relase">
    	...
    </environment>
</environments>

environments 元素的 default 属性可更改使用不同的环境 ID。 environment 元素的 id 属性可为当前环境命名。

2.1 事务管理器(transactionManager)

在 MyBatis 中有两种类型的事务管理器:

  1. JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。(默认使用)

  2. MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)

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

2.2 数据源(dataSource)

dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。需要注意的是,数据源是必须配置的

dataSource 提供了3中数据源类型:

  1. UNPOOLED - 这个数据源的实现会每次请求时打开和关闭连接。(没有池的概念)
  2. POOLED - 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求。(默认使用)
  3. JNDI - 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的数据源引用。

dataSource 元素内的常用属性如下:

  • driver – 这是 JDBC 驱动的 Java 类全限定名(并不是 JDBC 驱动中可能包含的数据源类)。
  • url – 这是数据库的 JDBC URL 地址。
  • username – 登录数据库的用户名。
  • password – 登录数据库的密码。

3. 属性(properties)

我们可以通过properties属性来实现引用外部配置文件,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。

引用外部配置文件需要在资源目录下新建一个 db.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
username=root
password=123456

将外部配置文件 db.properties 导入到 mybatis-config.xml 配置文件中:

<?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>
    <!-- 导入外部配置文件 -->
    <properties resource="db.properties"/>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <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>
    ...
</configuration>

除了上述情况,还有一种情况,我们可以自己添加一些属性。例如 db.properties 中没有 usernamepassword 属性,我们可以在 mybatis-config.xml 配置文件中的 properties 标签内添加属性, 例如:

db.properties 文件

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC

mybatis-config.xml 文件

<?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>
    <properties resource="db.properties">
        <!-- 自己添加属性 -->
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </properties>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <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>
    ...
</configuration>

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

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

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

从 MyBatis 3.4.2 开始还新增了一个新的功能,为占位符指定一个默认值,使用方法可参考:mybatis.org/mybatis-3/z…

4. 类型别名(typeAliases)

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

Mybatis 提供了2种方法给我们设置类型别名:

第一种:单独为 Java Bean 命名。

mybatis-config.xml 配置文件中设置:

<?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>
    <properties resource="db.properties">
        ...
    </properties>
    <!-- 类型别名 -->
    <typeAliases>
        <typeAlias type="com.lmx.demo.pojo.User" alias="User"/>
    </typeAliases>
    <environments default="development">
        ...
    </environments>
    <mappers>
        ...
    </mappers>
</configuration>

设置完成后,可在任何使用 com.lmx.demo.pojo.User 的地方使用 User ,例如:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lmx.demo.mapper.UserMapper">
    <!-- 使用类型别名 -->
    <select id="getUserList" resultType="User">
        select * from user;
    </select>

    <insert id="addUser" parameterType="User">
        insert into user (name, password) VALUES (#{name}, #{password});
    </insert>
</mapper>

第二种:扫描包下的所有 Java Bean。

只需在 Mybatis-config.xml 中的 typeAliases 配置一下:

<?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>
    <properties resource="db.properties">
        ...
    </properties>
    <!-- 类型别名 -->
    <typeAliases>
        <!-- MyBatis 会在包名下面搜索需要的 Java Bean -->
        <package name="com.lmx.demo.pojo"/>
    </typeAliases>
    <environments default="development">
        ...
    </environments>
    <mappers>
        ...
    </mappers>
</configuration>

通过 package 设置好后, MyBatis 会在包名下面搜索需要的 Java Bean ,会使用 Bean 的首字母小写的非限定类名来作为它的别名。例如 com.lmx.demo.pojo.User 的别名为 user 。除此之外,还可以通过注解的方式进行设置别名,当前提是在扫描的包下面,例如:

<?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>
    <properties resource="db.properties">
        ...
    </properties>
    <!-- 类型别名 -->
    <typeAliases>
        <!-- MyBatis 会在包名下面搜索需要的 Java Bean -->
        <package name="com.lmx.demo.pojo"/>
    </typeAliases>
    <environments default="development">
        ...
    </environments>
    <mappers>
        ...
    </mappers>
</configuration>

Java Bean:

package com.lmx.demo.pojo;

import org.apache.ibatis.type.Alias;

// 将别名设置为注解中的值
@Alias("User")
public class User {

  private long id;
  private String name;
  private String password;

}

注意:Mybatis 扫描包下的 Java Bean 时,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。若有注解,则别名为其注解值。

下面是一些为常见的 Java 类型内建的类型别名。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。

别名映射的类型
_bytebyte
_longlong
_shortshort
_intint
_integerint
_doubledouble
_floatfloat
_booleanboolean
stringString
byteByte
longLong
shortShort
intInteger
integerInteger
doubleDouble
floatFloat
booleanBoolean
dateDate
decimalBigDecimal
bigdecimalBigDecimal
objectObject
mapMap
hashmapHashMap
listList
arraylistArrayList
collectionCollection
iteratorIterator

5. 映射器(mappers)

用于定义 SQL 映射语句。如果为定义 SQL 映射语句,在程序执行时会报 MapperRegiseter 错误。

我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。 你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:/// 形式的 URL),或类名和包名等。

  1. 资源引用:

    推荐使用

    <!-- 使用相对于类路径的资源引用 -->
    <mappers>
    	<!-- 这种方式是将 UserMapper.xml 放入 resource/mapper 目录下 -->
        <mapper resource="mapper/UserMapper.xml"/>
        <!-- 这种方式是将 UserMapper.xml 放入 src/main/java/com/lmx/demo/mapper 目录下 -->
        <mapper resource="com/lmx/demo/mapper/UserMapper.xml"/>
    </mappers>
    
  2. 完全限定资源定位符(URL):

    不推荐使用

    <!-- 使用完全限定资源定位符(URL) -->
    <mappers>
        <mapper url="file:///var/mappers/AuthorMapper.xml"/>
        <mapper url="file:///var/mappers/BlogMapper.xml"/>
        <mapper url="file:///var/mappers/PostMapper.xml"/>
    </mappers>
    
  3. 接口实现类的完全限定类名:

    <!-- 使用映射器接口实现类的完全限定类名 -->
    <mappers>
        <!-- 这种方式需要将 UserMapper.xml 和 UserMapper.java 在同一个包下;接口名和配置文件必须同名 -->
        <mapper class="com.lmx.demo.mapper.UserMapper"/>
    </mappers>
    

    注意点:

    • Mapper 接口和 Mapper.xml 必须在同一个包下。否则会出错!
    • Mapper 接口和 Mapper.xml 必须同名。否则会出错!
    • 如果采用 class 方式引入 需要在 pom.xml 开启文件过滤。可参考 JavaWeb进阶之路:MyBatis初体验
  4. 包内的接口实现全部注册为映射器:

    <!-- 将包内的映射器接口实现全部注册为映射器 -->
    <mappers>
        <package name="com.lmx.demo.mapper"/>
    </mappers>
    

    使用这种方式注册 Mapper 也需要像 class 方式那注意3点。

6. 设置(settings)

在 Mybatis 中 settings 的设置极为重要,会改变MyBatis 的运行时行为。一个配置完整的 settings 元素的示例如下:

<?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>
    <settings>
        <!--全局全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存,默认为true-->
        <setting name="cacheEnabled" value="true"/>
        <!--延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。默认值为false -->
        <setting name="lazyLoadingEnabled" value="false"/>
        <!--当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载,默认值false-->
        <setting name="aggressiveLazyLoading" value="false"/>
        <!--是否允许单一语句返回多结果集,默认值为true-->
        <setting name="multipleResultSetsEnabled" value="true"/>
        <!--使用列标签代替列名,默认值为true-->
        <setting name="useColumnLabel" value="true"/>
        <!--允许 JDBC 支持自动生成主键,需要驱动兼容,默认值为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="NONE"/>
        <!--配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements); BATCH 执行器将重用语句并执行批量更新。默认值为SIMPLE -->
        <setting name="defaultExecutorType" value="SIMPLE"/>
        <!--设置超时时间,它决定驱动等待数据库响应的秒数。参数为任意正整数,未设置默认值-->
        <setting name="defaultStatementTimeout" value="25"/>
        <!--为驱动的结果集获取数量(fetchSize)设置一个提示值。此参数只可以在查询设置中被覆盖。参数为任意正整数,未设置默认值 -->
        <setting name="defaultFetchSize" value="100"/>
        <!--允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为false,默认值未false -->
        <setting name="safeRowBoundsEnabled" value="false"/>
        <!--允许在嵌套语句中使用分页(ResultHandler)。如果允许使用则设置为false。默认值为true -->
        <setting name="safeResultHandlerEnabled" value="true"/>
        <!--是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射,默认值为false -->
        <setting name="mapUnderscoreToCamelCase" value="false"/>
        <!--MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。
			默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。
			若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlSession 的不同调用将不会共享数据。-->
        <setting name="localCacheScope" value="SESSION"/>
        <!--当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需要指定列的 JDBC 类型,多数情
        况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。默认值为OTHER -->
        <setting name="jdbcTypeForNull" value="OTHER"/>
        <!--指定哪个对象的方法触发一次延迟加载。 -->
        <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
        <!--指定动态 SQL 生成的默认语言。-->
        <setting name="defaultScriptingLanguage" value="org.apache.ibatis.scripting.xmltags.XMLLanguageDriver"/>
        <!--指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这对于有 Map.keySet() 依赖或
        null 值初始化的时候是有用的。注意基本类型(int、boolean等)是不能设置成 null 的。-->
        <setting name="callSettersOnNulls" value="false"/>
        <!--当返回行的所有列都是空时,MyBatis默认返回null。 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的
            结果集 (i.e. collectioin and association)。(从3.4.2开始-->
        <setting name="returnInstanceForEmptyRow" value="false"/>
        <!--指定 MyBatis 增加到日志名称的前缀-->
        <setting name="logPrefix" value="log"/>
        <!--指定 MyBatis 所用日志的具体实现,未指定时将自动查找
            SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING。 -->
        <setting name="logImpl" value="LOG4J"/>
        <!--指定 Mybatis 创建具有延迟加载能力的对象所用到的代理工具。CGLIB | JAVASSIST-->
        <setting name="proxyFactory" value="JAVASSIST"/>
        <!--指定VFS的实现-->
        <setting name="vfsImpl" value="vfs"/>
        <!--允许使用方法签名中的名称作为语句参数名称。 为了使用该特性,你的工程必须采用Java 8编译,并且加上-parameters选项。
           (从3.4.1开始)-->
        <setting name="useActualParamName" value="true"/>
        <!--指定一个提供Configuration实例的类。 这个被返回的Configuration实例用来加载被反序列化对象的懒加载属性值。 
            这个类必须包含一个签名方法static Configuration getConfiguration(). (从 3.2.3 版本开始)-->
        <setting name="configurationFactory" value="configClass"/>
    </settings>
</configuration>

7.类型处理器(typeHandlers)

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

还可以重写类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。

详情请看:官方参考文档-类型处理器

8. 对象工厂(objectFactory)

每次 MyBatis 创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成实例化工作。 默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认无参构造方法,要么通过存在的参数映射来调用带有参数的构造方法。 如果想覆盖对象工厂的默认行为,可以通过创建自己的对象工厂来实现。

详情请看:官方参考文档-对象工厂

9. 插件(pligins)

可以通过插件的方式帮助我们快速的编写代码。常用的插件有:

  1. MyBatis Generator Core

  2. MyBatis Plus

详情请看:官方参考文档-插件

10. 数据库厂商标识(databaseIdProvider)

MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。MyBatis 会加载带有匹配当前数据库 databaseId 属性和所有不带 databaseId 属性的语句。 如果同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃。 为支持多厂商特性,只要像下面这样在 mybatis-config.xml 文件中加入 databaseIdProvider 即可:

<databaseIdProvider type="DB_VENDOR" />

详情请看:官方参考文档-数据库厂商标识