你的位置:首页 > 信息动态 > 新闻中心
信息动态
联系我们

MyBatis配置-全局配置文件详解

2021-11-19 1:17:38

0. 工程搭建

我们还是先来搭建一个新的工程吧,跟之前的区分一下。工程名我们就叫它 mybatis-02-configuration 吧,导入的依赖跟上一章一样,然后把上一章的那些代码原样拷贝下来,我们继续拿来用。

拷贝完成后的工程结构及文件应该是这样的:

6. 工程结构.png

OK ,我们开始学习。

全局配置文件一览

MyBatis 的全局配置文件,自上而下的编写内容如下:

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

小册不会把这里面所有的内容都讲解,而是只选择一些我们平时开发中使用比较多,以及相对来讲比较重要的配置讲解。

1. properties-属性

properties 属性,它的作用是定义全局配置变量,并且它可以加载外部化的 properties 配置文件。下面我们来简单演示一下 properties 的使用。

1.1 简单使用

借助 IDE ,在 xml 中编写 <properties> 时,下面就会发现只有一个 <property> 标签,而且是标准的 key-value 格式:

    <properties>
        <property name="" value=""/>
    </properties>

所以我们可以来试着提取一下下面数据源的几个配置:

    <properties>
        <property name="jdbc.driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="jdbc.url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8"/>
        <property name="jdbc.username" value="root"/>
        <property name="jdbc.password" value="123456"/>
    </properties>

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

下面的数据源在引用配置时,只需要使用 ${} 的表达式引用即可。

配置之后,重新运行之前留下的那个 MyBatisApplication6 ,发现一切正常,说明这样配置是没有任何问题的。

1.2 加载外部化配置文件

如果仅仅是为了在上面定义 property 的话,那这未免显得有那么一点点鸡肋,我们也没必要把它单独拎出来讲。<properties> 标签是可以直接声明 resource 或者 url 来加载外部化配置文件的。下面我们也简单演示一下。

先把 properties 文件编写出来:

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=123456

然后,使用 <properties> 标签把这个 properties 文件加载进来即可:

    <properties resource="jdbc.properties" />

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

是不是比上面的方式简单多了?所以这种写法才是我们平时使用相对比较多的方式。重新运行 MyBatisApplication6 ,程序仍然可以正常运行,说明这样写也是完全没问题的。

注意,resource 或者 url 只能声明一个文件, MyBatisApplication6 ,。如果真的需要一次性加载多个外部化配置文件,下面我们马上会说。

另外还有一点,resource 跟 url 是互斥的,二者只能取其一,如果两个都定义,MyBatis 都没办法初始化,会抛出异常!所以我们只需要声明一个属性即可。

1.3 加载多个外部化配置文件

如果真的需要一次性加载多个外部化配置文件,使用 xml 配置的方式是无法实现的。不过我们可以换一种思路来实现:Properties 这个类是可以加载多个 properties 文件到一个对象中的,所以我们可以基于这个思路来实现。

先来造两个外部化配置文件吧,这次我们把数据源连接的几个属性拆到两个文件中:(越写越感觉奇怪,这例子有点勉强哈,,,)

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=123456

然后,全局配置文件中的 <properties> 可以先暂时屏蔽掉了。

最后,我们来试试编程式加载这些 properties 文件:

public class LoadPropertiesApplication {
    
    public static void main(String[] args) throws Exception {
        InputStream xml = Resources.getResourceAsStream("mybatis-config.xml");
        // 使用Properties的API加载这些properties文件
        Properties properties = new Properties();
        properties.load(Resources.getResourceAsStream("jdbc1.properties"));
        properties.load(Resources.getResourceAsStream("jdbc2.properties"));
        
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(xml, properties);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        
        DepartmentMapper departmentMapper = sqlSession.getMapper(DepartmentMapper.class);
        Department department = departmentMapper.findById("18ec781fbefd727923b0d35740b177ab");
        System.out.println(department);
        System.out.println(department.getUsers());
    }
}

像上面代码中的写法,我们直接借助 MyBatis 加载资源文件的能力,就能把这几个 properties 文件都加载上来。这样编写完成后,运行 main 方法也是完全没有问题的。

1.4 配置优先级

所以总结下来,配置属性的方式有 3 种:

  • 直接在 <properties> 中定义配置属性
  • 借助 <properties> 的 resource / url 属性加载外部化配置文件
  • 编程式加载外部化配置文件

所以这三种方式定义的配置属性,谁的优先级更高呢?按照官方文档的说法,MyBatis 会按照上面所述的顺序读取配置属性,而下面的属性会覆盖上面的,所以优先级的顺序就刚好与上面列举的顺序相反:

  • 编程式加载的外部化配置文件
  • 借助 <properties> 的 resource / url 属性加载的外部化配置文件
  • 在 <properties> 中定义的配置属性

具体的顺序加载,小伙伴们可以自行测试一下,小册就不带各位慢慢折腾了。

小册提供一个测试思路,可以通过创建几个不同的数据库,每个数据库中都有同样的表,但每个库中表的数据内容不一样,看一下最终控制台打印的数据内容,就可以判断数据来自哪个数据库,从而得出最终加载的配置是来自哪里了。

2. setting-配置

setting 配置,这里面提供了 MyBatis 中可供调整的所有内部配置项的全局设置。全部的配置项,我们都可以参照官方文档来配置,这里我们列出几个相对重要的配置项看一看,先混个脸熟:

配置项描述可选值默认值
cacheEnabled全局开启二级缓存true / falsetrue
lazyLoadingEnabled全局开启延迟加载true / falsefalse
mapUnderscoreToCamelCase驼峰命名转下划线命名true / falsefalse
logImpl日志提供商SLF4J / LOG4J / LOG4J2 /COMMONS_LOGGING / ...(空)

这些配置,都是基于实际的需求进行修改,所以小伙伴们没有必要去记它们,随用随查即可。

3. typeAliases-类型别名

typeAliases 类型别名的设置,是考虑到 mapper.xml 中我们每次写实体类的时候,都要写它们的全限定类名,太麻烦,于是 MyBatis 提供了类型别名的机制。这部分应当属于学习 MyBatis 就应该一并学习了的知识,所以这里我们快速过一下就 OK 了。

    <typeAliases>
        <!-- 逐个声明 -->
        <typeAlias alias="Department" type="com.linkedbear.mybatis.entity.Department"/>
        
        <!-- 包扫描
             以此法被扫描的实体类,别名为类名的首字母小写形式(类似于Bean -> bean)
        -->
        <package name="com.linkedbear.mybatis.entity"/>
    </typeAliases>

另外,不要忘记一点,MyBatis 的别名是不区分大小写的。

4. typeHandlers-类型处理器

typeHandlers 类型处理器,它的意义是针对一个特定的 Java 类型,或者 jdbc 类型,采用特定的处理器来处理这个类型的字段。听起来这个概念很陌生,但实际上 MyBatis 本身内部就已经预置了好多好多类型处理器了,举几个例子吧:

类型处理器javaTypejdbcType
IntegerTypeHandlerInteger 、intint / numeric
DoubleTypeHandlerDouble 、doubledouble / numberic
StringTypeHandlerStringvarchar / char
DateTypeHandlerDatetimestamp
EnumTypeHandlerEnumvarchar / char

可见,Java 类型和 jdbc 类型之间,用什么类型进行转换,都是这些 typeHandler 干的活。

一般情况下,我们只需要使用 MyBatis 内置的这些 typeHandler 就完全够用,如果实在是满足不了需求,也没关系,我们可以针对某些特定的类型,自定义 typeHandler 来处理。下面我们简单介绍下如何自定义 typeHandler 。

4.1 定义DepartmentTypeHandler

我们自己定义的 TypeHandler ,都需要实现 TypeHandler 接口,并声明其泛型,泛型就是要处理的目标类型。

TypeHandler 接口中定义了 4 个方法,大面上分两类:当 mapper.xml 中定义的 statement 中出现指定泛型类型的参数时,如何对 PreparedStatement 操作查询动作封装结果集时,对于实体类中出现的指定泛型类型的属性时,应该如何从 ResultSet 中取到数据,并转换为指定类型。所以按照这个思路,我们在实现这些方法时,思路就比较简单了:

public class DepartmentTypeHandler implements TypeHandler<Department> {
    
    @Override
    public void setParameter(PreparedStatement ps, int i, Department department, JdbcType jdbcType) throws SQLException {
        ps.setString(i, department.getId());
    }
    
    @Override
    public Department getResult(ResultSet rs, String columnName) throws SQLException {
        Department department = new Department();
        department.setId(rs.getString(columnName));
        return department;
    }
    
    @Override
    public Department getResult(ResultSet rs, int columnIndex) throws SQLException {
        Department department = new Department();
        department.setId(rs.getString(columnIndex));
        return department;
    }
    
    @Override
    public Department getResult(CallableStatement cs, int columnIndex) throws SQLException {
        Department department = new Department();
        department.setId(cs.getString(columnIndex));
        return department;
    }
}

这样就算编写完成了,都非常简单,小伙伴们扫一眼,快速跟着写一下就 OK 。

4.2 注册、使用DepartmentTypeHandler

编写完成后,下面我们把它注册到 MyBatis 全局中。

4.2.1 手动使用

注意在注册 TypeHandler 的时候,需要把对应的 javaType 和 jdbcType 也都声明好:

    <typeHandlers>
        <typeHandler handler="com.linkedbear.mybatis.handler.DepartmentTypeHandler"
                     javaType="com.linkedbear.mybatis.entity.Department" jdbcType="VARCHAR"/>
    </typeHandlers>

只注册好还不够,如果此时直接在 mapper.xml 中声明 statement :

    <select id="findAllUseTypeHandler" resultType="com.linkedbear.mybatis.entity.User">
        select * from tbl_user
    </select>

调用查询时,department 属性只会为 null :

User{id='09ec5fcea620c168936deee53a9cdcfb', name='阿熊', department=null}
User{id='5d0eebc4f370f3bd959a4f7bc2456d89', name='老狗', department=null}

出现这个情况,是因为 MyBatis 只知道查询回来一个 department_id ,并不知道它要跟 department 属性挂钩。所以我们需要手动声明一个新的 resultMap ,来告诉 MyBatis ,这个 department 属性的类型是 Department ,可以使用刚刚定义的 DepartmentTypeHandler :

    <resultMap id="userHandlerMap" type="com.linkedbear.mybatis.entity.User">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="age" column="age"/>
        <result property="birthday" column="birthday"/>
        <association property="department" javaType="com.linkedbear.mybatis.entity.Department"/>
    </resultMap>

    <select id="findAllUseTypeHandler" resultMap="userHandlerMap">
        select * from tbl_user
    </select>

以此法编写完成后,接下来我们编写测试代码,从数据库中查出所有的 User :

public class DepartmentTypeHandlerApplication {
    
    public static void main(String[] args) throws Exception {
        InputStream xml = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(xml);
        SqlSession sqlSession = sqlSessionFactory.openSession();
    
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = userMapper.findAllUseTypeHandler();
        userList.forEach(System.out::println);
    }
}

运行 main 方法,可以发现 department 属性中已经不再为 null :

User{id='09ec5fcea620c168936deee53a9cdcfb', name='阿熊', department=Department{id='09ec5fcea620c168936deee53a9cdcfb', name='null', tel='null'}}
User{id='5d0eebc4f370f3bd959a4f7bc2456d89', name='老狗', department=Department{id='5d0eebc4f370f3bd959a4f7bc2456d89', name='null', tel='null'}}

4.2.2 约定大于配置

上面的问题其实可以不用声明 resultMap 也能解决,如果 User 类中能有一个 department_id 的属性,那 MyBatis 就可以识别了,我们自己定义的 DepartmentTypeHandler 也还是可以派上用场的。

public class User {
    // ......
    private Department department;
    private Department department_id;
    // ......
}

以此法封装好之后,即便是不用 resultMap ,只声明 resultType ,查询得到的 User 对象也能带 department_id 的属性了(也即 DepartmentTypeHandler 生效了):

6. 只有字段名完全一致时才可以被封装为对象.png

不过话又说回来,我们自己定义实体类的时候,按照命名规范不应当这样命名,当然一切还是以实际情况为主,如果小伙伴自己,或者所在团队对这方面没什么要求的话,那直接两边都起一样的名,也省的写了,岂不美哉?

4.2.3 保存动作的使用

下面我们再介绍一下增删改的情况,这里小册以 insert 动作为例,之前我们在写插入的时候,SQL 中不能直接放对象,得取对象的属性 ( #{department.id} ) ,但有了 TypeHandler 之后,我们就可以直接把整个 Department 对象传进去了:

    <insert id="saveUser" parameterType="com.linkedbear.mybatis.entity.User">
        insert into tbl_user (id, name, department_id) VALUES (#{id}, #{name}, #{department})
    </insert>

看,像这样直接传入整个 Departmet 对象,我们自己定义的 DepartmentTypeHandler 就会帮我们把其中的 id 取出来,设置进 PreparedStatement 中了。

下面我们改一下 main 方法,手动构造一个 User 对象,并保存进数据库:

public class DepartmentTypeHandlerApplication {
    
    public static void main(String[] args) throws Exception {
        InputStream xml = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(xml);
        SqlSession sqlSession = sqlSessionFactory.openSession();

        User user = new User();
        user.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        user.setName("hahahaha");
        Department department = new Department();
        department.setId("18ec781fbefd727923b0d35740b177ab");
        user.setDepartment(department);
        userMapper.saveUser(user);

        // commit才能使数据库操作生效
        sqlSession.commit();
        sqlSession.close();
    }
}

运行 main 方法,日志中可以打印出执行成功一条 SQL :

[main] DEBUG tis.mapper.UserMapper.saveUser  - ==>  Preparing: insert into tbl_user (id, name, department_id) VALUES (?, ?, ?) 
[main] DEBUG tis.mapper.UserMapper.saveUser  - ==> Parameters: 0e7e237ccac84518914244d1ad47e756(String), hahahaha(String), 18ec781fbefd727923b0d35740b177ab(String) 
[main] DEBUG tis.mapper.UserMapper.saveUser  - <==    Updates: 1 

与此同时数据库也成功的添加了此条数据:

6. User保存成功.png

5. objectFactory-对象工厂

objectFactory 对象工厂,要聊这个东西,我们要先了解一下,我们每次查询出来的对象数据都是如何封装出来的。

每次查询动作中,数据库返回 ResultSet 时,MyBatis 会根据 statemet 的定义,创建对应的结果对象(跟表对应的实体类对象)。而创建结果对象的工厂,是一个叫 ObjectFactory 的家伙负责的。默认情况下,MyBatis 内置了一个 DefaultObjectFactory 来实现结果对象的创建,而我们定义的结果对象通常都有默认的无参构造器,或者有显式定义无参构造器,这样也是方便 DefaultObjectFactory 帮我们创建结果对象。

既然 MyBatis 的全局配置文件中提供了 objectFactory 标签,就说明 MyBatis 允许我们自定义 ObjectFactory 以代替默认的 DefaultObjectFactory 。下面我们也来试试水,自定义一个。

先说下需求,我们要实现的功能是这样的:每次创建的 User 对象,如果数据库中的 age 属性为空,则初始化值为 0 。

5.1 定义ExtendsObjectFactory

自定义的 objectFactory ,类型必须是 org.apache.ibatis.reflection.factory.ObjectFactory ,不过我们肯定不会这么干,MyBatis 已经帮我们实现好基础的创建对象的逻辑了,我们只需要在此基础上扩展即可,所以我们都是继承默认的 DefaultObjectFactory 即可。

DefaultObjectFactory 中实现了一个按类型创建对象的方法 create ,我们可以在此基础上做做文章,代码如下:

public class ExtendsObjectFactory extends DefaultObjectFactory {
    
    @Override
    public <T> T create(Class<T> type) {
        T t = super.create(type);
        // 判断是否为User类型,如果是,则预初始化值
        if (User.class.equals(type)) {
            User user = (User) t;
            user.setAge(0);
        }
        return t;
    }
}

逻辑还是很容易编写的吧!编写完成后记得注册进 MyBatis 的全局配置文件中:

    <objectFactory type="com.linkedbear.mybatis.factory.ExtendsObjectFactory"/>

这样准备工作就搞定了。

5.2 测试效果

下面我们就来测试一下,用的代码还是上面第 4 小节中的查询代码:

    public static void main(String[] args) throws Exception {
        InputStream xml = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(xml);
        SqlSession sqlSession = sqlSessionFactory.openSession();
    
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = userMapper.findAllUseTypeHandler();
        userList.forEach(System.out::println);
    }

以 Debug 的形式运行 main 方法,可以发现上面我们刚添加的 hahaha 用户,虽然没有传入 age 属性,但查询结果中 age 属性不是 null 了,说明 ExtendsObjectFactory 已经成功发挥了作用。

6. age的属性被初始化了.png

6. plugins-插件

plugins 插件,这是我们比较熟悉的节点了。我们都知道,MyBatis 的插件实际上就是拦截器,它可以拦截 MyBatis 的执行流程,并在特定的位置上提供扩展。可供扩展的位置有 4 个:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

如果小伙伴有过 MyBatis 的使用经验,应该知道一个比较有名的分页插件 PageHelper ,它就是基于 MyBatis 的插件机制来实现的。

由于插件这部分的内容比较多,且涉及到 MyBatis 的整体生命周期和运行流程原理,所以有关插件部分的详细讲解,我们放到后面的扩展章节讲解,这里小册只是先一笔带过。

7. environments-环境

environments 环境,它类似于 SpringFramework 中的 profiles 的概念,它允许我们定义多个环境,以分别定义不同的数据库连接配置。这种场景在我们平时开发中是很常见的:开发、测试、生产分别要用到 3 种不同的环境,连接 3 个不同的数据库,这个时候就需要分别配置了。

不过,尽管我们可以定义多个环境配置,但激活生效的只允许选择一个,激活的方式是在 <environments> 标签上声明 default 属性。

一个完整的配置示例如下:

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

其余有关 environments 的内容都很简单,而且也很少用,小册就不再过多阐述。

8. databaseIdProvider-数据库厂商标识

databaseIdProvider 数据库厂商标识,它为我们提供了数据库可移植性的支持。了解 Hibernate 的小伙伴应该知道,Hibernate 的数据库可移植性是天然的,MyBatis 虽然不像 Hibernate 那样全自动,但它也提供了支持的方案:我们在编写 mapper.xml 时,针对不同的 statement ,声明不同的数据库厂商标识,MyBatis 即会动态的根据数据库厂商标识,使用不同的 statement ,从而达到不同的数据库发送不同 SQL 的效果。

下面我们来实际演示一下 databaseIdProvider 的使用。

8.1 初始化一个新的数据库环境

为了区分出不同的数据库环境,我们要在现有的数据库环境之外,再初始化一个新的数据库,而且还不能是相同的数据库厂商,小伙伴们可以任意选择 Oracle 、SQLServer 、DB2 、PostgreSQL 等数据库,小册选择使用 PostgreSQL 作为第二数据库。

数据表的话,我们只初始化一个 users 表,对标 tbl_user 表即可:

CREATE TABLE users (
    id varchar(32) NOT NULL,
    name varchar(32) NOT NULL,
    age int4,
    department_id varchar(32) NOT NULL,
    CONSTRAINT users_pkey PRIMARY KEY (id)
);
INSERT INTO users(id, name, age, department_id) VALUES ('09ec5fcea620c168936deee53a9cdcfb', '阿熊', 18, '18ec781fbefd727923b0d35740b177ab');
INSERT INTO users(id, name, age, department_id) VALUES ('5d0eebc4f370f3bd959a4f7bc2456d89', '老狗', 30, 'ee0e342201004c1721e69a99ac0dc0df');

6. postgresql数据库的users表.png

其他数据库平台的 DDL 语句很类似 ~

8.2 配置databaseIdProvider

接下来我们先在 MyBatis 的全局配置文件中,把数据库厂商的标识都定义好:

    <databaseIdProvider type="DB_VENDOR"> <!-- DB_VENDOR是固定的 -->
        <property name="MySQL" value="mysql"/>
        <property name="Oracle" value="oracle"/>
        <property name="PostgreSQL" value="postgresql"/>
    </databaseIdProvider>

这里面针对每个数据库厂商的名称,定义好对应的别名即可,这个别名在下面的 mapper.xml 中就会用到。

8.3 修改mapper.xml

mapper.xml 中,我们要分别定义两个 statement ,它们的 id 相同,SQL 不同,对应的 databaseId 不同:

    <select id="findAllByDepartmentId" parameterType="string" 
            resultType="com.linkedbear.mybatis.entity.User" databaseId="mysql">
        select * from tbl_user where department_id = #{departmentId}
    </select>

    <select id="findAllByDepartmentId" parameterType="string" 
            resultType="com.linkedbear.mybatis.entity.User" databaseId="postgresql">
        <!-- 注意这里查的表不一样 -->
        select * from users where department_id = #{departmentId}
    </select>

注意看,每个 statement 都可以声明 databaseId 属性,以指定不同的数据库厂商。

8.4 测试效果

下面我们测试一下效果,测试代码快速编写一下:

public class DatabaseProviderApplication {
    
    public static void main(String[] args) throws Exception {
        InputStream xml = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(xml);
        SqlSession sqlSession = sqlSessionFactory.openSession();
    
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = userMapper.findAllByDepartmentId("18ec781fbefd727923b0d35740b177ab");
        userList.forEach(System.out::println);
    }
}

现在我们连接的数据库是 MySQL 环境,运行 main 方法,可以发现查询回来两条数据:

[main] DEBUG erMapper.findAllByDepartmentId  - ==>  Preparing: select * from tbl_user where department_id = ? 
[main] DEBUG erMapper.findAllByDepartmentId  - ==> Parameters: 18ec781fbefd727923b0d35740b177ab(String) 
[main] DEBUG erMapper.findAllByDepartmentId  - <==      Total: 2 
User{id='09ec5fcea620c168936deee53a9cdcfb', name='阿熊', department=null}
User{id='0e7e237ccac84518914244d1ad47e756', name='hahahaha', department=null}

然后,我们修改 jdbc.properties ,将连接信息改为 PostgreSQL :

jdbc.driverClassName=org.postgresql.Driver
jdbc.url=jdbc:postgresql://localhost:5432/postgres
jdbc.username=postgres
jdbc.password=123456

再次运行 main 方法,这次只查询到了一条数据:(发送的 SQL 也变了)

[main] DEBUG erMapper.findAllByDepartmentId  - ==>  Preparing: select * from users where department_id = ? 
[main] DEBUG erMapper.findAllByDepartmentId  - ==> Parameters: 18ec781fbefd727923b0d35740b177ab(String) 
[main] DEBUG erMapper.findAllByDepartmentId  - <==      Total: 1 
User{id='09ec5fcea620c168936deee53a9cdcfb', name='阿熊', department=null}

由此可以看出 databaseIdProvider 已经生效了。

9. mappers-映射器

这个标签我们再熟悉不过了,配置 mapper.xml 都在这里面写。我们简单回顾一下它的写法吧:

    <mappers>
        <mapper resource="mapper/department.xml"/> <!-- 直接加载mapper.xml -->
        <mapper class="com.linkedbear.mybatis.mapper.UserMapper"/> <!-- 加载Mapper接口 -->
        <package name="com.linkedbear.mybatis.mapper"/> <!-- 包扫描Mapper接口 -->
    </mappers>

OK,以上就是整个 MyBatis 全局配置文件的所有标签解析,小册的解析是根据日常开发的使用,在不同的知识点上有所侧重,小伙伴们也可以参照 MyBatis 的官方文档,对全局配置文件中的一些其他内容进行了解。