Mybatis之配置详解

9 篇文章 0 订阅
7 篇文章 0 订阅

Mybatis系列文章
Mybatis之配置详解
Mybatis之XML 映射器详解
Mybatis之动态 SQL详解
Mybatis之缓存详解
Mybatis之映射器注解详解
Mybatis之Mybatis Generator vs IDEA插件 自动生成代码

前言

以下描述的配置标签,均以xml配置标签为主,即mybatis-config.xml配置文件里的标签,不过多介绍通过application.yml来进行配置,因为两者配置是等价的,这里推荐将mybatis配置集中配置在mybatis-config.xml中。
配置目录结构如下:
在这里插入图片描述

属性(properties)

这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java properties属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。例如:

<properties resource="org/mybatis/example/config.properties">
  <property name="username" value="dev_user"/>
  <property name="password" value="F2Fa3!33TYyg"/>
</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>

这个例子中的 username 和 password 将会由 properties 元素中设置的相应值来替换。 driver 和 url 属性将会由 config.properties 文件中对应的值来替换。这样就为配置提供了诸多灵活选择。

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

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

MyBatis 3.4.2开始,你可以为占位符指定一个默认值。例如:

<dataSource type="POOLED">
  <!-- ... -->
  <property name="username" value="${username:ut_user}"/> 
  <!-- 如果属性 'username' 没有被配置,'username' 属性的值将为 'ut_user' -->
</dataSource>

这个特性默认是关闭的。要启用这个特性,需要添加一个特定的属性来开启这个特性。例如:

<properties resource="org/mybatis/example/config.properties">
  <!-- ... -->
  <property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/>
  <!-- 启用默认值特性 -->
</properties>

注意:启用默认值特性 仅对configuration、SQL中${}占位符有用
提示 如果你在属性名中使用了 “:” 字符(如:db:username),或者在 SQL 映射中使用了 OGNL 表达式的三元运算符(如: ${tableName != null ? tableName : ‘global_constants’}),就需要设置特定的属性来修改分隔属性名和默认值的字符。例如:

<properties resource="org/mybatis/example/config.properties">
  <!-- ... -->
  <property name="org.apache.ibatis.parsing.PropertyParser.default-value-separator" value="?:"/> 
  <!-- 修改默认值的分隔符 -->
</properties>
<dataSource type="POOLED">
  <!-- ... -->
  <property name="username" value="${db:username?:ut_user}"/>
</dataSource>

设置(settings)

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

一个推荐的 settings 元素的示例如下:

    <settings>
        <!--是否开启二级缓存-->
        <setting name="cacheEnabled" value="true"/>
        <!--自动映射列到字段或属性的行为 PARTIAL 只会自动映射没有定义嵌套结果映射的字段-->
        <setting name="autoMappingBehavior" value="PARTIAL"/>
        <!--发现自动映射目标未知列(或未知属性类型)的行为 NONE: 不做任何反应-->
        <setting name="autoMappingUnknownColumnBehavior" value="NONE"/>
        <!--配置默认的执行器-->
        <setting name="defaultExecutorType" value="SIMPLE"/>
        <!--一级缓存 STATEMENT使一级缓存不起作用-->
        <setting name="localCacheScope" value="SESSION"/>
        <!--空值的默认 JDBC 类型-->
        <setting name="jdbcTypeForNull" value="OTHER"/>
        <!--指定 Enum 使用的默认 TypeHandler-->
        <setting name="defaultEnumTypeHandler" value="org.apache.ibatis.type.EnumTypeHandler"/>
        <!--非默认值,设置驼峰匹配-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!--控制台打印 可打印sql入参出参-->
        <setting name="logImpl" value="STDOUT_LOGGING" />
        <!--当返回行的所有列都是空时,MyBatis默认返回 null。 当开启这个设置时,MyBatis会返回一个空实例-->
        <setting name="returnInstanceForEmptyRow" value="false" />
    </settings>

关于Mybatis延迟加载

Mybatis的延迟加载主要针对于嵌套select查询,在配置文件中通过两个属性lazyLoadingEnabledaggressiveLazyLoading来控制延迟加载按需加载
lazyLoadingEnabled:是否启用延迟加载,mybatis默认为false,不启用延迟加载。lazyLoadingEnabled属性控制全局是否使用延迟加载,特殊关联关系也可以通过嵌套查询中fetchType属性单独配置(fetchType属性值lazy或者eager)。
aggressiveLazyLoading:是否按需加载属性,默认值false,启用该属性并且lazyLoadingEnabled属性启用时只要加载对象,就会加载该对象的所有属性;关闭该属性则会根据lazyLoadTriggerMethods按需加载,使用到某关联属性时,实时执行嵌套查询加载该属性。
一般常用用法不开启lazyLoadingEnabled,通过关联结果集中fetchType来指定使用延迟加载。

<resultMap id="StudentWithSchoolResultMap" type="com.nestor.mybatisdemo.dto.StudentDTO">
    <id property="id" column="id"/>
    <result property="name" column="name"/>
    <result property="age" column="age"/>
    <result property="sex" column="sex" typeHandler="com.nestor.mybatisdemo.anothertypehandler.BaseEnumTypeHandler"/>
    <result property="enterScore" column="enter_score"/>
    <result property="createTime" column="create_time"/>
    <result property="updateTime" column="update_time"/>
    <association property="school" javaType="School" column="school_id" select="com.nestor.mybatisdemo.mapper.SchoolMapper.selectById" fetchType="lazy"/>
</resultMap>

类型别名(typeAliases)

  • 类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:
<typeAliases>
  <typeAlias alias="Author" type="domain.blog.Author"/>
  <typeAlias alias="Blog" type="domain.blog.Blog"/>
  <typeAlias alias="Comment" type="domain.blog.Comment"/>
  <typeAlias alias="Post" type="domain.blog.Post"/>
  <typeAlias alias="Section" type="domain.blog.Section"/>
  <typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>
  • 指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
<typeAliases>
  <package name="domain.blog"/>
</typeAliases>

每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的非限定类名来作为它的别名。 若有注解,则别名为其注解值。见下面的例子:

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

下面是一些为常见的 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

类型处理器(typeHandlers)

MyBatis 在设置预处理语句(PreparedStatement)中的参数或从结果集中取出一个值时, 都会用类型处理器将获取到的值以合适的方式转换成 Java 类型。下表描述了一些默认的类型处理器。
提示 从 3.4.5 开始,MyBatis 默认支持 JSR-310(日期和时间 API) 。

类型处理器Java 类型JDBC 类型
BooleanTypeHandlerjava.lang.Boolean, booleanBOOLEAN
ByteTypeHandlerjava.lang.Byte, byteNUMERIC 或 BYTE
ShortTypeHandlerjava.lang.Short, shortNUMERIC 或 SMALLINT
IntegerTypeHandlerjava.lang.Integer, intNUMERIC 或 INTEGER
LongTypeHandlerjava.lang.Long, longNUMERIC 或 BIGINT
FloatTypeHandlerjava.lang.Float, floatNUMERIC 或 FLOAT
DoubleTypeHandlerjava.lang.Double, doubleNUMERIC 或 DOUBLE
BigDecimalTypeHandlerjava.math.BigDecimalNUMERIC 或 DECIMAL
StringTypeHandlerjava.lang.StringCHAR, VARCHAR
ClobReaderTypeHandlerjava.io.Reader-
ClobTypeHandlerjava.lang.StringCLOB, LONGVARCHAR
NStringTypeHandlerjava.lang.StringNVARCHAR, NCHAR
NClobTypeHandlerjava.lang.StringNCLOB
BlobInputStreamTypeHandlerjava.io.InputStream-
ByteArrayTypeHandlerbyte[]字节流类型
BlobTypeHandlerbyte[]BLOB, LONGVARBINARY
DateTypeHandlerjava.util.DateTIMESTAMP
DateOnlyTypeHandlerjava.util.DateDATE
TimeOnlyTypeHandlerjava.util.DateTIME
SqlTimestampTypeHandlerjava.sql.TimestampTIMESTAMP
SqlDateTypeHandlerjava.sql.DateDATE
SqlTimeTypeHandlerjava.sql.TimeTIME
ObjectTypeHandlerAnyOTHER 或未指定类型
EnumTypeHandlerEnumeration TypeVARCHAR 或任何字符串类型,用来存储枚举的名称
EnumOrdinalTypeHandlerEnumeration Type任何NUMERIC 或 DOUBLE 类型,用来存储枚举的序数值。
SqlxmlTypeHandlerjava.lang.StringSQLXML
InstantTypeHandlerjava.time.InstantTIMESTAMP
LocalDateTimeTypeHandlerjava.time.LocalDateTimeTIMESTAMP
LocalDateTypeHandlerjava.time.LocalDateDATE
LocalTimeTypeHandlerjava.time.LocalTimeTIME
OffsetDateTimeTypeHandlerjava.time.OffsetDateTimeTIMESTAMP
OffsetTimeTypeHandlerjava.time.OffsetTimeTIME
ZonedDateTimeTypeHandlerjava.time.ZonedDateTimeTIMESTAMP
YearTypeHandlerjava.time.YearINTEGER
MonthTypeHandlerjava.time.MonthINTEGER
YearMonthTypeHandlerjava.time.YearMonthVARCHAR 或 LONGVARCHAR
JapaneseDateTypeHandlerjava.time.chrono.JapaneseDateDATE

你可以重写已有的类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。 具体做法为:实现 org.apache.ibatis.type.TypeHandler 接口, 或继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler, 并且可以(可选地)将它映射到一个 JDBC 类型。比如:

package com.nestor.mybatisdemo.typehandler;
/**
 * 年级枚举类型处理器
 *
 * @author : Nestor.Bian
 * @version : V 1.0
 * @date : 2020/3/22
 */
@MappedTypes(GradeLevel.class)
@MappedJdbcTypes(value = JdbcType.TINYINT, includeNullJdbcType = true)
public class GradeLevelTypeHandler extends BaseTypeHandler<GradeLevel> {

    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, GradeLevel level, JdbcType jdbcType) throws SQLException {
        System.err.println(String.format("level: %s", level));
        preparedStatement.setInt(i, level.getValue());
    }

    @Override
    public GradeLevel getNullableResult(ResultSet resultSet, String s) throws SQLException {
        return EnumUtil.getByCode(resultSet.getInt(s), GradeLevel.class);
    }

    @Override
    public GradeLevel getNullableResult(ResultSet resultSet, int i) throws SQLException {
        return EnumUtil.getByCode(resultSet.getInt(i), GradeLevel.class);
    }

    @Override
    public GradeLevel getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        return EnumUtil.getByCode(callableStatement.getInt(i), GradeLevel.class);
    }
}

mybatis-config.xml

<!--定义类型处理器-->
<typeHandlers>
    <typeHandler handler="com.nestor.mybatisdemo.anothertypehandler.BaseEnumTypeHandler"/>
    <package name="com.nestor.mybatisdemo.typehandler" />
</typeHandlers>
  • 如上配置Mybatis会自动隐式的调用,不需要显示地在入参和结果集处显式的调用typeHandler=…
  • 如果显式指定将会忽略类型,直接使用指定的类型处理器处理。
    最好明确指定@MappedJdbcTypes@MappedTypes来让Mybatis知道处理哪个类型,否则可能导致误用。
  • 不明确指定@MappedTypes可以通过类型处理器的泛型,得知该类型处理器处理的 Java 类型。
  • 当在 ResultMap 中决定使用哪种类型处理器时,此时 Java 类型是已知的(从结果类型中获得),但是 JDBC 类型是未知的。 因此 Mybatis 使用 javaType=[Java 类型], jdbcType=null 的组合来选择一个类型处理器。 这意味着使用 @MappedJdbcTypes 注解可以限制类型处理器的作用范围。 如果希望能在 ResultMap 中隐式地使用类型处理器,那么设置 @MappedJdbcTypes注解的 includeNullJdbcType=true即可。 然而如果某个 Java 类型只有一个注册的类型处理器,即使没有设置 includeNullJdbcType=true,那么这个类型处理器也会是 ResultMap 使用 Java 类型时的默认处理器。

你可以创建能够处理多个类的泛型类型处理器。为了使用泛型类型处理器, 需要增加一个接受该类的 class 作为参数的构造器,具体代码如下:

/**
 * BaseEnum枚举类型处理器
 *
 * @author : Nestor.Bian
 * @version : V 1.0
 * @date : 2020/3/22
 */
@MappedTypes({GradeLevel.class, Sex.class})
@MappedJdbcTypes(value = {JdbcType.VARCHAR, JdbcType.TINYINT}, includeNullJdbcType = true)
public class BaseEnumTypeHandler<T extends BaseEnum> extends BaseTypeHandler<T> {

    private Class<T> type;

    public BaseEnumTypeHandler(Class<T> type) {
        if (type == null) {
            throw new IllegalArgumentException("Type argument cannot be null");
        } else {
            this.type = type;
        }
    }

    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, T t, JdbcType jdbcType) throws SQLException {
        preparedStatement.setObject(i, t.getValue());
    }

    @Override
    public T getNullableResult(ResultSet resultSet, String s) throws SQLException {
        return (T) EnumUtil.getByCode(resultSet.getObject(s), type);
    }

    @Override
    public T getNullableResult(ResultSet resultSet, int i) throws SQLException {
        return (T) EnumUtil.getByCode(resultSet.getObject(i), type);
    }

    @Override
    public T getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        return (T) EnumUtil.getByCode(callableStatement.getObject(i), type);
    }

}

注意:泛型类型处理器必须明确指定@MappedTypes,来指定明确处理那些java类型

插件(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 发行包中的源代码。 如果你想做的不仅仅是监控方法的调用,那么你最好相当了解要重写的方法的行为。 因为在试图修改或重写已有方法的行为时,很可能会破坏 MyBatis 的核心模块。 这些都是更底层的类和方法,所以使用插件的时候要特别当心。

/**
 * 自定义Mybatis拦截器
 *
 * @author : Nestor.Bian
 * @version : V 1.0
 * @date : 2020/3/22
 */
@Intercepts({
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class,
                RowBounds.class, ResultHandler.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class,
                RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
        @Signature(type = Executor.class, method = "queryCursor", args = {MappedStatement.class, Object.class,
                RowBounds.class}),
})
public class CustomMybatisInterceptor implements Interceptor {

    private Properties properties;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.err.println("拦截前参数:" + Arrays.toString(invocation.getArgs()));
        Object result = invocation.proceed();
        System.err.println("拦截后结果:" + result);

        return result;
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

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

mybatis-config.xml

    <!--定义插件-->
    <plugins>
        <plugin interceptor="com.nestor.mybatisdemo.common.CustomMybatisInterceptor"></plugin>
    </plugins>

数据库厂商标识(databaseIdProvider)

MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于mapper xml映射语句中的 databaseId属性。 MyBatis 会优先加载带有 databaseId,其次加载不带 databaseId的相同语句。 为支持多厂商特性,只要像下面这样在 mybatis-config.xml 文件中加入 databaseIdProvider 即可,databaseIdProvider对应的 DB_VENDOR 实现(对应Mybatis默认提供的VendorDatabaseIdProvider)会设置简短的databaseId替代connection的DatabaseMetaData#getDatabaseProductName() 返回的字符串。下面例子中产商名称MySQL会被mysql替换,只需要在mapper xml中指定databaseId="mysql"即可。

    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis-demo?useUniCode=true&amp;characterEncoding=utf-8&amp;serverTimezone=UTC" />
                <property name="username" value="root" />
                <property name="password" value="123456" />
            </dataSource>
        </environment>
    </environments>

    <databaseIdProvider type="DB_VENDOR">
        <property name="MySQL" value="mysql"/>
        <property name="Oracle" value="oracle" />
    </databaseIdProvider>

environment:多环境配置并不是多数据源,只能用default指定一个环境,但是可以让SQL做到多环境兼容,更方便切换环境。
databaseIdProvider:给数据库厂商取别名,方便mapper xml中datasourceId指定,优执行mapper xml语句中datasourceId=当前数据源的别名的语句,其次是不带datasourceId的语句。

你可以通过实现接口 org.apache.ibatis.mapping.DatabaseIdProvider 并在 mybatis-config.xml 中注册来构建自己的 DatabaseIdProvider:

/**
 * 自定义databaseId provider
 *
 * @author : Nestor.Bian
 * @version : V 1.0
 * @date : 2020/4/18
 */
public class CustomDatabaseIdProvider implements DatabaseIdProvider {
    private static final String DATABASE_MYSQL = "MySQL";
    private static final String DATABASE_POSTGRESQL = "PostgreSQL";
    private static final String DATABASE_ORACLE = "Oracle";
    private static final String DATABASE_DB2 = "DB2";

    @Override
    public void setProperties(Properties p) {
    }

    @Override
    public String getDatabaseId(DataSource dataSource) throws SQLException {
        Connection conn = dataSource.getConnection();
        String dbName = conn.getMetaData().getDatabaseProductName();
        String dbAlias = "";
        switch (dbName) {
            case DATABASE_MYSQL:
                dbAlias = "mysql";
                break;
            case DATABASE_POSTGRESQL:
                dbAlias = "pg";
                break;
            case DATABASE_ORACLE:
                dbAlias = "oracle";
                break;
            case DATABASE_DB2:
                dbAlias = "db2";
                break;
            default:
                break;
        }
        return dbAlias;
    }
}

mybatis-config.xml中添加如下配置替换上面定义DatabaseIdProvider:

<!--使用自定义DatabaseIdProvider-->
<databaseIdProvider type="com.nestor.mybatisdemo.common.CustomDatabaseIdProvider" />

映射器(mappers)

既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。 你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:///形式的 URL),或类名和包名等。例如:

<!-- 使用相对于类路径的资源引用 -->
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
</mappers>
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
  <mapper url="file:///var/mappers/AuthorMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>

映射器接口扫描

@SpringBootApplication
@MapperScan("com.nestor.mybatisdemo.mapper")
@EnableTransactionManagement
public class MybatisDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(MybatisDemoApplication.class, args);
    }

}

在App启动类上添加@MapperScan配置需要扫描的包即可,如果不在扫描包的范围内,可以在mapper接口上加@Mapper接口,同样能被扫描到。

github工程地址https://github.com/nestorbian/spring-boot-examples/tree/master/mybatis-demo

Mybatis系列文章
Mybatis之配置详解
Mybatis之XML 映射器详解
Mybatis之动态 SQL详解
Mybatis之缓存详解
Mybatis之映射器注解详解
Mybatis之Mybatis Generator vs IDEA插件 自动生成代码

参考:
Mybatis学习系列延迟加载
Mybatis3官网
MyBatis配置文件(八)--databaseIdProvider数据库厂商标识

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值