MyBatis 面试题(五)

1. MyBatis 支持哪些传参数的方法?

MyBatis 提供了多种方式来传递参数到 SQL 语句中。以下是一些主要的参数传递方法:

  1. 单个参数
    当 SQL 语句只接受一个参数时,你可以直接在 mapper 接口的方法中定义一个参数,然后在 XML 映射文件中使用 #{参数名} 来引用它。
public interface UserMapper {
    User getUserById(int id);
}

<select id="getUserById" resultType="User">
    SELECT * FROM user WHERE id = #{id}
</select>
  1. 多个参数
    对于多个参数,MyBatis 提供了几种处理方式:

    • 使用 @Param 注解:在 mapper 接口的方法中,使用 @Param 注解为每个参数命名,然后在 XML 映射文件中使用这些名称来引用参数。
    java`public interface UserMapper {
        User getUserByNameAndAge(@Param("name") String name, @Param("age") int age);
    }`
    
    xml`<select id="getUserByNameAndAge" resultType="User">
        SELECT * FROM user WHERE name = #{name} AND age = #{age}
    </select>`
    
    • 使用 Map:你可以创建一个 Map 对象,将参数作为键值对放入 Map 中,然后在 XML 映射文件中通过键名来引用参数。
    • 使用 Java Bean 或 DTO:创建一个包含所有参数的 Java Bean 或 DTO,然后在 mapper 接口的方法中使用这个对象作为参数。
  2. List 或数组参数
    对于 List 或数组类型的参数,你可以在 mapper 接口的方法中定义 List 或数组类型的参数,然后在 XML 映射文件中使用 foreach 元素来处理这些集合。

public interface UserMapper {
    List<User> getUsersByIds(List<Integer> ids);
}

<select id="getUsersByIds" resultType="User">
    SELECT * FROM user WHERE id IN 
    <foreach item="id" index="index" collection="ids" open="(" separator="," close=")">
        #{id}
    </foreach>
</select>
  1. RowBounds
    MyBatis 还支持使用 RowBounds 对象来限制查询结果的数量和偏移量,这通常用于分页查询。

这些只是 MyBatis 中传递参数的一些常见方法,实际上,MyBatis 提供了非常灵活和强大的参数处理机制,可以根据具体的业务需求选择合适的方式。

2. MyBatis 的$和# 传参的区别?

MyBatis 中,#{}${} 都是用于参数传递的,但它们之间存在一些重要的区别。

  1. 预编译处理

    • #{}:MyBatis 会对使用 #{} 的参数进行预编译处理,形成 PreparedStatement。这样做的好处是可以防止 SQL 注入,因为预编译的 SQL 语句中的参数会被当作占位符处理,参数值不会和 SQL 语句的其他部分拼接在一起。
    • ${}:MyBatis 不会对使用 ${} 的参数进行预编译处理,而是直接将其替换为参数值。因此,如果参数值中包含 SQL 语句的片段或特殊字符,可能会导致 SQL 注入的风险。
  2. 类型处理

    • #{}:MyBatis 会根据参数的类型自动进行转换和处理,确保参数在 SQL 语句中的正确性。
    • ${}:需要手动确保参数值的正确性和类型匹配,因为 MyBatis 不会对其进行任何转换或处理。
  3. 动态 SQL

    • ${} 在某些场景下非常有用,比如在构建动态 SQL 时。由于它不会进行预编译处理,所以它可以用来动态地插入表名、列名等。但是,在使用 ${} 时需要格外小心,确保不会引入 SQL 注入的风险。
    • #{} 则更适用于普通的参数传递场景,因为它提供了安全的预编译处理。
  4. 使用场景

    • 在大多数情况下,推荐使用 #{} 来传递参数,因为它提供了更高的安全性。
    • 只有在确实需要动态构建 SQL,并且确信不会引入 SQL 注入风险的情况下,才应该使用 ${}

总的来说,#{}${} 在 MyBatis 中各有其用途,但在使用时需要注意它们之间的区别和潜在的风险。

3. MyBatis 可以映射到枚举类吗?

MyBatis 可以映射到枚举类。MyBatis 提供了对枚举类型的支持,允许你将数据库中的某些字段映射到 Java 的枚举类型。

在 MyBatis 中,你可以通过以下方式实现枚举类型的映射:

  1. 使用 @TypeHandler 注解
    你可以在枚举类上使用 @TypeHandler 注解,并指定一个实现了 TypeHandler 接口的类来处理枚举类型的转换。这个类需要实现 setNonNullParametergetNullableResult 方法,分别用于设置参数和获取结果。

例如:

@TypeHandler(MyEnumTypeHandler.class)
public enum MyEnum {
    VALUE1,
    VALUE2,
    // ... 其他枚举值
}

然后在你的 MyEnumTypeHandler 类中实现必要的转换逻辑。
2. 在 XML 映射文件中使用 typeHandler
如果你不想在枚举类上使用注解,你也可以在 XML 映射文件中为特定的参数或结果集列指定一个类型处理器。

例如:

<resultMap id="myResultMap" type="com.example.MyEntity">
    <result property="myEnumProperty" column="my_enum_column" typeHandler="com.example.MyEnumTypeHandler"/>
</resultMap>
  1. 使用 MyBatis 的内置枚举类型处理器
    MyBatis 提供了一个内置的枚举类型处理器 EnumTypeHandler,它可以根据枚举的名称或序列号进行转换。要使用它,你只需确保枚举类有一个与数据库列名相匹配的字段,并且这个字段要么是枚举的名称,要么是枚举的序列号。

例如,如果你的数据库列名是 status,并且你的枚举类有一个名为 status 的字段,那么 MyBatis 会自动使用 EnumTypeHandler 进行转换。
4. 自定义 SQL 映射
如果内置的枚举类型处理器不满足你的需求,你还可以自定义 SQL 映射,并在查询时手动处理枚举类型的转换。

无论你选择哪种方式,都需要确保枚举类型的转换逻辑与你的数据库列数据相匹配,以避免数据映射错误。

4. MyBatis 怎么封装动态 SQL?

MyBatis 提供了多种方式来封装动态 SQL,以适应不同的查询需求。以下是几种常见的动态 SQL 封装方法:

1. 使用 <if> 标签

<if> 标签可以根据条件来动态地包含或排除 SQL 片段。

<select id="findUsersByConditions" resultType="User">
  SELECT * FROM user
  WHERE 1 = 1
  <if test="name != null">
    AND name = #{name}
  </if>
  <if test="age != null">
    AND age = #{age}
  </if>
</select>

在上面的例子中,如果 name 不为 null,则会在 SQL 语句中包含 AND name = #{name} 片段;如果 age 不为 null,则会包含 AND age = #{age} 片段。

2. 使用 <choose>, <when>, <otherwise> 标签

这些标签提供了类似于 Java 中的 switch-case-default 结构,用于在多个条件中选择一个。

<select id="findUsersByType" resultType="User">
  SELECT * FROM user
  WHERE 1 = 1
  <choose>
    <when test="type == 'admin'">
      AND role = 'ADMIN'
    </when>
    <when test="type == 'user'">
      AND role = 'USER'
    </when>
    <otherwise>
      AND status = 'ACTIVE'
    </otherwise>
  </choose>
</select>
3. 使用 <trim>, <where>, <set> 标签

这些标签用于处理 SQL 语句中的前缀和后缀,以及更新语句中的 SET 子句。

  • <trim> 标签用于自定义 SQL 片段的前缀和后缀。
  • <where> 标签用于处理 WHERE 子句,它会自动处理前缀,并且只有在有动态条件的情况下才添加 WHERE 关键字。
  • <set> 标签用于更新语句,它会自动处理 SET 子句,并只在有动态字段的情况下才添加逗号。
<update id="updateUser" parameterType="User">
  UPDATE user
  <set>
    <if test="name != null">
      name = #{name},
    </if>
    <if test="age != null">
      age = #{age},
    </if>
  </set>
  WHERE id = #{id}
</update>
4. 使用 <foreach> 标签

<foreach> 标签用于遍历集合或数组,通常用于构建 IN 子句。

<select id="findUsersByIds" resultType="User">
  SELECT * FROM user
  WHERE id IN
  <foreach item="id" index="index" collection="ids" open="(" separator="," close=")">
    #{id}
  </foreach>
</select>

在上面的例子中,ids 是一个包含多个用户 ID 的集合,<foreach> 标签会遍历这个集合,并构建 IN 子句。

5. 使用 SQL 片段

使用 <sql> 标签可以定义可重用的 SQL 片段,并在需要的地方引用它。

<sql id="base_column_list">
  id, name, age, address
</sql>

<select id="selectUsers" resultType="User">
  SELECT
  <include refid="base_column_list" />
  FROM user
</select>

在上面的例子中,<sql> 标签定义了一个名为 base_column_list 的 SQL 片段,然后在 selectUsers 查询中通过 <include> 标签引用了这个片段。

通过这些方法,MyBatis 提供了灵活且强大的动态 SQL 功能,可以根据不同的条件和需求动态地构建 SQL 语句。

5. MyBatis trim 标签有什么用?

trim 标签在 MyBatis 中是一个非常有用的元素,它主要用于动态地生成 SQL 语句的片段。它允许你根据条件添加或移除 SQL 语句的前缀和后缀,以及中间的某些部分。这在处理动态 SQL 时非常有用,特别是当你想根据某些条件来包含或排除某些 SQL 语句片段时。

trim 标签有以下主要属性:

  • prefix:添加到 trimmed SQL 语句的前缀。
  • prefixOverrides:覆盖或移除 trimmed SQL 语句的前缀。这常常用于移除某些不必要的逗号或操作符。
  • suffix:添加到 trimmed SQL 语句的后缀。
  • suffixOverrides:覆盖或移除 trimmed SQL 语句的后缀。

例如,假设你有一个 SQL 语句,它基于某些条件动态地包含或排除某些列:

<select id="selectUsers" resultType="User">
  SELECT
  <trim prefix="WHERE" prefixOverrides="AND |OR ">
    <if test="id != null">
      id = #{id} AND
    </if>
    <if test="name != null">
      name = #{name} OR
    </if>
    <if test="email != null">
      email = #{email}
    </if>
  </trim>
  FROM user
</select>

在这个例子中,trim 标签用于处理 WHERE 子句的动态生成。prefix="WHERE" 表示生成的 SQL 语句片段将以 WHERE 开头。prefixOverrides="AND |OR " 表示如果生成的 SQL 语句片段以 ANDOR 开头,那么这些前缀将被移除。这样,你可以确保生成的 SQL 语句是正确和有效的。

如果 idname 都不为 null,那么生成的 SQL 语句片段将是 id = #{id} AND name = #{name}。由于这个片段以 AND 开头,并且 trim 标签的 prefixOverrides 属性设置为移除 ANDOR 前缀,所以最终的 SQL 语句将是 WHERE id = #{id} AND name = #{name}。同样地,如果只有 email 不为 null,那么生成的 SQL 语句将是 WHERE email = #{email}

6. MyBatis where 标签有什么用?

MyBatis 的 <where> 标签在动态 SQL 中非常有用,它主要用于处理 SQL 语句中的 WHERE 子句。当需要根据条件动态地构建 WHERE 子句时,<where> 标签可以自动处理 WHERE 关键字和条件之间的逻辑。

以下是 <where> 标签的一些主要特点和用途:

  1. 自动添加 WHERE 关键字:当 <where> 标签内部有至少一个条件成立时,MyBatis 会自动在生成的 SQL 语句前面添加 WHERE 关键字。这避免了手动编写条件判断来确保 WHERE 关键字的存在。

  2. 移除多余的前缀:如果 <where> 标签内的第一个条件不成立(即条件表达式的结果为 false),MyBatis 会智能地移除生成的 SQL 语句中多余的 ANDOR 前缀,从而确保 SQL 语句的语法正确性。

  3. 嵌套使用<where> 标签可以嵌套在其他动态 SQL 元素中,如 <if><choose> 等,以实现更复杂的动态 SQL 构建逻辑。

下面是一个使用 <where> 标签的示例:

<select id="findUsersByConditions" resultType="User">
  SELECT * FROM user
  <where>
    <if test="name != null">
      AND name = #{name}
    </if>
    <if test="age != null">
      AND age = #{age}
    </if>
    <if test="email != null">
      AND email = #{email}
    </if>
  </where>
</select>

在这个例子中,如果 nameageemail 都不为 null,生成的 SQL 语句将是:

SELECT * FROM user WHERE name = ? AND age = ? AND email = ?

如果只有 nameemail 不为 null,生成的 SQL 语句将是:

SELECT * FROM user WHERE name = ? AND email = ?

注意,在 <if> 标签内部的条件前面没有 WHERE 关键字,也没有多余的 AND 前缀。这是因为 <where> 标签会自动处理这些细节。

使用 <where> 标签可以大大简化动态 SQL 的编写,减少错误,并提高代码的可读性和可维护性。

7. MyBatis 是如何进行分页的?分页插件的原理是什么?

MyBatis 本身并不直接提供分页功能,但可以通过一些方法实现分页查询。常用的分页方法包括:使用 SQL 语句的 LIMIT 子句(适用于 MySQL、PostgreSQL 等支持 LIMIT 的数据库),或者使用 RowBounds 类进行分页(MyBatis 提供的分页方式,但性能较低)。

然而,对于大型应用来说,更常见的是使用分页插件来进行分页。这些插件通常是对 MyBatis 的核心功能进行扩展,以提供更高效、更灵活的分页解决方案。

分页插件的原理大致如下:

  1. 拦截 SQL 语句:分页插件通过 MyBatis 的插件机制,拦截到即将执行的 SQL 语句。
  2. 分析 SQL 语句:插件会分析拦截到的 SQL 语句,判断其是否需要进行分页。这通常是通过检查 SQL 语句是否包含特定的分页关键字或标记来实现的。
  3. 修改 SQL 语句:如果确定需要进行分页,插件会修改原始的 SQL 语句,添加分页相关的逻辑。这通常是在 SQL 语句的末尾添加 LIMIT 和 OFFSET 子句,或者根据数据库的特性使用其他分页方法。
  4. 执行分页查询:修改后的 SQL 语句会被发送给数据库执行,返回分页后的结果集。
  5. 处理结果集:插件会处理数据库返回的结果集,可能包括合并多个分页查询的结果,或者对结果进行特定的格式化或转换。
  6. 返回最终结果:最后,插件将处理后的结果集返回给 MyBatis,再由 MyBatis 返回给调用方。

通过这种方式,分页插件可以在不修改原始 SQL 语句和 MyBatis 配置的情况下,实现对任意 SQL 查询的分页功能。同时,由于分页逻辑是在数据库层面实现的,因此通常具有较高的性能和效率。

注意:不同的分页插件可能具有不同的实现方式和特性,因此在使用时需要根据具体插件的文档和说明进行配置和使用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

依邻依伴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值