MyBatis 实现动态 SQL

 MyBatis 中的动态 SQL 就是SQL语句可以根据不同的情况情况来拼接不同的sql。

本文会介绍 xml注解 两种方式的动态SQL实现方式。

XML的实现方式

先创建一个数据表,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对象的对应如下:

 MyBatis 实现动态 SQL_第1张图片

平时在注册账号时会有一些非必填项,而我们就可以使用 标签来跟据条件进行动态的SQL语句的添加。

接口定义:

@Mapper
public interface Userinfo {
    Integer addUserinfo(User user);
}

标签

语法:

语句块

如果 test 后面的条件判断结果为 true,那么就将后面的语句块拼接到最终的 SQL 语句中。

XML的实现代码如下:


    insert into userinfo(id, username,
                
                    gender,
                
                
                    delete_flag
                
    ) values (
                #{id},#{username},
                
                  #{gender},
                
                
                    #{deleteFlag}
                
    );

注意: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);

MyBatis 实现动态 SQL_第2张图片

但是此时我们的代码还有一个隐藏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语句出现了多余的逗号。

此时就需要使用标签

标签

标签中有如下属性:

  • prefix:表示在整个语句块起始位置加上prefix的值作为前缀
  • suffix:表示在整个语句块结尾加上suffix的值作为后缀
  • prefixOverrides:如果整个语句块的前缀等于prefixOverrides的值,去掉prefixOverrides的值;
  • suffixOverrides:如果整个语句块的后缀等于suffixOverrides的值,去掉suffixOverrides的值。

我们利用标签来将上述SQL中结尾的 ‘,’ 去除


    insert into userinfo 
    
        id, username,
        
            gender,
        
        
            delete_flag
        
    
    values
        
        #{id},#{username},
        
          #{gender},
        
        
            #{deleteFlag}
        
    

此时程序就可以正常执行了。

标签

标签一般应用于需要动态组装where条件的地方。

只会在子元素有内容的情况下才插入where子句,而且会自动去除子句的开头的AND或
OR。

例如:我们此时根据 id 和 gender 来查找数据。

数据库中的数据如下:

MyBatis 实现动态 SQL_第3张图片

接口定义:

User selectUser(Integer id, Integer gender);

xml实现:

JAVA测试代码

@Test
void selectUser() {
    System.out.println(userinfo.selectUser(1, 1));
}

MyBatis 实现动态 SQL_第4张图片

从打印的结果和日志中我们可以看出结果正确。

如果 id 和 gender 都为 null

@Test
void selectUser() {
    System.out.println(userinfo.selectUser(null, null));
}

虽然程序报错了,可是并不是因为SQL错了而是因为接收的参数报错。

此时可以看出 where 被去掉了。 

MyBatis 实现动态 SQL_第5张图片

此时如果 gender 为空

@Test
void selectUser() {
    System.out.println(userinfo.selectUser(1, null));
}

标签并不能去除句末的 and 

标签

标签用于动态更新数据

用于 update 语句中动态的在SQL语句中插入 set 关键字,并会删掉额外的逗号。

例如:根据传入的id属性,修改 username 和 gender 中不为null的属性。

接口定义:

Integer upData(Integer id, String username, Integer gender);

xml代码实现:


    update userinfo  
    
        
            username = #{username},
        
        
            gender = #{gender}
        
    
    where id = #{id};

JAVA测试代码

void upData() {
    //gender为空
    userinfo.upData(2, "xiaohong", null);
}

MyBatis 实现动态 SQL_第6张图片
可以看出删掉了额外的逗号(前后都会删掉)。

标签

该标签可以在对集合进行遍历时使用。

标签有如下属性:

  • collection:绑定方法参数中的集合,如List,Set,Map或数组对象;
  • item:遍历时对象中的每个元素;
  • open:语句块开头的字符串;
  • close:语句块结束的字符串;
  • separator:每次遍历之间间隔的字符串。

例如:批量删除数据

接口定义:

Integer deleteUsers(List ids);

xml代码实现:


    delete from userinfo where id in
    
        #{id}
    

注意:这两个地方的名称必须相同。

MyBatis 实现动态 SQL_第7张图片

JAVA测试代码

@Test
void deleteUsers() {
    List list = new ArrayList<>();
    list.add(1);
    list.add(2);
    userinfo.deleteUsers(list);
}

MyBatis 实现动态 SQL_第8张图片

标签

这两个标签配合使用可以实现对重复的代码片段进行抽取,将其通过 标签封装到一个SQL片段,然后再通过 标签进行引用。用来降低代码的冗余度。

  • :定义可重用的SQL片段
  • :通过属性refid,指定包含的SQL片段

例如:我们可以抽取下面xml中的部分代码。


    delete from userinfo where id in
    
        #{id}
    

    delete from userinfo where id in



    
    
        #{id}
    

 JAVA测试代码

@Test
void deleteUsers() {
    List list = new ArrayList<>();
    list.add(1);
    list.add(2);
    userinfo.deleteUsers(list);
}

MyBatis 实现动态 SQL_第9张图片

@注解的实现方式

注解的实现其实非常简单只需把xml标签中的SQL(包括标签),使用 标签括起来就可以了。

例如下面的xml代码


INSERT INTO userinfo (
username,
`password`,
age,

gender,

phone)
VALUES (
#{username},
#{age},

#{gender},

#{phone})

注解的实现方法:

@Insert("")
Integer insertUserByCondition(UserInfo userInfo);

你可能感兴趣的:(java,spring,mybatis,mvc,sql,数据库)