CSDN话题挑战赛第2期
参赛话题;学习笔记
学习之路;长路漫漫;需要您的陪伴。
关注一波;您的关注是我最大的动力。
文章目录接上篇文章 Mybatis-plus快速入门;1;
① 问题
也许有同学发现了;在上一篇文章 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属性用来定义主键策略;这里我们介绍其中的两种常用的;
值描述IdType.ASSIGN_ID;默认;基于雪花算法的策略生成数据id;与数据库id是否设置自增无关IdType.AUTO使用数据库的自增策略;注意;该类型请确保数据库设置了id自增
可在实体类对应的字段上进行设置;
//将属性所对应的字段指定为主键
//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); }
点赞;关注;收藏;您的支持是我更新的最大动力;;;
网友评论
快盘下载暂未开通留言功能。
-
推荐文章
最新文章