# 一.基本介绍
# 1.常见操作
- ge、gt、le、lt、isNull、isNotNull
- eq、ne
- between、notBetween
- allEq
- like、notLike、likeLeft、likeRight
- in、notIn、inSql、notinSql、exists、notExists
- or、and
- 嵌套 or、嵌套 and
- orderBy、orderByDesc、orderByAsc
- last
- 指定要查询的列
- set、setSql
# 2.条件构造器
- Wrapper : 条件构造抽象类,最顶端父类
- AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
- QueryWrapper : Entity 对象封装操作类,不是用 lambda 语法
- UpdateWrapper : Update 条件封装,用于 Entity 对象更新操作
- AbstractLambdaWrapper : Lambda 语法使用 Wrapper 统一处理解析 lambda 获取 column。
- LambdaQueryWrapper :看名称也能明白就是用于 Lambda 语法使用的查询 Wrapper
- LambdaUpdateWrapper : Lambda 更新封装 Wrapper
# 二.常见查询
# 1.根据主键查询
User user = userMapper.selectById(1094592041087729666L);
# 2.通过多个 id 查询
List<Long> longs = Arrays.asList(1094592041087729666L, 1094590409767661570L);
List<User> users = userMapper.selectBatchIds(longs);
users.forEach(System.out::println);
2
3
# 3.通过 map 查询
Map<String, Object> params = new HashMap<>();
params.put("name", "张雨琪");
List<User> users = userMapper.selectByMap(params);
2
3
# 4.时间格式化
wrapper.apply("date_format(create_time,"%Y-%m-%d") = {0}", "2019-02-14")
# 5.allEq
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
Map<String, Object> map = new HashMap<>();
map.put("id", 2);
map.put("name", "Jack");
map.put("age", 20);9
queryWrapper.allEq(map);
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
2
3
4
5
6
7
8
# 6.指定查询列
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("id", "name", "age");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
2
3
4
5
# 三.普通查询
# 1.链式条件查询
//条件查询-等于-like-小于-大于-排序
private Wrapper<TaskRecordDO> getTaskRecordWrapper(ListTaskRecordRequestDTO query) {
Date startExecuteTime = query.getStartExecuteTime();
Date endExecuteTime = query.getEndExecuteTime();
Calendar calendar = new GregorianCalendar();
if (endExecuteTime != null) {
calendar.setTime(endExecuteTime);
calendar.add(Calendar.DATE, 1);
}
return new QueryWrapper<TaskRecordDO>()
.lambda()
.eq(StringUtils.isNotBlank(query.getExecuteStatus()), TaskRecordDO::getExecStatus, query.getExecuteStatus())
.like(StringUtils.isNotBlank(query.getKeyword()), TaskRecordDO::getOutNodeName, query.getKeyword())
.lt(endExecuteTime != null, TaskRecordDO::getStartRunTime, calendar.getTime())
.ge(startExecuteTime != null, TaskRecordDO::getStartRunTime, startExecuteTime)
.eq(query.getTaskId() != null, TaskRecordDO::getTaskId, query.getTaskId())
.orderByDesc(TaskRecordDO::getId);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 2.selectOne
UserRelateCar userRelateCar = userRelateCarMapper.selectOne(Wrappers.<UserRelateCar>lambdaQuery().eq(UserRelateCar::getXcxUserId, driverXcxUserId)
.eq(UserRelateCar::getNumber, number));
2
# 3.selectList
List<ShipmentOrderDetailGoodsInfo> shipmentOrderDetailGoodsInfos = shipmentOrderDetailGoodsInfoMapper.selectList(Wrappers.<ShipmentOrderDetailGoodsInfo>lambdaQuery()
.eq(ShipmentOrderDetailGoodsInfo::getShipmentOrderDetailId, shipmentDetailId));
2
# 4.selectPage 分页
@GetMapping(value = "/selectAllInPage")
public List<Teacher> selectAllInPage(int pageNumber,int pageSize){
Page<Teacher> page =new Page<>(pageNumber,pageSize);
EntityWrapper<Teacher> entityWrapper = new EntityWrapper<>();
entityWrapper.ge("id", 1);
return teacherMapper.selectPage(page,entityWrapper);
}
2
3
4
5
6
7
LambdaUpdateWrapper<AdsDayCityOrrCalendarDo> wrapper = Wrappers.lambdaUpdate(AdsDayCityOrrCalendarDo.class)
.eq(AdsDayCityOrrCalendarDo::getBrandDetailNo, query.getBrandDetailNo());
final Page<AdsDayCityOrrCalendarDo> citys = adsDayCityOrrCalendarMapper.selectPage(new Page<>(query.getPage(), query.getSize()), wrapper);
2
3
# 5.排序
可以使用 QueryWrapper 的 orderByDesc 方法来指定字段降序查询,示例代码如下:
//其中,"age" 是需要降序排列的字段名。
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.orderByDesc("age"); // 按照 age 字段降序排列
List<User> userList = userMapper.selectList(wrapper);
2
3
4
# 6.模糊查询
//条件查询-左边模糊匹配-右边模糊匹配
@Override
public boolean checkExist(String tableName) {
Wrapper<DagConfDO> queryWrapper = Wrappers.<DagConfDO>query().lambda()
.likeLeft(DagConfDO::getConf, tableName)
.likeRight(DagConfDO::getConf, tableName)
.orderByDesc(DagConfDO::getId)
.groupBy(DagConfDO::getTaskId);
dagConfMapper.selectList(queryWrapper);
return false;
}
2
3
4
5
6
7
8
9
10
11
# 四.高阶查询
# 1.复杂多条件
@GetMapping(value = "/selectAllByWrapper4")
public List<Teacher> selectAllByWrapper4(){
EntityWrapper entity=new EntityWrapper();
entity.gt("id","0");
entity.le("id",11);
entity.ne("teacher_name","null_name");
entity.like("teacher_name","tt");
entity.notLike("teacher_pwd","sadas");
entity.orderBy("id");
return teacherMapper.selectList(entity);
}
2
3
4
5
6
7
8
9
10
11
# 2.and 条件
QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<AttrEntity>().
eq("attr_id",key).
eq("catelog_id",catelogId);
2
3
或者
QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<AttrEntity>().
eq("attr_id",key);
queryWrapper.and(qr -> qr.eq("catelog_id", catelogId));
2
3
4
# 3.or 条件
QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<AttrEntity>().
eq("attr_id",key).
or().
eq("catelog_id",catelogId);
2
3
4
要查询 MailInfo
表中 user_id
或 to_user_id
等于 userId
的数据,可以在 QueryWrapper
中使用 or
方法来添加条件。下面是你可以使用的代码示例:
Page<MailInfo> pageParm = new Page<>();
pageParm.setCurrent(page);
pageParm.setSize(pageSize);
QueryWrapper<MailInfo> wrapper = new QueryWrapper<>();
wrapper.eq("is_delete", 0)
.and(w -> w.eq("user_id", userId).or().eq("to_user_id", userId))
.orderByDesc("update_time");
return Result.ok(MailInfoDTO.Converter.INSTANCE.from(this.mailInfoService.page(pageParm, wrapper)));
2
3
4
5
6
7
8
9
在这个示例中:
- 使用
and
方法将is_delete
条件和其他条件组合在一起。 - 在
and
方法中,使用w
作为 Lambda 参数来定义user_id
或to_user_id
的条件,确保在两者中都能找到匹配项。
这样就能查询出所有 user_id
或 to_user_id
等于 userId
的记录。
# 4.优先级连接
QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<AttrEntity>().eq("attr_type", "base".equalsIgnoreCase(type) ? 1 : 0);
queryWrapper.and(qr ->
qr.eq("attr_id", key).
or().
like("attr_name", key)
);
queryWrapper.and(qr -> qr.eq("catelog_id", catelogId));
2
3
4
5
6
7
8
select ...
WHERE (attr_type = ? AND ( (attr_id = ? OR attr_name LIKE ?) ) AND ( (catelog_id = ?) ))
...;
2
3
由此还可见 or(Consumer consumer),and(Consumer consumer)这两个方法参数为 Consumer 时,会在连接处生成 2 对括号,以此提高优先级。
or带括号练习:
LambdaQueryWrapper<CsdnRedPackage> wrapper = new LambdaQueryWrapper<>();
wrapper.and(QueryWrapper ->
QueryWrapper.notIn(CsdnRedPackage::getMsg, CommonConstant.RedPackageResponse.COMPLETED, CommonConstant.RedPackageResponse.RECEIVED)
.or(query -> query.eq(CsdnRedPackage::getMsg, "received").eq(CsdnRedPackage::getMyAmount, 0))
);
wrapper.eq(CsdnRedPackage::getIsDelete, 0);
2
3
4
5
6
# 5.随机排序
希望返回的数据是随机的,而不是根据某一个字段进行排序,我们可以使用 rand()函数进行排序。
QueryWrapper<CsdnUserInfo> wrapper = new QueryWrapper<>();
wrapper.eq("is_delete", 0);
wrapper.orderByAsc("rand()");
final List<CsdnUserInfo> list = csdnUserInfoService.list(wrapper);
2
3
4
# 6.日期处理
QueryWrapper<CsdnRedPackage> wrapper = new QueryWrapper<>();
wrapper.eq("is_delete", 0);
String today = DateUtil.today();
String formattedDate = DateUtil.format(DateUtil.parse(today), "yyyy-MM-dd");
wrapper.apply("DATE(create_time) = {0}", formattedDate);
final List<CsdnRedPackage> list = csdnRedPackageService.list(wrapper);
2
3
4
5
6
# 7.notIn
多个不等于的值使用 notIn
if (StringUtils.isNotEmpty(msg)) {
if (StringUtils.equals(msg, "其它")) {
wrapper.notIn("msg", "completed", "received");
} else {
wrapper.eq("msg", msg);
}
}
2
3
4
5
6
7
# 8.inSql
in、notIn、inSql、notinSql、exists、notExists 也都是支持的
- 查询创建时间为 2019 年 2 月 14
- 并且上级领导姓王
wrapper.apply("date_format(create_time,"%Y-%m-%d") = {0}", "2019-02-14")
.inSql("manager_id", "select id from user where name like "王%"");
2
# 9.likeRight
likeRight 是匹配以什么开头的数据。
QueryWrapper<CsdnFollowFansInfo> wrapper = new QueryWrapper<>();
wrapper.eq("is_delete", 0);
wrapper.likeRight("user_name", "2301_");
final List<CsdnFollowFansInfo> list = this.list(wrapper);
2
3
4
# 10.nested
nested相当于括号,以下代码实现了2个括号一个or的功能
Page<SingleChatLog> pageParm = new Page<>();
pageParm.setCurrent(page);
pageParm.setSize(pageSize);
LambdaQueryWrapper<SingleChatLog> queryWrapper = new LambdaQueryWrapper<>();
final LoginUser loginUser = AuthInterceptor.THREAD_LOCAL.get();
final Integer userId = loginUser.getId();
if (Objects.nonNull(userId) && Objects.nonNull(toUserId)) {
queryWrapper
.nested(w -> w.eq(SingleChatLog::getFromUserId, userId).eq(SingleChatLog::getToUserId, toUserId))
.or()
.nested(w2 -> w2.eq(SingleChatLog::getFromUserId, toUserId).eq(SingleChatLog::getToUserId, userId));
}
queryWrapper.eq(SingleChatLog::getIsDelete, 0);
queryWrapper.orderByDesc(SingleChatLog::getCreateTime);
return Result.ok(SingleChatLogDTO.Converter.INSTANCE.from(this.singleChatLogService.page(pageParm, queryWrapper)));
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 五.update 和 remove
# 1.update
userRelateCarMapper.update(new UserRelateCar(), Wrappers.<UserRelateCar>lambdaUpdate()
.set(UserRelateCar::getIsDefault, DefaultCarEnum.YES.getType())
.eq(UserRelateCar::getNumber, carNumber)
.eq(UserRelateCar::getXcxUserId, xcxUserId));
2
3
4
# 2.remove
shipmentOrderRelateUserService.remove(Wrappers.<ShipmentOrderRelateUser>lambdaQuery()
.eq(ShipmentOrderRelateUser::getRoleId, RoleEnum.DRIVER.getType())
.eq(ShipmentOrderRelateUser::getShipmentOrderId, id));
2
3
# 3.set 和 setSql
//修改值
User user = new User();
user.setAge(99);
//修改条件
UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
userUpdateWrapper
.like("name", "h")
.set("name", "老李头")//除了可以查询还可以使用set设置修改的字段
.setSql(" email = '123@qq.com'");//可以有子查询
int result = userMapper.update(user, userUpdateWrapper);
2
3
4
5
6
7
8
9
10
11
# 4.批量修改
先根据 id 获取到批量的集合,需要注意的是这里的 ids 不能太大。
if (CollectionUtil.isNotEmpty(ids) && StringUtils.isNotEmpty(type)) {
List<PicInfo> picInfoList = ids.stream()
.map(id -> picInfoService.getById(id))
.collect(Collectors.toList());
picInfoList.forEach(picInfo -> picInfo.setType(type));
picInfoService.updateBatchById(picInfoList);
}
2
3
4
5
6
7
# 六.常见配置
# 1.实现类写法
@Service
public class StoreBaseServiceImpl extends ServiceImpl<StoreBaseMapper, StoreBase> implements IStoreBaseService {
}
public interface IStoreBaseService extends IService<StoreBase> {
}
2
3
4
5
6
7
8
# 2.注解
@Api(tags = "外部系统(供应链)交互API") //controller
@ApiOperation("信息软删除") //方法
@ApiModelProperty(value = "对接系统") //属性
@ApiModel(value = "任务统计") //返回的对象
2
3
4
5
6
7
# 3.只打印 SQL 语句
Mybatis 配置
mybatis:
configuration:
### 开启打印sql配置
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
### 开启驼峰配置
map-underscore-to-camel-case:true
2
3
4
5
6
MybatisPlus 配置
mybatis-plus:
configuration:
### 开启打印sql配置
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
### 开启驼峰配置
map-underscore-to-camel-case:true
2
3
4
5
6
生产关闭日志
mybatis-plus:
configuration:
#关闭sql日志
log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl
2
3
4
其他配置
### mybatis 相关配置
mybatis:
config-location: classpath:mybatis.cfg.xml # mybatis主配置文件所在路径
type-aliases-package: com.example.entity # 定义所有操作类的别名所在包
mapper-locations: classpath:mapper/*.xml # 所有的mapper映射文件
configuration:
# 开启驼峰uName自动映射到u_name
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
### mybatis-plus 相关配置
mybatis-plus:
type‐aliases‐package: com.example.entity # 定义所有操作类的别名所在包
# xml扫描,多个目录用逗号或者分号分隔(告诉 Mapper 所对应的 XML 文件位置)
mapper-locations: classpath:mapper/*.xml
# 以下配置均有默认值,可以不设置
global-config:
banner: false # 是否 mybatis-plus 在控制台输出的logo
db-config:
#主键类型 AUTO:"数据库ID自增" INPUT:"用户输入ID",ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";
id-type: auto
#字段策略 IGNORED:"忽略判断" NOT_NULL:"非 NULL 判断") NOT_EMPTY:"非空判断"
field-strategy: NOT_EMPTY
#数据库类型
db-type: MYSQL
logic-delete-field: deleted # 全局逻辑删除的实体字段名
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
configuration:
# 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射
map-underscore-to-camel-case: true
# 如果查询结果中包含空值的列,则 MyBatis 在映射的时候,不会映射这个字段
call-setters-on-nulls: true
# 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
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
# 4.驼峰设置
mybatis 默认是属性名和数据库字段名一一对应的,即
- 数据库表列:user_name
- 实体类属性:user_name
但是 java 中一般使用驼峰命名
- 数据库表列:user_name
- 实体类属性:userName
在 Springboot 中,可以通过设置 map-underscore-to-camel-case 属性为 true 来开启驼峰功能。 application.yml 中:
mybatis:
configuration:
map-underscore-to-camel-case: true
2
3
application.properties 中:
mybatis.configuration.map-underscore-to-camel-case:=true
# 5.创建时间
/**
* 创建时间
*/
@TableField(value = "create_time", fill = FieldFill.INSERT)
private Date createTime;
/**
* 修改时间
*/
@TableField(value = "edit_time", fill = FieldFill.INSERT_UPDATE)
private Date editTime;
2
3
4
5
6
7
8
9
10
# 6.数据库不存在字段
@TableField(exist = false)
# 7.更新字段
如果您是在使用 MyBatis-Plus 进行数据库操作,可以使用以下代码将 id 为 1 的数据的 is_delete 字段改为 1:
QueryWrapper<Chatbot> wrapper = new QueryWrapper<>();
wrapper.eq("id", 1);
Chatbot chatbot = new Chatbot();
chatbot.setIsDelete(1);
return Result.ok(this.chatbotService.update(chatbot, wrapper));
2
3
4
5
在上述代码中,我们先创建了一个 QueryWrapper
对象,通过 eq
方法指定查询条件为 id = 1
和 is_delete = 1
。然后,我们创建了一个 Chatbot
对象,设置其 is_delete
字段为 1
。最后,我们调用 update
方法,将修改后的 Chatbot
对象和查询条件 QueryWrapper
对象传递给 update
方法,完成数据更新操作。 需要注意的是,如果您要更新的数据不存在,update
方法会返回 false
,否则会返回 true
。如果您需要返回更新后的数据,可以使用 updateById
方法,该方法会返回更新后的完整实体对象。
# 8.@TableField
如果您在使用 MyBatis-Plus 进行数据库操作,可以使用 @TableField
注解来标记实体类中的字段,指定该字段不在数据库中对应的列。以下是一个示例代码:
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
@TableName("chatbot")
public class Chatbot {
private Long id;
private String name;
private Integer age;
@TableField(exist = false)
private String otherField;
// 省略 getter 和 setter 方法
}
2
3
4
5
6
7
8
9
10
11
12
13
在上述代码中,我们使用 @TableField
注解来标记 otherField
字段,指定该字段不在数据库中对应的列。其中,exist
属性指定该字段是否在数据库表中存在。如果 exist
属性设置为 false
,则表示该字段不在数据库表中存在,否则表示该字段在数据库表中存在。在本例中,我们将 exist
属性设置为 false
,表示 otherField
字段不在数据库表中存在。
需要注意的是,如果您在实体类中使用了 @TableField
注解,那么在进行查询、更新、删除等操作时,MyBatis-Plus 会忽略该字段。如果您需要在查询中使用该字段,可以使用 select
方法指定查询的字段列表。
# 七.自动更新时间
# 1.MyMetaObjectHandler
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
this.strictInsertFill(metaObject, "updateTime", Date.class, new Date());
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
}
}
2
3
4
5
6
7
8
9
10
11
12
13
# 2.实体类
@ApiModelProperty("创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField(value = "create_time", fill = FieldFill.INSERT)
private Date createTime;
@ApiModelProperty("更新时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
2
3
4
5
6
7
8
# 3.数据库
`create_time` timestamp DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
2