在后台管理中 , 常常需要设置多个条件来筛选数据 , 也就是多条件查询

多条件查询

Spring Boot+Mybatis多条件模糊查询,动态sql_fanminghao的博客-CSDN博客

  • 使用动态SQL

在此 SQL 语句中, where 1=1 是多条件拼接时的小技巧, 后面的条件查询就可以都用 and 了。

使用 if 标签来处理动态 SQL

注意if标签里面的 test , 对应的应该是实体类的属性名

实体类

User.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package com.miao.domain;

import com.baomidou.mybatisplus.annotation.*;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;
import java.util.Objects;
/**
*
* @TableName t_user
*/
@TableName(value ="t_user")
@Data
@ApiModel("用户表")
public class User implements Serializable {
/**
* 用户id
*/
@TableId(type = IdType.AUTO)
@ApiModelProperty(value = "用户id")
private Integer userId;

/**
* 用户昵称
*/
@ApiModelProperty(value = "用户昵称")
private String userName;

/**
* 账户
*/
@ApiModelProperty(value = "账户名")
private String userAccount;

/**
* 登录密码
*/
@ApiModelProperty(value = "密码",hidden = true)
private String userPassword;


/**
* 学校
*/
@ApiModelProperty(value = "学校")
private String school;

/**
* 头像地址
*/
@ApiModelProperty(value = "头像url")
private String avatarUrl;

/**
* 性别 1 男 0 女
*/
@ApiModelProperty(value = "性别")
private Integer gender;

/**
* 手机号
*/
@ApiModelProperty(value = "电话")
private String phone;

/**
* 邮箱
*/
@ApiModelProperty(value = "邮箱")
private String email;

/**
* 注册时间
*/
@ApiModelProperty(value = "注册时间")
private Date createTime;

/**
* 出生日期
*/
@ApiModelProperty(value = "生日")
private Date birth;

/**
* 更新时间
*/
@ApiModelProperty(value = "更新时间")
private Date updateTime;

/**
* 是否是管理员
*/
@ApiModelProperty(value = "权限")
private int isAdmin;
/**
* 是否注销 1 注销
*/
@TableLogic
@ApiModelProperty(value = "逻辑删除")
private int isDelete;

@TableField(exist = false)
private static final long serialVersionUID = 1L;

}

UserSelectiveDTO.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.miao.DTO;

import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.bind.DefaultValue;
import org.springframework.format.annotation.DateTimeFormat;

import java.util.Date;

/**
* @author dhx_
* @className SelectiveDTO
* @date : 2022/11/07/ 20:13
**/
@Data
@ApiModel("多条件查询用户实体类")
public class UserSelectiveDTO {

@ApiModelProperty(name = "用户名称" )
private String userName;

@ApiModelProperty(name = "用户性别" )
private Integer gender;

@ApiModelProperty(name = "学校" )
private String school;

@ApiModelProperty(name = "创建时间" )
@DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd'T'HH:mm:ss")
private Date createTime;
}

动态SQL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!--    - 用户昵称-->
<!-- - 用户注册时间 (时间段) 精确到月份-->
<!-- - 用户性别-->
<!-- - 用户学校-->
<select id="selectByUserSelective" resultType="com.miao.domain.User" parameterType="com.miao.domain.User">
select <include refid="Base_Column_List" />
from t_user
where 1=1
<if test="userName != null and userName !='' ">
and user_name like concat('%',#{userName},'%')
</if>
<if test="school != null and school !='' ">
and school like concat('%',#{school},'%')
</if>
<if test="gender != null ">
and gender= #{gender}
</if>
<if test="createTime != null ">
and DATE_FORMAT(create_time,'%Y%m') = #{createTime}
</if>
</select>

在MySQL中查询

1
2
3
4
5
6
7
mysql> select user_name , gender , create_time from t_user where 1=1 and user_name like'%d%' and gender = 1 and DATE_FORMAT(create_time,'%Y') =2013;  
+-------------+--------+---------------------+
| user_name | gender | create_time |
+-------------+--------+---------------------+
| Ando Minato | 1 | 2013-08-23 13:29:45 |
+-------------+--------+---------------------+
1 row in set (0.03 sec)

代码测试

1
2
3
4
5
6
7
8
9
10
11
12
@Test
public void testSelect(){
Date date= new Date();
date.setYear(113);// 从1900年开始
date.setMonth(7); // 0~11
User user = new User();
user.setUserName("d");
user.setGender(1);
user.setCreateTime(date);
List<User> users = userMapper.selectByUserSelective(user);
users.forEach(System.out::println);
}

问题

查询不到数据

需要注意日期的格式问题

我们必须提前预定好格式

需要注意的是, java在传入时间的时候传入的是时间戳 , 并且如果在查询的时候日期的格式中包含了 - , 后面拼接的值只能是字符串

mybatis-plus执行语句

mybatis Date类型和Timestamp隐式转换问题,导致sql执行变慢。_y-yyl的博客-CSDN博客_mybatis timestamp转date

MySQL控制台

但是我们可以看到mybatis在查询的时候传入的createTime 的类型是timeStamp , 因此如果我们直接按照

and DATE_FORMAT(create_time,'%Y%m') = #{createTime} , 查询, 一定是查询不到数据的 ,

原本纠结了好一会, 一直想怎么转换java.util.Date , 实际上我们直接使用MySQL的DATE_FORMAT

把穿进去的createTime给格式化就可以了

那么新的SQL语句就是下面这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!--    - 用户昵称-->
<!-- - 用户注册时间 (时间段) 精确到月份-->
<!-- - 用户性别-->
<!-- - 用户学校-->
<select id="selectByUserSelective" resultType="com.miao.domain.User" parameterType="com.miao.domain.User">
select <include refid="Base_Column_List" />
from t_user
where 1=1
<if test="userName != null and userName !='' ">
and user_name like concat('%',#{userName},'%')
</if>
<if test="school != null and school !='' ">
and school like concat('%',#{school},'%')
</if>
<if test="gender != null ">
and gender= #{gender}
</if>
<if test="createTime != null ">
and DATE_FORMAT(create_time,'%Y-%m') = DATE_FORMAT(#{createTime},'%Y-%m')
</if>
</select>

另外需要注意的查询的时候日期的格式必须完全相同 , 不能多也不能少, 也需要注意-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
mysql> select create_time from t_user where DATE_FORMAT(create_time,'%Y%m') = 202211;
+---------------------+
| create_time |
+---------------------+
| 2022-11-02 10:01:08 |
| 2022-11-03 20:25:35 |
| 2022-11-05 23:34:16 |
+---------------------+
3 rows in set (0.03 sec)

mysql> select create_time from t_user where DATE_FORMAT(create_time,'%Y%m') = 20221102;
Empty set

mysql> select create_time from t_user where DATE_FORMAT(create_time,'%Y%m%d') = 20221102;
+---------------------+
| create_time |
+---------------------+
| 2022-11-02 10:01:08 |
+---------------------+
1 row in set (0.03 sec)

多条件的分页查询

(MyBatis-Plus 分页查询以及自定义sql分页_IT贱男的博客-CSDN博客_mybatisplus 原生sql 分页

重构上面的方法为

IPage<User> selectByUserSelective(IPage<User> page,@Param("user")User user);

注意点

需要添加@Param 注解 , 否则在多个参数的情况下mybatis是无法自动获取到参数的名称的

会报错: parameter 'username' not found. available parameters are [arg1, arg0, param1, param2]

同时需要把sql语句中的userName 改成user.userName => 这里面的user应该与@Param注解里面的value保持一致

代码如下