- , 9 9月 2021
- 作者 847954981@qq.com
- 后端学习, 我的编程之路
MyBatis基础2(XML)
XML模式开发顺序:
- 创建DO对象
- 创建DAO对象,配置@Mapper注解
- 创建XML文件,并完成resultMap配置
- 创建对应的XML语句
在MyBatis中使用XML首先需要在 application.properties 文件中添加配置。
代码语言:javascript复制mybatis.mapper-locations=classpath:com/youkeda/dao/*.xml,classpath:com/youkeda/comment/dao/*.xml
一般来说这个路径和DAO的包路径一致,一个DAO类对应一个XML文件
代码语言:javascript复制<?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.youkeda.comment.dao.UserDAO">
</mapper>
XML在写入头信息后需要继续添加mapper节点,节点存在 namespace 属性表示命名空间,一般这里所对应的DAO的全称。
resultMap
resultMap用于处理表和DO对象的属性映射,确保表中的每一个字段都有属性可以匹配
代码语言:javascript复制<mapper namespace="com.youkeda.comment.dao.UserDAO">
<resultMap id="userResultMap" type="com.youkeda.comment.dataobject.UserDO">
<id column="id" property="id"/>
<result column="user_name" property="userName"/>
</resultMap>
</mapper>
resultMap中的属性如下:
- id 唯一标识,一般命名为 xxxResultMap
- type 对应的DO类完整路径
resultMap的子节点:
- id 设置数据库主键字段信息,column属性对应的是表的字段名,property对应的是DO属性名称
- result 设置数据库其他字段信息,column属性对应的是表的字段名,property对应的是DO属性名称
resultMap也存在子节点 <association> 用于聚合其他对象:
代码语言:javascript复制 <association property="author" javaType="com.youkeda.comment.model.User">
<id column="user_id" property="id"/>
<result column="user_name" property="userName"></result>
<result column="nick_name" property="nickName"></result>
<result column="avatar" property="avatar"></result>
</association>
其中 javaType 表示对应是数据模型,property 对应的是表中字段名
XML实现Insert功能
代码语言:javascript复制<insert id="add" parameterType="com.youkeda.comment.dataobject.UserDO" >
INSERT INTO user (user_name, pwd, nick_name,avatar,gmt_created,gmt_modified)
VALUES(#{userName}, #{pwd}, #{nickName}, #{avatar},now(),now())
</insert>
属性:
- id 同DAO类的方法名,同一个xml内是要唯一的。
- parameterType 用于传递参数类型,一般是和DAO内对应方法的参数类型一致
- 以上两个属性也适用于 update、delete、select 语句中
如之前的DAO内写入Insert方法,XML也可以修改主键设置
代码语言:javascript复制<insert id="add" parameterType="com.youkeda.comment.dataobject.UserDO" useGeneratedKeys="true" keyProperty="id">
与DAO内 @Options 注解效果相同
Update/Delete语句同理
代码语言:javascript复制<update id="update" parameterType="com.youkeda.comment.dataobject.UserDO">
update user set nick_name=#{nickName},gmt_modified=now() where id=#{id}
</update>
代码语言:javascript复制 <delete id="delete">
delete from user where id=#{id}
</delete>
需要注意的是,因为我们在写删除语句的DAO时,语句为
代码语言:javascript复制int delete(@Param("id") long id);
@Param传入的参数(详见注解整理)是普通参数,默认情况下这类数据会被当做 Map 类型传入,而parameterType默认的类型就是 Map 因此这里可以把类型指定省略。
Select语句
select语句由于是获取数据,与上面几个语句不同,所以语法也不同
代码语言:javascript复制<select id="findByUserName" resultMap="userResultMap">
select * from user where user_name=#{userName} limit 1
</select>
这里使用了 resultMap 属性,它的值一般为XML文件下 resultMap 节点的id值,可以将获取的数据通过 resultMap 节点集体映射。
if语句
XML模式是支持添加if语句的如:
代码语言:javascript复制<update id="update" parameterType="com.youkeda.comment.dataobject.UserDO">
update user set
<if test="nickName != null">
nick_name=#{nickName},gmt_modified=now()
</if>
where id=#{id}
</update>
其中 if 存在属性 test 表明 if 的条件
set语句
在实际使用if语句中,可能会产生由于条件不满足而导致SQL语句错误,我们一般配合 set标签来完成 update
代码语言:javascript复制<update id="update" parameterType="com.youkeda.comment.dataobject.UserDO">
update user
<set>
<if test="nickName != null">
nick_name=#{nickName},
</if>
<if test="avatar != null">
avatar=#{avatar},
</if>
gmt_modified=now()
</set>
where id=#{id}
</update>
这里通过 set 标签代替了SQL语句中的set ,但注意的是其中的逗号不能漏掉,且使用 <set> 系统会自动去除最后一个逗号,而不用担心哪一列才是最后一个。
if select
先看例子
代码语言:javascript复制<select id="search" resultMap="userResultMap">
select * from user where
<if test="keyWord != null">
user_name like CONCAT('%',#{keyWord},'%')
or nick_name like CONCAT('%',#{keyWord},'%')
</if>
<if test="time != null">
and gmt_created <![CDATA[ >= ]]> #{time}
</if>
</select>
这里 >=、<、<=、>、&、| 这类表达式会导致MyBatis解析失败,所以我们需要使用 <![CDATA[ key ]]> 来包裹
类似于 Insert中的 set 可以用 <set> 语句代替,select中的 where 也可以用 <where> 语句代替
代码语言:javascript复制 <where>
<if test="keyWord != null">
user_name like CONCAT('%',#{keyWord},'%')
or nick_name like CONCAT('%',#{keyWord},'%')
</if>
<if test="time != null">
and gmt_created <![CDATA[ >= ]]> #{time}
</if>
</where>
循环语句
XML存在循环语句 <foreach>
代码语言:javascript复制<insert id="batchAdd" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (user_name, pwd, nick_name,avatar,gmt_created,gmt_modified)
VALUES
<foreach collection="list" item="it" index="index" separator =",">
(#{it.userName}, #{it.pwd}, #{it.nickName}, #{it.avatar},now(),now())
</foreach >
</insert>
属性:
- collection 指定集合的上下文参数名称,比如这里的list 对应 @Param(“list”)
- item 指定遍历中每一个数据的变量的指代名,一边用it命名
- index 集合的索引值名称指定
- separator 遍历每条记录并添加分隔符
- open 表示节点开始时的分隔符即所有数据前面的符号
- close 表示节点结束时的分隔符即所有数据之后的符号
上面代码结果为:
代码语言:javascript复制INSERT INTO user (user_name, pwd, nick_name,avatar,gmt_created,gmt_modified)
VALUES
(?, ?, ?,?,now(),now()),
(?, ?, ?,?,now(),now()),
(?, ?, ?,?,now(),now())
MyBatis会自动优化最后一个逗号,确保SQL正确。
添加上open和close:
代码语言:javascript复制<select id="findByIds" resultMap="userResultMap">
select * from user
<where>
id in
<foreach item="item" index="index" collection="ids"
open="(" separator="," close=")">
#{item}
</foreach>
</where>
</select>
其结果为:
代码语言:javascript复制select * from user where id in (?,?,?)
配置优化
当数据JSON输出时,会存在null数据,我们需要忽略它来节约流量,通过修改配置文件 application.properties 来完成
代码语言:javascript复制spring.jackson.deserialization.fail-on-unknown-properties=false
spring.jackson.default-property-inclusion=non_null
两个配置的作用是:
- 允许序列化未知字段,可以兼容Java模型和JSON数据不一致的情况
- 忽略null字段