MyBatis 映射器:实现简单的 SQL 语句

本文为稀土掘金技术社区首发签约文章,30天内禁止转载,30天后未获授权禁止转载,侵权必究!

大家好,我是王有志,一个分享硬核 Java 技术的互金摸鱼侠。

经过 MyBatis 核心配置讲解这两篇文章之后,相信你一定对如何配置 MyBatis 应用程序的核心参数有了清晰的认知。接下来,我们就一起来学习 MyBatis 中最重要的部分:MyBatis 映射器

MyBatis 映射器具有非常强大的功能,它能够完成:

  • 描述结果集的映射关系
  • 描述 SQL 语句与 Java 接口的映射关系
  • 实现动态的 SQL 语句
  • 配置 MyBatis 的缓存

正是因为 MyBatis 具有功能如此强大的映射器,才使得 MyBatis 成为非常多应用程序的首选 ORM 框架。

MyBatis 提供了两种实现映射器的方式:XML 形式和注解形式 。其中应用最为广泛的是通过 XML 的形式实现的映射器。因此我们今天的主题就是:MyBatis 中 XML 形式映射器的使用

好了,话不多说,我们正式开始今天的内容吧!

Tips

之前有小伙伴反馈,把每个元素和属性都讲解一遍的话,学习负担会比较大,况且有些"冷门"的知识点学习起来性价比并不高。因此在学习 MyBatis 映射器时我们不再按照 mybatis-3-mapper.dtd 中内容逐个讲解,而是选择"热门"的内容和大家分享。

MyBatis 映射器中的元素

mapper 元素是 MyBatis 映射器的根元素,是所有 MyBatis 映射器的开始 ,这点在 MyBatis 入门中定义的 UserMapper.xml 中也可以看到:

xml 复制代码
<?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.wyz.mapper.UserMapper">
  <!-- 省略 SQL 语句的映射 -->
</mapper>

mapper 元素只定义了一个属性:namespace,即命名空间。命名空间是很多编程语言或是应用框架中使用到的代码组织形式,通过命名空间来区分不同的代码片段,避免产生冲突

就像我们在 MyBatis 入门中创建的映射器 UserMapper.xml 那样,定义了 id 为"selectAll"的 SQL 语句,我们知道同一个映射器内不能出现 id 相同的 SQL 语句,但是在不同的映射器中可以出现 id 相同的 SQL 语句 。因此任何其他的映射器中都可以定义 id 为"selectAll"的 SQL 语句,但如果仅通过 id 来识别 SQL 语句的话,MyBatis 在运行时可能会选择到错误 SQL 语句上。所以 mapper 元素中引入了 namespace 这一属性,并与 SQL 语句的 id 相组合,便能够识别到唯一的 SQL 语句

除了属性 namespace 外,mapper 元素还定义了 9 个子元素:

元素 说明
select 用于声明查询语句
insert 用于声明插入语句
update 用于声明更新语句
delete 用于声明删除语句
sql 用于定义可重复使用的 SQL 语句片段
resultMap 用于描述 SQL 语句查询出的结果集与 Java 对象的映射规则
cache 用于定义当前 Mapper 中的缓存配置
cache-ref 用于引用其它 Mapper 中的缓存
parameterMap 已经被 MyBatis 官方标记为废弃,并可能会在未来的版本中移除,不建议使用

我将这 9 个元素分为了 3 类:

  • SQL 语句相关:select 元素,insert 元素,update 元素,delete 元素和 sql 元素;
  • 参数与结果集相关 :resultMap 元素和 parameterMap 元素
  • 缓存相关:cache 元素和 cache-ref 元素。

本文中,我们只关注 SQL 语句相关的 5 个元素,接下来我就按照表中的顺序,对这 5 个元素的用法做一个分享。

select 元素

select 元素用于声明查询语句,如我们在 UserMapper.xml 中定义的那样:

xml 复制代码
<select id="selectAll" resultType="com.wyz.entity.UserDO">
  select user_id, name, age, gender, id_type, id_number from user
</select

上面的查询语句中,我只使用了 select 元素的两个属性:id 和 resultType。算上这两个属性的话,MyBatis 一共为 select 元素定义了 15 个属性:

属性 说明
id SQL 语句的标识,在同一个 Mapper.xml 中是唯一的
resultType 结果集映射的 Java 类型的全限名,可以使用别名,如果是集合类型需要使用其泛型类型,与 resultMap 互斥
resultMap 引入 Mapper.xml 中定义的 resultMap ,与 resultType 互斥
parameterType SQL 语句的参数类型,需要使用 Java 类型的全限定名或者别名
parameterMap 已经被 MyBatis 官方标记为废弃,并可能会在未来的版本中移除,不建议使用
statementType SQL 语句类型,可选 STATEMENT,PREPARED 或 CALLABLE,对应 Java 中的Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED
useCache 是否使用二级缓存缓存结果,select 元素中,默认值:true
flushCache 是否在 SQL 语句调用后,清空本地缓存和二级缓存,默认值:false
timeout 设置 SQL 语句的超时时间,超过指定时间后抛出异常,单位:秒
fetchSize 设置查询结果的行数,效果依赖于数据库,如使用 Oracle 和 PostgreSQL 等支持游标的数据库时能够准确的分批次返回数据
resultSetType 结果集 resultSet 的行为模式,可选 FORWARD_ONLY,SCROLL_SENSITIVE,SCROLL_INSENSITIVE 或 DEFAULT,默认值为 DEFAULT(即 unset, 依赖于数据库厂商的设置)
resultOrdered 这个设置仅针对嵌套结果 select 语句:如果为 true,将会假设包含了嵌套结果集或是分组,当返回一个主结果行时,就不会产生对前面结果集的引用。 这就使得在获取嵌套结果集的时候不至于内存不够用。默认值:false
resultSets 存在多个结果集时,列出 SQL 语句执行后的结果集,并为每个结果集命名,名称间一逗号分隔
databaseId 数据库厂商标识,需要结合 MyBatis核心配置讲解(下)中提到的 databaseIdProvider 元素使用
lang 用于指定 SQL 语句的脚本语言的

上述的属性中,我们常用的只有 3 个:id 属性,resultType 属性和 parameterType 属性。

所有的属性中,只有 id 属性是必选项,其余都是可选项。其中 MyBatis 推荐配置查询语句的 resultType,便于更好的实现结果集的映射。另外,如果没有使用参数相关的 parameterType 属性,MyBatis 在处理时会使用类型处理器(TypeHandler)来推断参数的具体类型

下面,我们来写一个根据 user_id 查询用户的 SQL 方法,并使用 parameterType 属性。

UserMapper 接口中定义的方法如下:

java 复制代码
UserDO selectByUserId(Integer userId);

接着,我们写映射器 UserMapper.xml 中的 SQL 语句:

xml 复制代码
<select id="selectByUserId" parameterType="integer" resultType="com.wyz.entity.UserDO">
  select user_id, name, age, gender, id_type, id_number from user
  where user_id = #{userId, jdbcType=INTEGER}
</select>

最后,我们添加一个测试方法:

java 复制代码
@Test
public void testSelectByUserId() {
  SqlSession sqlSession = sqlSessionFactory.openSession();
  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

  UserDO user = userMapper.selectByUserId(2);
  log.info("查询指定用户:{}", JSON.toJSONString(user));
  sqlSession.close();
}

通过测试可以看到,控制台成功输出了 user_id 为 2 的用户的数据。

在定义UserMapper#selectByUserId方法的 SQL 语句时,parameterType 属性中并没有使用 Integer 的全限名,而是使用了全小写字母的"integer",这是因为 MyBatis 已经为常见的 Java 类型定义了别名,在使用时既可以使用全限名,也可以使用 MyBatis 的别名。

Tips:MyBatis 的别名注册位于 TypeAliasRegistry 类中。

#{} 与 ${} 在 MyBatis 中的区别

UserMapper#selectByUserId方法的 SQL 语句,我们使用#{userId, jdbcType=INTEGER}设置参数,#{} 表示一个占位符,通过 #{} 可以实现向 PreparedStatement 中的占位符设置参数,并自动进行 Java 类型与 JDBC 类型的转换,可以有效的防止 SQL 注入。使用 #{} 设置 SQL 语句参数等价于 JDBC 编程中的如下代码:

java 复制代码
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "123456");

String sql = "select user_id, name, age, gender, id_type, id_number from user where user_id = ?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, 2);

除了使用 #{} 来设置参数外,还可以使用 {} 设置参数,**{} 表示将字符串拼接到 SQL 语句中,且不会进行 Java 类型与 JDBC 类型的转换,使用 ${} 会导致 SQL 注入的风险大大增加**,因此通常会推荐使用 #{} 的方式来设置 SQL 语句的参数。

MyBatis 的参数设置

通常我们在 MyBatis 中使用的参数时,只会使用到 jdbcType 来设置 JDBC 类型,实际上 MyBatis 还提供了一些其它的设置选项。

指定参数的 Java 类型

xml 复制代码
#{userId, jdbcType=INTEGER, javaType=int}

指定参数的类型处理器

xml 复制代码
#{userId, typeHandler=com.wyz.customize.handler.type.NewIntegerHandler}

指定浮点类型参数的精度

xml 复制代码
#{score, jdbcType=DOUBLE, numericScale=2}

除了以上的参数设置外,MyBatis 中还提供了诸如 mode,resultMap,jdbcTypeName 等设置选项,只不过在大部分时候,我们只需要使用最基础的 jdbcType 设置即可(甚至 jdbcType 都可以不用设置)。

insert 元素

insert 元素用于声明插入语句,它定义了 11 个属性,其中大部分我们都在 select 元素的属性中见到过,并且相同属性的用法一致,我们一起来看下这 11 个属性:

属性 说明
useGeneratedKeys 使用 JDBC 中的Statement#getGeneratedKeys生成数据库的主键,如:MySQL 的自增主键,默认值:false
keyProperty 与 useGeneratedKeys 配合使用,指定生成的主键在 Java 对象中的字段,如果含有多列(联合主键),使用英文逗号间隔
keyColumn 与 useGeneratedKeys 配合使用,指定生成的主键在数据库表中的字段名称,如果含有多列(联合主键),使用英文逗号分隔
id 与 select 元素中的用法相同
parameterType 与 select 元素中的用法相同
timeout 与 select 元素中的用法相同
flushCache 与 select 元素中的用法相同
statementType 与 select 元素中的用法相同
databaseId 与 select 元素中的用法相同
lang 与 select 元素中的用法相同
parameterMap 与 select 元素中的用法相同

下面我们写一个使用 insert 元素的示例。

首先,在 UserMapper 接口中定义一个插入用户的方法:

java 复制代码
int insert(UserDO userDO);

接着,在 UserMapper.xml 中写方法映射的 SQL 语句:

xml 复制代码
<insert id="insert" parameterType="com.wyz.entity.UserDO">
  insert into user(user_id, name, age, gender, id_type, id_number)
  values (#{userId, jdbcType=INTEGER}, #{name, jdbcType=VARCHAR}, #{age, jdbcType=INTEGER}, #{gender, jdbcType=VARCHAR}, #{idType, jdbcType=INTEGER}, #{idNumber, jdbcType=VARCHAR})
</insert>

最后,添加一个测试方法:

java 复制代码
@Test
public void testInsert() {
  SqlSession sqlSession = sqlSessionFactory.openSession();
  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

  UserDO user = new UserDO(3, "小王", 18, "M", 1, "11011990778795X");
  userMapper.insert(user);
  sqlSession.commit();
  sqlSession.close();
}

通过测试可以看到,数据可以被成功的插入到 user 表中。

使用 useGeneratedKeys 属性与 selectKey 元素生成主键

下面我们使用 useGeneratedKeys 属性,并配合 insert 元素的子元素 selectKey 元素来生成主键。

假如,我们有一张表 user_sequence 用于记录 user 表的 id,每次新增 user 表数据时,获取 user_sequence 中最大的 user_id,并在此基础上加 1 作为新增数据的 user 表主键。

首先,我们在 UserMapper 接口定义方法:

java 复制代码
int insertUseCustomizeId(UserDO userDO);

接着,在 UserMapper.xml 中写方法映射的 SQL 语句:

xml 复制代码
<insert id="insertUseCustomizeId" parameterType="com.wyz.entity.UserDO" useGeneratedKeys="true" keyProperty="userId">
  <selectKey keyProperty="userId" resultType="Integer" order="BEFORE">
    select max(user_id) + 1 from user_sequence
  </selectKey>
  insert into user(user_id, name, age, gender, id_type, id_number)
  values (#{userId, jdbcType=INTEGER}, #{name, jdbcType=VARCHAR}, #{age, jdbcType=INTEGER}, #{gender, jdbcType=VARCHAR}, #{idType, jdbcType=INTEGER}, #{idNumber, jdbcType=VARCHAR})
</insert>

这段 SQL 语句中,将 useGeneratedKeys 设置为 true,并标记了主键为 UserDO 对象中的 userId 字段,最后我们使用 selectKey 元素通过 user_sequence 获取主键。需要注意的是,在写 insert 语句时我们依旧要在 SQL 语句中为 user_id 字段赋值,只不过在传入的 UserDO 对象中,不再需要为 UserDO 的 userId 字段赋值

Tips:不要忘了提前为 user_sequence 初始化数据。

最后,我们添加测试方法:

java 复制代码
@Test
public void insertUseCustomizeId() {
  SqlSession sqlSession = sqlSessionFactory.openSession();
  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

  UserDO user = new UserDO("小孙", 18, "M", 1, "11011990778795X");
  userMapper.insertUseCustomizeId(user);
  sqlSession.commit();
  sqlSession.close();
}

通过测试可以看到,即便我们没有主动的为 UserDO 对象的 userId 字段赋值,但是在我们观察数据库 user 表插入结果时也可以看到插入的数据中 user_id 字段已经被赋值了。

Tips:实际上,在生产应用的业务表中不会使用这种方式设置主键,常见的做法是使用单独的序列号生成系统或是序列号生成组件来完成发号动作;而对于与业务无关的配置表,主键往往不需要具备业务含义,并且配置表中数据相对较少,因此大部分场景下可以使用数据库提供的自增主键,同样也不需要使用 useGeneratedKeys 属性配合 selectKey 元素来生成主键。

update 元素

update 元素用于声明更新语句,它定义的属性无论是数量还是用法上都与 insert 元素的一致,因此这里就不再赘述了。

我们直接编写一个使用 update 元素的示例来展示其用法,如下:

xml 复制代码
<update id="update" parameterType="com.wyz.entity.UserDO">
  update user
  set name      = #{name, jdbcType=VARCHAR},
  age           = #{age, jdbcType=INTEGER},
  gender        = #{gender, jdbcType=VARCHAR},
  id_type       = #{idType, jdbcType=INTEGER},
  id_number     = #{idNumber, jdbcType=VARCHAR}
  where user_id = #{userId, jdbcType=INTEGER}
</update>

这里我就不带着大家一起写 UserMapper 接口中的方法和相应的测试案例了,大家可以自行实现并进行测试。

向映射器中传递多个参数

前面的例子中,无论是 insert 语句,还是 update 语句,我们都只传递了 Java 对象 UserDO 这一个参数,或者说是通过 UserDO 传递了多个参数,那么 MyBatis 中还可以使用其它的方式传递多个参数吗?

使用 Map 传递参数

最容易想到的是通过 Map 来传递多个参数,这与使用 UserDO 传递参数的方式是相似的,这里我们对之前 update 语句的示例做简单的修改来展示使用 Map 传递多个参数的方式。

首先,修改 update 语句中的 parameterType,如下:

xml 复制代码
<update id="update" parameterType="map">
  update user
  set name      = #{name, jdbcType=VARCHAR},
  age           = #{age, jdbcType=INTEGER},
  gender        = #{gender, jdbcType=VARCHAR},
  id_type       = #{idType, jdbcType=INTEGER},
  id_number     = #{idNumber, jdbcType=VARCHAR}
  where user_id = #{userId, jdbcType=INTEGER}
</update>

接着,修改 UserMapper 接口中方法的参数列表:

java 复制代码
int updateUseMap(Map<String, Object> userMap);

最后,修改测试案例:

java 复制代码
@Test
public void testUpdate() {
  SqlSession sqlSession = sqlSessionFactory.openSession();
  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

  Map<String, Object> userMap = new HashMap<>();
  userMap.put("userId", 1);
  userMap.put("name", "大王");
  userMap.put("age", "99999");
  userMap.put("gender", "X");
  userMap.put("idType", 3);
  userMap.put("idNumber", "999999999");

  userMapper.updateUseMap(userMap);

  sqlSession.commit();
  sqlSession.close();
}

通过测试,你可以看到我们对数据的修改已经被成功的更新到了数据库当中,证明使用 Map 传递多个参数是可行的。

Tips :有些小伙伴是跟着 MyBatis核心配置讲解(下)一步步配置过来的,在使用 Map 传递参数时需要将 mybatis-config.xml 中自定义的 ObjectWrapperFactory 注释掉,因为我们通过自定义 ObjectWrapperFactory 生成的自定义 ObjectWrapper 中并没有处理 Map 类型的参数。

虽然说,可以使用 Map 来传递多个参数,但我个人强烈建议不要使用 Map 来传递参数,原因有以下几点:

  1. Map 无法保证类型安全 ,为了满足不同参数的类型,你需要使用泛型类型为 Object 的 Map 对象,如:Map<String, Object>
  2. 代码可读性差,如果使用 Map 传递参数,为了得知 Map 里包含哪些参数,你可能需要将代码的上下文逻辑都捋一遍;
  3. 可维护性差,在为 Map 对象赋值时,需要设置大量的 Key,这些 key 都是应用程序中的硬编码。

相比于使用 Map 传递多个参数,我更推荐使用 Java 对象来传递多个参数

使用 @Param 注解传递参数

如果需要传递的参数较少,我们可以使用 @Param 注解将参数添加到接口方法的参数列表中。

假如说我们有一个需求,需要查询某个名字的男生和女生的数量,那么在设计查询方法时只需要两个参数即可,这时就可以借助 @Param 注解传递这两个参数。

UserMapper 接口中定义的方法如下:

java 复制代码
List<UserDO> selectByNameAndGender(@Param("name") String name, @Param("gender") String gender);

接着我们来写 UserMapper.xml 中的 SQL 语句:

xml 复制代码
<select id="selectByNameAndGender" resultType="com.wyz.entity.UserDO">
  select * from user 
  where name = #{name, jdbcType=VARCHAR} and gender = #{gender, jdbcType=VARCHAR}
</select>

到这里你可能没有看到 @Param 注解起到了什么样的作用,别着急,我们先往下看使用匿名参数的方式。

使用匿名参数

首先要说明,我个人强烈建议不要使用匿名参数,我想不到任何使用这种方式的理由。这里写它也只是为了与使用 @Param 注解的方式做一个对比,其次是解释下在实现根据 user_id 查询用户时为什么没有使用 @Param 注解。

使用匿名参数与使用注解基本上是一样的,只需要删除接口方法中的注解,并稍微修改 UserMapper.xml 中参数的名称即可,如下:

java 复制代码
<select id="selectByNameAndGender" resultType="com.wyz.entity.UserDO">
  select * from user
  where name = #{param1, jdbcType=VARCHAR} and gender = #{param2, jdbcType=VARCHAR} 
</select>

可以看到我在 SQL 语句中使用到 name 参数和 gender 参数时不再是使用参数的名称,而是 param1,param2 这类以方法中参数列表顺序命名的参数名称,这是因为在使用匿名参数时,MyBatis 无法识别方法中参数列表中的参数名称,只能够根据参数列表的顺序使用它们。

那么你可能会问到,为什么UserMapper#selectByUserId方法对应的 SQL 语句中可以使用参数名称 userId 呢?

这是因为UserMapper#selectByUserId方法只有一个参数,而且实际上 MyBatis 也没有识别到参数名称 userId,只不过是在这里使用了参数列表中的第一个参数,而恰好这个方法只有一个参数,因此不会有任何歧义,不信的话你可以将 SQL 语句中的 userId 修改成任何合法的名称试一试,比如:abc。

关于参数传递的总结

这里做一个简单的总结,上面我们总共提到了 4 种传递多个参数的方式:

  1. 使用 Java 对象
  2. 使用 @Param 注解
  3. 使用 Map 对象
  4. 使用匿名参数

这 4 种方式中只推荐使用 Java 对象和使用 @Param 注解这两种方式 ,剩余的两种方式建议直接禁止使用,并写进代码规范中。至于什么情况使用 Java 对象,什么情况使用 @Param 注解,我个人的习惯是,当参数个数小于等于 3 个时,使用 @Param 注解将所有参数写到方法的参数列表中,其余情况可以直接封装成 Java 对象来传递参数,除此之外,我个人还有个习惯,就是无论参数列表中有几个参数,我都会使用 @Param 定义其在映射器中使用的名称

除此之外,MyBatis 还可以使用 List,Set 等集合类型来传递参数,这点我会在实现动态 SQL 的文章中和大家分享使用的方法。

delete 元素

delete 元素用于声明删除语句,它只定义了 8 个属性:id 属性,parameterMap 属性,parameterType 属性,timeout 属性,flushCache 属性,statementType 属性,databaseId 属性和 lang 属性。这些属性都已经在上面分享其它元素的用法时出现过了,而且用法也一致,因此我就不再多说了。

我们直接来写一个通过 userId 删除用户的示例,如下:

xml 复制代码
<delete id="deleteByUserId" parameterType="integer">
  delete from user
  where user_id = #{userId, jdbcType=INTEGER}
</delete>

在实际的生产应用中,使用 delete 元素进行物理删除的场景比较少,大部分都是通过数据状态的变更来实现逻辑上删除。

sql 元素

sql 元素用于声明可重复使用的 SQL 语句片段,它定义了 3 个属性:id 属性,databaseId 属性和 lang 属性,这些我们也都已经见到过了,就不过多赘述了。

如果你使用 MyBatis Generator 这类工具生成 MyBaits 的映射器文件,相信你一定会见到过类似的代码:

xml 复制代码
<sql id="Base_Column_List">
  user_id, name, age, gender, id_type, id_number,
</sql>

以上就是 MyBatis Generator 工具为我们生成的 SQL 代码片段,我们可以直接在 SQL 语句中使用它们。

例如,我们修改一下查询全部用户的 SQL 语句,使用 Base_Column_List 来代替在 SQL 语句中的字段,UserMapper.xml 中的代码如下:

xml 复制代码
<select id="selectAll" resultType="com.wyz.entity.UserDO" databaseId="mysql">
  select <include refid="Base_Column_List" /> from user
</select>

上面的代码中,我们使用了元素 include 来引入提前定义好的 SQL 语句片段,同样的,我们也可以在 sql 元素中使用 include 元素引入其它的 SQL 语句片段。

首先,我们修改一下 user 表,为其添加一些审计字段:

sql 复制代码
alter table user add insert_time datetime null;
alter table user add update_time datetime null;

Tips:别忘了为 Java 对象 UserDO 添加这两个审计字段,以及对表中的数据做一个简单的初始化。

接着,我们在 UserMapper.xml 中定义两个 SQL 语句片段,第一个是包含 user 表中业务字段的 SQL 语句片段,第二个是包含 user 表所有字段的 SQL 语句片段:

xml 复制代码
<sql id="business_column" lang="mysql">
  user_id, name, age, gender, id_type, id_number
</sql>

<sql id="all_column" lang="mysql">
  <include refid="business_column"/>, insert_time, update_time
</sql>

可以看到,在 SQL 语句片段 all_column 中,我们通过 include 元素引入了 SQL 语句片段 business_column。

sql 元素也提供了动态设置的能力,我们修改下 SQL 语句片段 business_column,使用 ${} 为其添加一个动态字段:

xml 复制代码
<sql id="business_column" lang="mysql">
  user_id, name, age, gender, id_type, id_number, ${dynamic_column}
</sql>

接着,我们在查询 user 表全部用户的 SQL 语句中使用修改后的 SQL 语句片段 business_column,如下:

xml 复制代码
<select id="selectAll" resultType="com.wyz.entity.UserDO">
  select
  <include refid="business_column">
    <property name="dynamic_column" value="insert_time"/>
  </include>
  from user
</select>

可以看到,通过 include 元素的子元素 property 元素替换了 SQL 语句片段 business_column 中的动态字段,当然这个动态参数也可以通过接口方法中的参数列表传入。

例如,我们定义一个使用动态字段的查询全部用户的接口,UserMapper 接口中方法定义如下:

java 复制代码
List<UserDO> selectAllUseDynamicColumn(@Param("dynamicColumn") String dynamicColumn);

接着,我们来写 UserMapper.xml 中的 SQL 语句,如下:

xml 复制代码
<select id="selectAllUseDynamicColumn" resultType="com.wyz.entity.UserDO">
  select
  <include refid="business_column">
    <property name="dynamic_column" value="${dynamicColumn}"/>
  </include>
  from user
</select>

Tips:注意,我这里使用的是 ${} 来拼接参数,而不是 #{},这是因为 #{} 会进行 JDBC 类型的转换,而 ${} 仅仅是拼接。

最后,我们来写测试代码:

java 复制代码
@Test
  public void selectAllUseDynamicColumn() {
  SqlSession sqlSession = sqlSessionFactory.openSession();
  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

  List<UserDO> users = userMapper.selectAllUseDynamicColumn("insert_time");

  sqlSession.close();
}

通过测试,我们可以看到查询结果中已经获取到了 insert_time 字段的数据了。


好了,今天的内容就到这里了,如果本文对你有帮助的话,希望多多点赞支持,如果文章中出现任何错误,还请批评指正。最后欢迎大家关注分享硬核 Java 技术的金融摸鱼侠 王有志,我们下次再见!

相关推荐
q567315238 分钟前
通过scrapy和Django登录、爬取和持久化数据
java·开发语言·数据库·scrapy·django
IT大玩客13 分钟前
SpringBoot如何集成WebSocket
spring boot·后端·websocket
ModelBulider13 分钟前
九、HttpMessageConverter
java·开发语言·后端·spring·springmvc
晨曦_子画14 分钟前
使用 Regex 在 Java 中使用 Logstash LogBack 屏蔽日志
java
就叫飞六吧21 分钟前
电商系统表的1-n如何设计?情景分析
java·后端·spring
亥时科技24 分钟前
政企学习考试系统(源码+文档+部署+讲解)
java·数据库·开源·源代码管理
涔溪28 分钟前
云原生后端深度解析
后端·云原生
祁思妙想28 分钟前
《JavaEE进阶》----21.<基于Spring图书管理系统②(图书列表+删除图书+更改图书)>
java·后端·spring
祁思妙想30 分钟前
《JavaEE进阶》----20.<基于Spring图书管理系统①(登录+添加图书)>
java·spring·java-ee
喝旺仔la32 分钟前
异步提交Django
后端·python·django