Mybatis的Mapper映射文件中常用标签及作用

186 阅读5分钟

Mybatis的Mapper映射文件中常用标签及作用

一、常用标签

在 MyBatis 中,Mapper 文件主要用于定义 SQL 查询以及映射查询结果到 Java 对象上。下面是一些常用的标签及其作用:

  1. <mapper> - 这是根元素,用于命名空间的定义,通常需要指定 namespace 属性,该属性值通常是 Mapper 接口的全限定名。
  2. <select> - 定义查询语句,使用该标签可以编写 SQL 查询,并且指定返回的结果类型(使用 resultType 属性)。
  3. <insert> - 用于插入数据,定义插入语句,并且可以通过 <selectKey> 子标签来处理主键的自动填充。
  4. <update> - 更新语句,定义更新数据的 SQL。
  5. <delete> - 删除语句,定义删除数据的 SQL。
  6. <resultMap> - 用于复杂的结果集映射,可以用来描述如何将 SQL 执行结果映射为 Java 对象。
  7. <parameter> - 虽然不是顶级标签,但在 <select>, <insert>, <update>, <delete> 标签内可以定义参数类型,指定 parameterType 属性来告诉 MyBatis 如何处理传入的参数。
  8. <include> - 用来引用 SQL 片段,允许重用 SQL 代码。
  9. <sql> - 定义可重用的 SQL 代码片段。
  10. <choose>, <when>, <otherwise> - 用于动态 SQL 处理,可以根据条件选择不同的 SQL 代码块。
  11. <if> - 同样是用于动态 SQL,根据条件判断是否包含特定的 SQL 代码。
  12. <foreach> - 当需要对集合进行迭代时使用,如批量插入或构建 IN 条件等。

这些标签共同协作,使得 MyBatis 成为一个非常强大的框架,能够灵活地处理各种复杂的数据库操作场景。

二、具体例子

1. <insert>

普通写法与在注解中写法相似,建议使用MybatisX插件自动生成对应的标签,可以防止一些类型上的错误

<insert id="insertUser" parameterType="com.example.model.User">
    INSERT INTO users (name, email) VALUES (#{name}, #{email})
</insert>

这是普通插入的情况,还可以使用 <slectKey> 标签来回显主键,一般用于插入业务中一对N关系的俩表中,新增一条数据的同时需要插入多条关联数据,这时候需要将新增进数据库中数据的的主键进行回显,作为关联表插入的逻辑外键入参

<insert id="insertUser" parameterType="com.example.model.User">    
    <selectKey keyProperty="id" resultType="int" order="AFTER">        
         SELECT 0
    </selectKey>    
    INSERT INTO users (name, email) VALUES (#{name}, #{email}) 
</insert>

还有另外一种方式也可以进行主键回显,写法相对简单但是需要数据库主键是属于 AUTO_INCREMENT类型的

<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
  INSERT INTO users (username, email) VALUES (#{username}, #{email})
</insert>

同时 <insert> 还可以和 <foreach> 标签配合进行批量插入

假设刚刚插入用户表的同时需要往经历表中批量插入n条信息

mapper:

int batchInsertByEmpId(List<Expr> exprList);

对应xml:

<insert id="batchInsertByEmpId">
        insert into expr(emp_id,job,begin,end,company,create_time,update_time)
        values
	<foreach collection="exprList" item="expr"  index="index" open="(" close=")" separator=","  >
            (#{expr.empId},#{expr.job},#{expr.begin},#{expr.end},#{expr.company},#{expr.createTime},#{expr.updateTime})
    </foreach>
</insert>

注意collcetion中的值要与mapper中方法的入参保持一致,也可以用@param注解来绑定参数。

2.<select>

用于编写查询的语句

<select id="getUserById" parameterType="int" resultType="com.example.model.User">
    SELECT * FROM users WHERE id = #{id}
</select>

同时在编写分页查询的时候常常会与**<where><if>**标签配合,实现动态的查询。

 <select id="pageQuery" resultType="com.example.pojo.dto.queryEmpDTO">
        select e.* ,d.name as deptName from emp as e left join dept as d on e.dept_id = d.id
        <where>
            <if test="name != null">
                and e.name like concat('%',#{name},'%')
            </if>
            <if test="gender != null">
                and e.gender = #{gender}
            </if>
            <if test="begin != null and end != null">
                and e.entry_date between #{begin} and #{end}
            </if>
        </where>
        order by e.update_time desc
    </select>

!!注意!! 如果使用了PageHelper插件,order by 必须要放在<where>外,因为PageHelper会在最后自动拼上limit语句

同时也可以配合**<foreach>**进行批量查询,提升查询性能

<select id="findUsersByIds" parameterType="java.util.List" resultType="com.example.model.User">
    SELECT * FROM users WHERE id IN
    <foreach collection="list" item="id" open="(" close=")" separator=",">
        #{id}
    </foreach>
</select>
3.<update>

用于编写更新的语句

<update id="updateUser" parameterType="com.example.model.User">
    UPDATE users SET name=#{name}, email=#{email} WHERE id=#{id}
</update>

一般会配合 <set><if> 标签实现动态的更新

<update id="updateUser" parameterType="com.example.model.User">
    UPDATE users 
    <set>
        <if test="name != null and name != ''">
            name = #{name},
        </if>
        <if test="email != null and email != ''">
            email = #{email},
        </if>
    </set>
    WHERE id = #{id}
</update>
4.<delete>

用于编写删除语句的标签

<delete id="deleteUserById" parameterType="int">
    DELETE FROM users WHERE id=#{id}
</delete>
5.<sql><inclulde>

这是一对配合使用的标签,如果在业务中有一些字段需要频繁查询,可以使用这对标签减少重复代码的编写,也可以是xml文件中的语句看起来更加优雅

<sql id="commonColumns">id, name, email</sql>

<select id="findUsers" resultType="com.example.model.User">
    SELECT <include refid="commonColumns"/> FROM users
</select>
6.<resultMap>

<resultMap> 标签允许你自定义结果集映射到 Java 对象的方式。它可以处理一对一、一对多等复杂关系,也可以处理嵌套查询和嵌套结果。通过 <resultMap>,你可以明确地指出数据库中的哪些字段应该映射到 Java 对象的哪些属性。

示例:一对多关系

假设我们有两个实体类:UserOrder,其中 User 可以拥有多个 Order

1. 实体类定义
public class User {
    private Integer id;
    private String name;
    private String email;
    private List<Order> orders; // 用户拥有的订单列表

    // getters 和 setters
}

public class Order {
    private Integer orderId;
    private String orderName;
    private Integer userId; // 订单所属用户的 ID

    // getters 和 setters
}
2. Mapper 接口定义
public interface UserMapper {
    User findUserWithOrders(Integer userId);
}
3. XML 映射文件
<mapper namespace="com.example.mapper.UserMapper">

    <resultMap id="UserWithOrdersResultMap" type="com.example.model.User">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="email" column="email"/>
        <!-- 处理一对多关系 -->
        <collection property="orders" ofType="com.example.model.Order" select="findOrdersByUserId" column="id"/>
    </resultMap>
    <select id="findUserWithOrders" resultMap="UserWithOrdersResultMap">
        SELECT * FROM users WHERE id = #{userId}
    </select>

    <!-- 用于加载订单列表 -->
    <select id="findOrdersByUserId" resultType="com.example.model.Order">
        SELECT * FROM orders WHERE user_id = #{userId}
    </select>
</mapper>
解释

在这个例子中,我们定义了一个名为 UserWithOrdersResultMap<resultMap>,它包含了映射到 User 对象的基本属性 (id, name, email) 的 <id><result> 元素。

<collection> 元素用来处理一对多关系(一对一使用<association>标签)。property 属性指定了 Java 对象的属性名,ofType 指定了集合中元素的类型。select 属性指定了一个 SQL 语句的 ID,这个 SQL 语句负责加载相关的订单信息。column 属性指定了传递给子查询的列名,这里是 users 表的 id 列。

当我们调用 findUserWithOrders 方法时,MyBatis 会先执行主查询来获取 User 的信息,然后使用 <collection> 中定义的子查询来加载每个 UserOrder 列表。

此外 <resultMap> 标签还可以对java中的实体进行一一对应的关系,如果业务中遇到数据库字段与实体的属性名不一致的情况,也可以使用该标签进行对应,省去了在sql语句中取别名的操作