Mybatis的Mapper映射文件中常用标签及作用
一、常用标签
在 MyBatis 中,Mapper 文件主要用于定义 SQL 查询以及映射查询结果到 Java 对象上。下面是一些常用的标签及其作用:
<mapper>- 这是根元素,用于命名空间的定义,通常需要指定namespace属性,该属性值通常是 Mapper 接口的全限定名。<select>- 定义查询语句,使用该标签可以编写 SQL 查询,并且指定返回的结果类型(使用resultType属性)。<insert>- 用于插入数据,定义插入语句,并且可以通过<selectKey>子标签来处理主键的自动填充。<update>- 更新语句,定义更新数据的 SQL。<delete>- 删除语句,定义删除数据的 SQL。<resultMap>- 用于复杂的结果集映射,可以用来描述如何将 SQL 执行结果映射为 Java 对象。<parameter>- 虽然不是顶级标签,但在<select>,<insert>,<update>,<delete>标签内可以定义参数类型,指定parameterType属性来告诉 MyBatis 如何处理传入的参数。<include>- 用来引用 SQL 片段,允许重用 SQL 代码。<sql>- 定义可重用的 SQL 代码片段。<choose>,<when>,<otherwise>- 用于动态 SQL 处理,可以根据条件选择不同的 SQL 代码块。<if>- 同样是用于动态 SQL,根据条件判断是否包含特定的 SQL 代码。<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 对象的哪些属性。
示例:一对多关系
假设我们有两个实体类:User 和 Order,其中 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> 中定义的子查询来加载每个 User 的 Order 列表。
此外 <resultMap> 标签还可以对java中的实体进行一一对应的关系,如果业务中遇到数据库字段与实体的属性名不一致的情况,也可以使用该标签进行对应,省去了在sql语句中取别名的操作