MyBatis的xml对于开发者的意义
mybatis相较于hibernate的区别在于myabtis是一种半自动的映射sql框架,所以我们不可避免都需要写一些xml,从而达到我们开发业务的水平,那么本篇博客就总结一下常用的xml各类元素。
核心元素
首先就是我们常用的增删改查操作的四个元素
-
<select>
:数据库查询
可以输入输出根据下面的属性来制定, 关键属性如下:id
:标识符,用于映射到Mapper接口方法。resultType
:定义返回对象的类型。parameterType
:定义输入参数的类型。resultMap
:定义结果映射的映射器,用于复杂类型的映射。
实例:
<select id="selectUser" parameterType="int" resultType="com.example.User"> SELECT * FROM users WHERE id = #{id} </select>
-
<insert>
:插入
可以进行批量插入,最后返回插入行的ID, 关键属性:id
:映射到Mapper接口方法的标识符。parameterType
:输入参数的类型。useGeneratedKeys
:是否使用数据库自动生成的主键。keyProperty
:指定自动生成的主键应该映射到的Java对象属性。
示例:
```xml <insert id="insertUser" parameterType="com.example.User"> INSERT INTO users (name, email) VALUES (#{name}, #{email}) </insert> ```
-
<update>
:更新
最后返回更新条数,关键属性:id
:映射到Mapper接口方法的标识符。parameterType
:输入参数的类型。
示例:
<update id="updateUser" parameterType="com.example.User"> UPDATE users SET name = #{name}, email = #{email} WHERE id = #{id} </update>
-
<delete>
:删除 返回删除的条数,关键属性:id
:映射到Mapper接口方法的标识符。parameterType
:输入参数的类型。
示例:
<delete id="deleteUser" parameterType="int"> DELETE FROM users WHERE id = #{id} </delete>
当然如果有一些代码是可以复用的,我们可以使用下面两个元素将它们抽离出来
-
<sql>
:用于定义可重用的SQL代码片段。 -
<include>
:如何使用此标签引入<sql>
片段。实例:
<sql id="userColumns"> username, email, status </sql> <select id="selectUsers" resultType="com.example.User"> SELECT <include refid="userColumns"/> FROM users </select>
xml与代码的映射关系
xml可以通过各种不同的元素与Mybatis进行结果的映射,提供了比如resultMap
、resultType
、parameterType
等元素,那么我们可以通过这些标签去自定义我们的映射关系
-
<parameterType>
:这个元素主要就是方便我们传入的时候指定元素,一般是我们的实体类或者是Map,当然我们如果不指定也能使用,相当于范式一样的规范,这里就不演示了 -
<resultType>
:这种情况一般是我们在外面定义好了实体,然后我们可以直接将这个实体加到标签上面,就可以实现映射<select id="selectAllUsers" resultType="com.example.User"> SELECT * FROM users </select>
-
<resultMap>
:它是MyBatis中最复杂也最强大的元素,当我们的字段与实体字段没有很好的映射时,resultMap
用于定义如何从数据库结果集中映射到Java对象。这个
resultMap
我们可以直接写到xml中,然后我们使用resultType
在引用它,例如<resultMap id="voMap" type="java.util.Map"> <id property="Id" column="Id"/> <result property="Name" column="Name"/> <result property="count" column="count"/> </resultMap> <select id="getVisitPage" resultType="voMap"> ... </select>
这里面column
对应的是数据库的列名或别名;property
对应的是结果集的字段或属性。
除了上面的实例之外,它还有别的用法,比如:我们有如下两个案例,一个是我们的元素要返回的对象中需要关联一个对象,另外一个需要关联集合,那么这个时候我们就需要使用如下的两个嵌套标签
association
嵌套对象
假设有两个实体类User
和UserProfile
,其中User
有一个UserProfile
的引用,对应于一对一关系。
-
User类:
public class User { private Long id; private String username; private UserProfile profile; // 与UserProfile的一对一关系 // getters and setters... }
-
UserProfile类:
public class UserProfile { private Long id; private String address; private String phone; // getters and setters... }
针对这种一对一关系,就可以在<resultMap>
中使用<association>
标签定义关联:
-
resultMap:
<resultMap id="userMap" type="User"> <id property="id" column="user_id"/> <result property="username" column="username"/> <association property="profile" javaType="UserProfile"> <id property="id" column="profile_id"/> <result property="address" column="address"/> <result property="phone" column="phone"/> </association> </resultMap>
collection
嵌套集合
假设User
类包含多个Order
对象的集合,对应于一对多关系。
-
User类 (扩展):
public class User { // ... 其他属性 ... private List<Order> orders; // 与Order的一对多关系 // getters and setters... }
-
Order类:
public class Order { private Long id; private String orderDetails; }
针对这种一对多关系,您可以在<resultMap>
中使用<collection>
标签定义关联:
-
resultMap:
<resultMap id="userMap" type="User"> <!-- User属性的映射 --> <collection property="orders" ofType="Order"> <id property="id" column="order_id"/> <result property="orderDetails" column="order_details"/> </collection> </resultMap>
动态sql
讲完上面的一些核心用法,那么下面我在讲讲如何利用一些动态sql提高我们的代码质量
<where>
和 <set>
这里可以自动帮我们处理AND或OR等,避免一些没用的sql语句,比如我们拼接sql的过程中搭配<if>标签使用的时候
<select id="findUsers" resultType="User">
SELECT * FROM users
<where>
<if test="username != null">
AND username = #{username}
</if>
</where>
</select>
<update id="updateUser">
UPDATE users
<set>
<if test="username != null">
username = #{username},
</if>
<if test="email != null">
email = #{email}
</if>
</set>
WHERE id = #{id}
</update>
使用这两元素之后我们就只管拼接sql就可以了,不需要担心出现where AND ...
从而报错的发生
<foreach>
- 集合处理
用途主要就是用于遍历集合,常用于构建动态的IN
查询。
示例:查询多个用户ID。
<select id="findUsersByIds" resultType="User">
SELECT * FROM users
WHERE id IN
<foreach item="id" collection="ids" open="(" separator="," close=")">
#{id}
</foreach>
</select>
<choose>
, <when>
, <otherwise>
这些元素一般组合使用,类似于Java中的switch
语句,用于在多个条件中选择一个执行,直接看下面实例
示例:根据不同的用户状态选择不同的查询条件。
<select id="findUserByStatus" resultType="User">
SELECT * FROM users
<where>
<choose>
<when test="status == 'active'">
AND status = 'active'
</when>
<when test="status == 'inactive'">
AND status = 'inactive'
</when>
<otherwise>
AND status = 'pending'
</otherwise>
</choose>
</where>
</select>
开发心得
最后是我在写xml中的一些技巧分享吧
-
能多使用提供的函数就尽量使用一些xml提供的函数,如:
在比较数字的时候可以使用函数将数字转化为
varchar
类型比较<if test="phone != '' and phone != null "> and u.phone = #{phone, jdbcType=VARCHAR} </if>
在使用模糊查询的时候,使用拼接函数对字段进行拼接
<if test="name != '' and name != null "> and u.name like CONCAT('%',#{name},'%') </if>
在判断集合为空的时候,使用函数判断
isEmpty()
集合是否为空<if test="map.userList != null and !map.userList.isEmpty()"> AND xro.user_id IN <foreach collection="map.userList" item="item" index="index" open="(" separator="," close=")"> #{item} </foreach> </if>
-
我们在入参的时候,我一般都会将实体类对象转化为map在进行传入,然后我会在代码层面将数据尽量处理好,比如:
Map<String, Object> map = new HashMap<>(); // new HashMap<>();// CollUtil.newHashMap(); if (StrUtil.isNotEmpty(request.getNikename())) { String nikeName = URLUtil.decode(request.getName()); map.put("name", nikeName); } if (ObjectUtil.isNotNull(request.getStatus())) { map.put("status", request.getStatus() ? 1 : 0); } dao.getList(map);
尽量减轻数据库压力,从而提高代码效率