Mybatis-plus快速入门(2)
作者:快盘下载 人气:CSDN话题挑战赛第2期
参赛话题;学习笔记
Mybatis-plus
学习之路;长路漫漫;需要您的陪伴。
关注一波;您的关注是我最大的动力。
文章目录
Mybatis-plus四、常用注解1、;TableName2、;TableId3、;TableField4、;TableLogic 五、条件构造器和常用接口1、wrapper介绍2、QueryWrapper3、UpdateWrapper4、condition5、LambdaQueryWrapper6、LambdaUpdateWrapper文章目录接上篇文章 Mybatis-plus快速入门;1;
四、常用注解
1、;TableName
① 问题
也许有同学发现了;在上一篇文章 Mybatis-plus快速入门;1; 中我们使用Mybatis-plus进行简单的CRUD时并没有指定表名;只是在Mapper接口继承BaseMapper时;设置了泛型User;而操作的表为User表
由此可知;MyBatis-Plus在确定操作的表时;由BaseMapper的泛型决定;即实体类型决定;且默认操作的表名和实体类型的类名一致
② 测试
测试如下;将user表改为t_user表;测试查询功能
程序抛出异常;Table ‘mybatis_plus.user’ doesn’t exist;因为现在的表名为t_user;而默认操作的表名和实体类型的类名一致;即user表
③ 添加;TableName
在实体类类型上添加;TableName(“t_user”);标识实体类对应的表;即可成功执行SQL语句
④ 全局配置
在开发的过程中;我们经常遇到以上的问题;即实体类所对应的表都有固定的前缀;例如t_ 或tbl_
此时;可以使用MyBatis-Plus提供的全局配置;在application.yaml中为实体类所对应的表名设置默认的前缀;那么就不需要在每个实体类上通过;TableName标识实体类对应的表
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#设置Mybatis-plus全局配置
global-config:
db-config:
#设置实体类所对应表的统一前缀
table-prefix: t_
#设置统一的主键生成策略
2、;TableId
我们在使用MyBatis-Plus实现CRUD时;会默认将id作为主键列;并在插入数据时;默认基于雪花算法的策略生成id。
① 问题
若实体类和表中表示主键的不是id;而是其他字段;例如uid;MyBatis-Plus会自动识别uid为主键列吗?
我们实体类中的属性id改为uid;将表中的字段id也改为uid;测试添加功能
程序抛出异常;Field ‘uid’ doesn’t have a default value;说明MyBatis-Plus没有将uid作为主键赋值
② 添加;TableId
在实体类中uid属性上通过;TableId将其标识为主键;即可成功执行SQL语句
③ ;TableId的value属性
若实体类中主键对应的属性为id;而表中表示主键的字段为uid;此时若只在属性id上添加注解;TableId;则抛出异常Unknown column ‘id’ in ‘field list’;即MyBatis-Plus仍然会将id作为表的主键操作;而表中表示主键的是字段uid
此时需要通过;TableId注解的value属性;指定表中的主键字段;;TableId(“uid”)或;TableId(value=“uid”)
④ ;TableId的type属性
type属性用来定义主键策略;这里我们介绍其中的两种常用的;
可在实体类对应的字段上进行设置;
//将属性所对应的字段指定为主键
//tableId注解的value属性用于指定主键的字段
//tableId注解的type属性用于设置主键生成策略
;TableId(value = ;uid;,type = IdType.AUTO)
private Long uid;
也可在application.yaml中配置全局主键策略;
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#设置Mybatis-plus全局配置
global-config:
db-config:
#设置实体类所对应表的统一前缀
table-prefix: t_
#设置统一的主键生成策略
id-type: auto
⑤ 雪花算法
雪花算法是由Twitter公布的分布式主键生成算法;它能够保证不同表的主键的不重复性;以及相同表的
主键的有序性。
核心思想;
长度共64bit;一个long型;。
首先是一个符号位;1bit标识;由于long基本类型在Java中是带符号的;最高位是符号位;正数是0;负
数是1;所以id一般是正数;最高位是0。
41bit时间截(毫秒级);存储的是时间截的差值;当前时间截 - 开始时间截);结果约等于69.73年。
10bit作为机器的ID;5个bit是数据中心;5个bit的机器ID;可以部署在1024个节点;。
12bit作为毫秒内的流水号;意味着每个节点在每毫秒可以产生 4096 个 ID;。
优点
整体上按照时间自增排序;并且整个分布式系统内不会产生ID碰撞;并且效率较高
3、;TableField
我们可以发现;MyBatis-Plus在执行SQL语句时;要保证实体类中的属性名和表中的字段名一致
如果实体类中的属性名和字段名不一致的情况;会出现什么问题呢?
情况①
若实体类中的属性使用的是驼峰命名风格;而表中的字段使用的是下划线命名风格
例如实体类属性userName;表中字段user_name
此时MyBatis-Plus会自动将下划线命名风格转化为驼峰命名风格
相当于在MyBatis中配置
情况②
若实体类中的属性和表中的字段不满足情况1
例如实体类属性name;表中字段username
此时需要在实体类属性上使用;TableField(“username”)设置属性所对应的字段名
4、;TableLogic
① 逻辑删除
物理删除;真实删除;将对应数据从数据库中删除;之后查询不到此条被删除的数据逻辑删除;假删除;将对应数据中代表是否被删除字段的状态修改为“被删除状态”;之后在数据库中仍旧能看到此条数据记录使用场景;可以进行数据恢复② 实现逻辑删除
步骤一、在User表中增加一个int型的字段is_deleted;初始值为0;代表未删除
步骤二、实体类中添加逻辑删除属性
步骤三、测试
测试删除功能;真正执行的是修改;从日志输出的sql语句可以看出
UPDATE t_user SET is_deleted=1 WHERE id=? AND is_deleted=0
测试查询功能;被逻辑删除的数据默认不会被查询
SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0
五、条件构造器和常用接口
1、wrapper介绍
Wrapper ; 条件构造抽象类;最顶端父类
AbstractWrapper ; 用于查询条件封装;生成 sql 的 where 条件
QueryWrapper ; 查询条件封装
UpdateWrapper ; Update 条件封装
AbstractLambdaWrapper ; 使用Lambda 语法
LambdaQueryWrapper ;用于Lambda语法使用的查询Wrapper
LambdaUpdateWrapper ; Lambda 更新封装Wrapper
2、QueryWrapper
① 组装查询条件
;Test
public void test01() {
//查询用户名包含a;年龄在20-30之间;邮箱信息不为null的用户信息
//日志输出的sql语句;SELECT uid,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like(;user_name;,;a;)
.between(;age;,20,30).isNotNull(;email;);
List<User> list = usermapper.selectList(queryWrapper);
list.forEach(System.out::println);
}
② 组装排序条件
;Test
public void test02() {
//查询用户信息;按照年龄进行降序排序;若年龄相同;则按照id升序排序
//日志输出的sql语句;SELECT uid,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 ORDER BY age DESC,uid ASC
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc(;age;)
.orderByAsc(;uid;);
List<User> list = usermapper.selectList(queryWrapper);
list.forEach(System.out::println);
}
③ 组装删除条件
;Test
public void test03() {
//删除邮箱地址为null的用户信息
//增加了逻辑删除;所以变化为更新了
//日志输出的sql语句;UPDATE t_user SET is_deleted=1 WHERE is_deleted=0 AND (email IS NULL)
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.isNull(;email;);
int res = usermapper.delete(queryWrapper);
System.out.println(;res = ; ; res);
}
④ 条件的优先级
;Test
public void test04() {
//将;年龄大于20并且名字中含有a;或邮箱为null的用户信息修改
//日志输出的sql语句;UPDATE t_user SET user_name=?, email=? WHERE is_deleted=0 AND (age > ? AND user_name LIKE ? OR email IS NULL)
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.gt(;age;,20).like(;user_name;,;a;)
.or().isNull(;email;);
User user = new User();
user.setName(;小明;);
user.setEmail(;test;atguigu.com;);
int res = usermapper.update(user, queryWrapper);
System.out.println(;res = ; ; res);
}
;Test
public void test05() {
//将名字中含有a并且;年龄大于20或邮箱为null;的用户信息修改
//日志输出的sql语句;UPDATE t_user SET user_name=?, email=? WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//lambda表达式内的逻辑优先运算
queryWrapper.like(;user_name;,;a;)
.and(i->i.gt(;age;,20).or().isNull(;email;));
User user = new User();
user.setName(;Sandy;);
user.setEmail(;test;atguigu.com;);
int res = usermapper.update(user, queryWrapper);
System.out.println(;res = ; ; res);
}
⑤ 组装select语句
;Test
public void test06() {
//查询用户的用户名;年龄;邮箱
//日志输出的sql语句;SELECT user_name,age,email FROM t_user WHERE is_deleted=0
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select(;user_name;,;age;,;email;);
//查询的是部分字段;没必要直接对应实体类对象;直接map集合即可
List<Map<String, Object>> maps = usermapper.selectMaps(queryWrapper);
maps.forEach(System.out::println);
}
⑥ 实现子查询
;Test
public void test07() {
//通过子查询查询用户id小于等于10的用户信息
//日志输出的查询语句;SELECT uid,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (uid IN (Select uid from t_user where uid <= 10))
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.inSql(;uid;,;Select uid from t_user where uid <= 10;);
List<User> list = usermapper.selectList(queryWrapper);
list.forEach(System.out::println);
}
3、UpdateWrapper
;Test
public void test08() {
//将名字中含有a并且;年龄大于20或邮箱为null;的用户信息修改
//日志输出的sql语句;UPDATE t_user SET user_name=?,email=? WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))
//UpdateWrapper设置修改条件的同时也可设置修改字段
UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
userUpdateWrapper.like(;user_name;,;a;)
.and(i->i.gt(;age;,20).or().isNull(;email;));
userUpdateWrapper.set(;user_name;,;小黑;).set(;email;,;xiaohei;atguigu.com;);
int res = usermapper.update(null, userUpdateWrapper);
System.out.println(;res = ; ; res);
}
4、condition
在真正开发的过程中;组装条件是常见的功能;而这些条件数据来源于用户输入;是可选的;因此我们在组装这些条件时;必须先判断用户是否选择了这些条件;若选择则需要组装该条件;若没有选择则一定不能组装;以免影响SQL执行的结果
思路①
;Test
public void test09() {
//开发中的场景
//日志输出的sql语句;SELECT uid,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age < ?)
//定义查询条件;有可能为null;用户未输入或未选择;
String userName=;小;;
Integer ageBegin=null;
Integer ageEnd=30;
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
if(StringUtils.isNotBlank(userName)) {
queryWrapper.like(;user_name;,userName);
}
if(ageBegin!=null) {
queryWrapper.gt(;age;,ageBegin);
}
if(ageEnd!=null) {
queryWrapper.lt(;age;,ageEnd);
}
List<User> list = usermapper.selectList(queryWrapper);
list.forEach(System.out::println);
}
思路②
;Test
public void test10() {
//相比test09更方便的写法
//日志输出的sql语句;SELECT uid,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age < ?)
String userName=;小;;
Integer ageBegin=null;
Integer ageEnd=30;
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like(StringUtils.isNotBlank(userName),;user_name;,userName)
.gt(ageBegin!=null,;age;,ageBegin)
.lt(ageEnd!=null,;age;,ageEnd);
List<User> list = usermapper.selectList(queryWrapper);
list.forEach(System.out::println);
}
5、LambdaQueryWrapper
;Test
public void test11() {
//LambdaQueryWrapper为了防止字段名写错;可以使用函数式接口访问实体类中的某一个属性所对应的字段名
//日志输出的sql语句
String userName=;小;;
Integer ageBegin=null;
Integer ageEnd=30;
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.like(StringUtils.isNotBlank(userName),User::getName,userName)
.gt(ageBegin!=null,User::getAge,ageBegin)
.lt(ageEnd!=null,User::getAge,ageEnd);
List<User> list = usermapper.selectList(lambdaQueryWrapper);
list.forEach(System.out::println);
}
6、LambdaUpdateWrapper
;Test
public void test12() {
//将名字中含有a并且;年龄大于20或邮箱为null;的用户信息修改
//日志输出的sql语句;UPDATE t_user SET user_name=?,email=? WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL)) //UpdateWrapper设置修改条件的同时也可设置修改字段
LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
lambdaUpdateWrapper.like(User::getName,;a;)
.and(i->i.gt(User::getAge,20).or().isNull(User::getEmail));
lambdaUpdateWrapper.set(User::getName,;小黑;).set(User::getEmail,;xiaohei;atguigu.com;);
int res = usermapper.update(null, lambdaUpdateWrapper);
System.out.println(;res = ; ; res);
}
点赞;关注;收藏;您的支持是我更新的最大动力;;;
加载全部内容