赞
踩
MyBatis 中的动态 SQL 就是SQL语句可以根据不同的情况情况来拼接不同的sql。
本文会介绍 xml 和 注解 两种方式的动态SQL实现方式。
先创建一个数据表,SQL代码如下:
- DROP TABLE IF EXISTS `userinfo`;
- CREATE TABLE `userinfo` (
- `id` int(11) NULL DEFAULT NULL,
- `username` varchar(127) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
- `gender` tinyint(4) NULL DEFAULT NULL COMMENT '1-男 2-⼥ ',
- `delete_flag` tinyint(4) NULL DEFAULT 0 COMMENT '0-正常, 1-删除',
- `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP,
- `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP
- ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-
- SET FOREIGN_KEY_CHECKS = 1;
数据库表和JAVA对象的对应如下:
平时在注册账号时会有一些非必填项,而我们就可以使用 <if> 标签来跟据条件进行动态的SQL语句的添加。
接口定义:
- @Mapper
- public interface Userinfo {
- Integer addUserinfo(User user);
- }
语法:
<if test = "条件"> 语句块 </if>
如果 test 后面的条件判断结果为 true,那么就将后面的语句块拼接到最终的 SQL 语句中。
XML的实现代码如下:
- <insert id="addUserinfo">
- insert into userinfo(id, username,
- <if test="gender != null">
- gender,
- </if>
- <if test="deleteFlag != null">
- delete_flag
- </if>
- ) values (
- #{id},#{username},
- <if test="gender != null">
- #{gender},
- </if>
- <if test="deleteFlag != null">
- #{deleteFlag}
- </if>
- );
- </insert>

注意:test中的gender和deleteFlag,是传入对象中的属性,不是数据库字段。
执行以下测试代码:
- @Test
- void addUserinfo() {
- User user = new User();
- user.setId(2);
- user.setUsername("zhangsan");
- user.setDeleteFlag(0);
- //此时gender为空
- userinfo.addUserinfo(user);
- }
运行之后我们从日志中可以看出最终执行的SQL语句中并没有 gender
而当我们令gender不为空:
user.setGender(1);
但是此时我们的代码还有一个隐藏BUG,比如当deleteFlag为空时:
- @Test
- void addUserinfo() {
- User user = new User();
- user.setId(2);
- user.setUsername("zhangsan");
- //user.setDeleteFlag(0);
- user.setGender(1);
- //此时deleteFlag为空
- userinfo.addUserinfo(user);
- }
此时代码报错了,我们可以从MyBatis打印的日志中看出SQL语句出现了多余的逗号。
此时就需要使用<trim>标签
<trim>标签中有如下属性:
我们利用<trim>标签来将上述SQL中结尾的 ‘,’ 去除
- <insert id="addUserinfo">
- insert into userinfo
- <trim prefix="(" suffix=")" suffixOverrides=",">
- id, username,
- <if test="gender != null">
- gender,
- </if>
- <if test="deleteFlag != null">
- delete_flag
- </if>
- </trim>
- values
- <trim prefix="(" suffix=");" suffixOverrides=",">
- #{id},#{username},
- <if test="gender != null">
- #{gender},
- </if>
- <if test="deleteFlag != null">
- #{deleteFlag}
- </if>
- </trim>
- </insert>

此时程序就可以正常执行了。
<where>标签一般应用于需要动态组装where条件的地方。
<where> 只会在子元素有内容的情况下才插入where子句,而且会自动去除子句的开头的AND或
OR。
例如:我们此时根据 id 和 gender 来查找数据。
数据库中的数据如下:
接口定义:
User selectUser(Integer id, Integer gender);
xml实现:
- <select id="selectUser" resultType="com.example.Spring_demo.mySQL.User">
- select * from userinfo
- <where>
- <if test="id != null">
- id=#{id}
- </if>
-
- <if test="gender != null">
- and gender=#{gender}
- </if>
-
- </where>
- ;
- </select>
JAVA测试代码
- @Test
- void selectUser() {
- System.out.println(userinfo.selectUser(1, 1));
- }
从打印的结果和日志中我们可以看出结果正确。
如果 id 和 gender 都为 null
- @Test
- void selectUser() {
- System.out.println(userinfo.selectUser(null, null));
- }
虽然程序报错了,可是并不是因为SQL错了而是因为接收的参数报错。
此时可以看出 where 被去掉了。
此时如果 gender 为空
- @Test
- void selectUser() {
- System.out.println(userinfo.selectUser(1, null));
- }
<where>标签并不能去除句末的 and
<set>标签用于动态更新数据
用于 update 语句中动态的在SQL语句中插入 set 关键字,并会删掉额外的逗号。
例如:根据传入的id属性,修改 username 和 gender 中不为null的属性。
接口定义:
Integer upData(Integer id, String username, Integer gender);
xml代码实现:
- <update id="upData">
- update userinfo
- <set>
- <if test="username != null">
- username = #{username},
- </if>
- <if test="gender != null">
- gender = #{gender}
- </if>
- </set>
- where id = #{id};
- </update>
JAVA测试代码
- void upData() {
- //gender为空
- userinfo.upData(2, "xiaohong", null);
- }
可以看出删掉了额外的逗号(前后都会删掉)。
该标签可以在对集合进行遍历时使用。
标签有如下属性:
例如:批量删除数据
接口定义:
Integer deleteUsers(List<Integer> ids);
xml代码实现:
- <delete id="deleteUsers">
- delete from userinfo where id in
- <foreach collection="ids" item="id" open="(" close=");" separator=",">
- #{id}
- </foreach>
- </delete>
注意:这两个地方的名称必须相同。
JAVA测试代码
- @Test
- void deleteUsers() {
- List<Integer> list = new ArrayList<>();
- list.add(1);
- list.add(2);
- userinfo.deleteUsers(list);
- }
这两个标签配合使用可以实现对重复的代码片段进行抽取,将其通过 <sql> 标签封装到一个SQL片段,然后再通过<include> 标签进行引用。用来降低代码的冗余度。
例如:我们可以抽取下面xml中的部分代码。
- <delete id="deleteUsers">
- delete from userinfo where id in
- <foreach collection="ids" item="id" open="(" close=");" separator=",">
- #{id}
- </foreach>
- </delete>
- <sql id="aaa">
- delete from userinfo where id in
- </sql>
-
- <delete id="deleteUsers">
- <include refid="aaa"></include>
- <foreach collection="ids" item="id" open="(" close=");" separator=",">
- #{id}
- </foreach>
- </delete>
JAVA测试代码
- @Test
- void deleteUsers() {
- List<Integer> list = new ArrayList<>();
- list.add(1);
- list.add(2);
- userinfo.deleteUsers(list);
- }
注解的实现其实非常简单只需把xml标签中的SQL(包括标签),使用<script></script> 标签括起来就可以了。
例如下面的xml代码
- <insert id="insertUserByCondition">
- INSERT INTO userinfo (
- username,
- `password`,
- age,
- <if test="gender != null">
- gender,
- </if>
- phone)
- VALUES (
- #{username},
- #{age},
- <if test="gender != null">
- #{gender},
- </if>
- #{phone})
- </insert>

注解的实现方法:
- @Insert("<script>" +
- "INSERT INTO userinfo (username,`password`,age," +
- "<if test='gender!=null'>gender,</if>" +
- "phone)" +
- "VALUES(#{username},#{age}," +
- "<if test='gender!=null'>#{gender},</if>" +
- "#{phone})"+
- "</script>")
- Integer insertUserByCondition(UserInfo userInfo);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。