本文通过 main() 方法来用 mybatis 执行带参数的 SQL 命令,来介绍 mybatis 执行 SQL 的大致过程。

准备数据库

准备一个 MySQL 数据库,十分钟内快速运行起一个 MySQL 的方法可以看这篇文章

数据库内创建一张很简单的表:

create database test;
use test;
create table t1(int id);
insert into t1 set id=11;

创建项目

首先创建一个空的 Maven 项目,加上下面的依赖关系:

<dependencies>
  <!-- mybatis 本身 -->
  <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.0</version>
  </dependency>
  <!-- 连接池数据源 -->
  <dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-dbcp2</artifactId>
    <version>2.5.0</version>
  </dependency>
  <!-- 数据库驱动 -->
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.15</version>
  </dependency>
  <!-- 日志输出 -->
  <dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
  </dependency>
</dependencies>

创建 main() 方法

在项目中随便创建一个类,写一个空的 main() 方法,确认这个方法可以正常运行。

接下来我们在 main() 方法中,一步一步完成这个使用 mybatis 执行 SQL 命令的例子。

1. 初始化数据源

要连接数据库,自然要先准备好数据源对象,这里就不多做解释了:

String url = "jdbc:mysql://localhost/test?serverTimezone=UTC";
String username = "root";
String password = "root123";

org.apache.commons.dbcp2.BasicDataSource dataSource = new BasicDataSource();
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);

dataSource 变量就是准备好的数据源对象。

2. 定义要执行的 SQL 命令

SqlCommandType commandType = SqlCommandType.SELECT;
String commandId = "sql1";
String commandStatement = "select * from t1 where id=#{id}";

String parameterName = "id";
Class<?> parameterType = Integer.class;
Object parameterValue = 11;

Class<?> resultType = HashMap.class;
List<ResultMapping> resultPropertyMappings = Collections.emptyList();

这个定义分为三部分:

  • 一是命令本身,包括命令的类型、ID、语句。在 mybatis 中,每条 SQL 命令都有唯一的 ID,因为在 SqlSession 里面,执行哪条 SQL 命令就是通过 ID 来指定的。
  • 二是参数,包括参数的名称、类型、参数值。这个例子中只有一个参数,参数名称 id 和语句里面的 #{id} 名称必须保持一致。
  • 三是返回值的类型。返回值的类型包括两部分,一是返回结果本身的类型,二是返回结果的每个字段各是什么类型(用于转换)。这个例子当中,我们简单的将返回结果包装为 Map 对象,所以里面的字段值就不去指定类型转换了,即 resultPropertyMappings 变量是个空的 List。

上面这 8 个变量,会在组装 mybatis 的 SQL 命令过程中用到。

3. 初始化 mybatis 配置

mybatis 的所有配置都在 org.apache.ibatis.session.Configuration 对象当中。Configuration 对象是一个很复杂的对象,涵盖了执行 SQL 命令需要的所有东西。正常使用的情况下,我们要为它配置 XML 路径、Mapper 所在的包、查询结果的类型转换等等。在本文的例子当中,我们用不到 XML,所以只做最简单的配置:

JdbcTransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("default", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);

可以看出,dataSource 变量是先放入 Environment 对象,然后再放入 Configuration 对象的。到这里,mybatis 的数据源就配置好了。接下来我们将之前定义的 SQL 命令加入 mybatis。

4. 构建 MappedStatement

mybatis 当中所有的 SQL 命令最终都是一个 MappedStatement 对象。但要构建它可不简单,我们要把前面定义的 SQL 命令三部分分别构建相应的对象,然后再组装成 MappedStatement 对象。

// 1. 构建 SqlSource 对象
SqlSource sqlSource = new SqlSourceBuilder(
    configuration
).parse(
    commandStatement, parameterType, null
);

// 2. 构建 ResultMap 对象
String resultMapId = commandId + "-Inline";
ResultMap resultMap = new ResultMap.Builder(
    configuration, resultMapId, resultType, resultPropertyMappings, null
).build();

// 3. 构建 ParameterMap 对象
ParameterMap parameterMap = new ParameterMap.Builder(
    configuration, commandId, null,
    Collections.singletonList(
        new ParameterMapping.Builder(
            configuration, parameterName, Integer.class
        ).build()
    )
).build();

// 4. 将 SqlSource 对象、 ResultMap 对象和 ParameterMap 对象
//    组合成最终的 MappedStatement 对象
MappedStatement mappedStatement = new MappedStatement.Builder(
    configuration, commandId, sqlSource, commandType
).resultMaps(
    Collections.singletonList(resultMap)
).parameterMap(
    parameterMap
).build();

看得出,因为构建起来很复杂,所以 mybatis 定义了大量 Builder 类来用。

5. 将 MappedStatement 加入 mybatis

configuration.addMappedStatement(mappedStatement);

所有的 MappedStatement 都要放入 Configuration

6. 初始化 SqlSession 并执行 SQL 命令

这一步相信熟悉 mybatis 的同学都会用,就不多解释了。

SqlSessionFactory sqlSessionFactory = new DefaultSqlSessionFactory(configuration);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
List<Object> result = sqlSession.selectList(commandId, parameterValue);

System.out.println(result);

上面这六个片段依次加入 main() 方法,即可完整执行。这就是 mybatis 执行 SQL 命令的基本套路。

有的同学就会问,那我在 XML 里面定义的 SQL 语句是怎么解析执行的呢?mybatis 有个叫 org.apache.ibatis.scripting.LanguageDriver 的接口类,负责将 XML 或其他语言的动态 SQL 模板解析为最终的 SQL 语句,然后交给 SqlSourceBuilder 生成 SqlSource 对象。具体可以看看源码。相信理解了本文之后再去看 mybatis 的源码,会对它的执行机制有更清晰的了解。


捏造的信仰
2.8k 声望272 粉丝

Java 开发人员