个人微信公众号:程序猿的月光宝盒
说明:
本文是继上一篇入门的进阶版
相关连接:
慕课入门视频:
https://www.imooc.com/learn/1130
入门文章:
https://www.cnblogs.com/jsccc520/p/14669347.html
本文对应进阶视频:
https://www.imooc.com/learn/1171
整合的github地址:
https://github.com/monkeyKinn/StudyMyBatisPlus
觉得不错给个star呗~
star
star
star
Start~
数据准备
#创建用户表
CREATE TABLE user_high (
id BIGINT(20) PRIMARY KEY NOT NULL COMMENT '主键',
name VARCHAR(30) DEFAULT NULL COMMENT '姓名',
age INT(11) DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
manager_id BIGINT(20) DEFAULT NULL COMMENT '直属上级id',
create_time DATETIME DEFAULT NULL COMMENT '创建时间',
update_time DATETIME DEFAULT NULL COMMENT '修改时间',
version INT(11) DEFAULT '1' COMMENT '版本',
deleted INT(1) DEFAULT '0' COMMENT '逻辑删除标识(0.未删除,1.已删除)',
CONSTRAINT manager_fk FOREIGN KEY (manager_id)
REFERENCES user_high (id)
) ENGINE=INNODB CHARSET=UTF8;
#初始化数据:
INSERT INTO user_high (id, name, age, email, manager_id
, create_time)
VALUES (1087982257332887553, '大boss', 40, 'boss@baomidou.com', NULL
, '2019-01-11 14:20:20'),
(1088248166370832385, '王天风', 25, 'wtf@baomidou.com', 1087982257332887553
, '2019-02-05 11:12:22'),
(1088250446457389058, '李艺伟', 28, 'lyw@baomidou.com', 1088248166370832385
, '2019-02-14 08:31:16'),
(1094590409767661570, '张雨琪', 31, 'zjq@baomidou.com', 1088248166370832385
, '2019-01-14 09:15:15'),
(1094592041087729666, '刘红雨', 32, 'lhm@baomidou.com', 1088248166370832385
, '2019-01-14 09:48:16');
注意在user实体类中加上注解映射表名
@TableName("user_high")
因为项目直接是分支下来的 配置就不配置了
具体的到我github上看吧 有需要的话
逻辑删除
简介
加个字段,表示删除状态----软删除了,有选项是级联删除....这就约等于删库跑路,,老板疯狂追你三条gai
MP实现
首先配置文件中给配置上
spring.application.name=MyBatisPlus
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mp?useSSL=false&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=admin
#日志输出配置
logging.level.root=warn
#只想看这个包里的sql日志 trace是最低级别
logging.level.com.jsc.mybatisplus.mapper=trace
# p:级别,m:内容,n:换行
logging.pattern.console=%p%m%n
#配置全局逻辑删除
#没删除 标志0
mybatis-plus.global-config.db-config.logic-not-delete-value=0
#删除 标志1
mybatis-plus.global-config.db-config.logic-delete-value=1
配置类
/**
* mybatis的配置类
*
* @author 金聖聰
* @version v1.0
* @email jinshengcong@163.com
* @date Created in 2021/04/16 15:48
*/
@Configuration
public class MyBatisPlusConfig {
// MP 3.1.1开始 不需要配置
// @Bean
// public ISqlInjector sqlInjector() {
// return new LogicSqlInjector();
// }
}
在实体类中加上逻辑删除的注解@TableLogic
@TableLogic
private Integer deleted;
创建测试类
@Autowired
UserMapper userMapper;
@Test
void delByIdLogic() {
// 加了前面的配置后这里就是逻辑删除了
int i = userMapper.deleteById(1087982257332887553L);
System.out.println("影响行数: " + i);
}
当逻辑删除后,以后进行的查询
,更新
等操作都会去除已经逻辑删除的数据
@Test
void selectAll() {
// 查询全部,这时候把deleted为1的过滤了
userMapper.selectList(null).forEach(System.out::println);
}
@Test
void updateById() {
User user = new User();
// 更新我逻辑删掉的数据,英雄行数为0 更新失败
// user.setId(1087982257332887553L);
// 更新没删除的别人,就可以
user.setId(1094592041087729666L);
user.setAge(18);
int i = userMapper.updateById(user);
System.out.println("影响行数: " + i);
}
查询中排除逻辑删除字段以及注意事项
在实体类的对应字段上加上注解@TableField(select=false)
/** 逻辑删除标识(0.未删除,1.已删除) */
@TableLogic
@TableField(select=false)
private Integer deleted;
下次再查询的时候这个字段就不会出现
但是在自定义的sql中,逻辑删除的还是会查出来,得看你自己的sql了
public interface UserMapper extends BaseMapper<User> {
@Select("select * from user_high ${ew.customSqlSegment}")
List<User> mySelectList(@Param(Constants.WRAPPER) Wrapper<User> wrapper);
}
@Test
void selectMyOwn() {
// 查询全部,这时候把deleted为1的过滤了
userMapper.mySelectList(
Wrappers.<User>lambdaQuery()
.gt(User::getAge,18)
)
.forEach(System.out::println);
}
User(id=1087982257332887553, name=大boss, age=40, email=boss@baomidou.com, managerId=null, createTime=2019-01-11T14:20:20, updateTime=null, version=1, deleted=1)
User(id=1088248166370832385, name=王天风, age=25, email=wtf@baomidou.com, managerId=1087982257332887553, createTime=2019-02-05T11:12:22, updateTime=null, version=1, deleted=0)
User(id=1088250446457389058, name=李艺伟, age=28, email=lyw@baomidou.com, managerId=1088248166370832385, createTime=2019-02-14T08:31:16, updateTime=null, version=1, deleted=0)
User(id=1094590409767661570, name=张雨琪, age=31, email=zjq@baomidou.com, managerId=1088248166370832385, createTime=2019-01-14T09:15:15, updateTime=null, version=1, deleted=0)
但是你想过滤的话
@Test
void selectMyOwn() {
// 查询全部,这时候把deleted为1的过滤了
userMapper.mySelectList(
Wrappers.<User>lambdaQuery()
.gt(User::getAge,18)
// 加上就过滤了
.eq(User::getDeleted,0)
)
.forEach(System.out::println);
}
自动填充
简介
有的项目有新增时间啊 修改时间啊 修改人啊啥的,每次都重复插入有点麻烦,虽然有些也是一个函数的事,,哎,~~~~但我就是玩儿~(不是,我就是懒
而且要是我就是要记录 是谁 在什么时间点动了数据库,这就玩(懒)不起来了..
还好,MP够懂Coder,你懒归你懒,清风拂山岗
实现
1.修改实体类
/** 创建时间 ,在插入时候填充*/
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
/** 修改时间 ,在更新时候填充*/
@TableField(fill = FieldFill.UPDATE)
private LocalDateTime updateTime;
2.新建处理器类
/**
* 我的元数据处理器
*
* @author 金聖聰
* @version v1.0
* @email jinshengcong@163.com
* @date Created in 2021/04/17 17:00
*/
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* 插入的时候的填充方法
*
* @param metaObject 元数据
* @return void 空
* @author 金聖聰
* @email jinshengcong@163.com
* Modification History:
* Date Author Description version
*--------------------------------------------------------*
* 2021/04/17 17:02 金聖聰 修改原因 1.0
*/
@Override
public void insertFill(MetaObject metaObject) {
// 3.3.0过期了 替代方法是 strictInsertFill
// setInsertFieldValByName("createTime", LocalDateTime.now(),metaObject);
// 等效于
// setFieldValByName("createTime", LocalDateTime.now(),metaObject);
strictInsertFill(metaObject,"createTime",LocalDateTime.class,LocalDateTime.now());
}
/**
* 更新时候的填充方法
* @param metaObject 元数据
* @return void 空
* @author 金聖聰
* @email jinshengcong@163.com
* Modification History:
* Date Author Description version
*--------------------------------------------------------*
* 2021/04/17 17:02 金聖聰 修改原因 1.0
*/
@Override
public void updateFill(MetaObject metaObject) {
// 3.3.0过期了 替代方法是 strictUpdateFill
// setUpdateFieldValByName("updateTime",LocalDateTime.now(),metaObject);
// 等效于
// setFieldValByName("updateTime",LocalDateTime.now(),metaObject);
strictUpdateFill(metaObject, "updateTime", LocalDateTime.class,LocalDateTime.now());
}
}
3.测试类
@Test
void insertAutoFilled() {
User user = new User();
user.setName("小李");
user.setAge(18);
// 自动填充了创建时间
int insert = userMapper.insert(user);
System.out.println("影响行数: " + insert);
}
@Test
void updateAutoFilled() {
User user = new User();
user.setId(1383349447410843650L);
user.setName("夹心");
user.setAge(16);
// 自动填充了更新时间
int insert = userMapper.updateById(user);
System.out.println("影响行数: " + insert);
}
自动填充优化
在处理器类中进行优化
@Override
public void insertFill(MetaObject metaObject) {
// 3.3.0过期了 替代方法是 strictInsertFill
// setInsertFieldValByName("createTime", LocalDateTime.now(),metaObject);
// 等效于
// setFieldValByName("createTime", LocalDateTime.now(),metaObject);
// 优化: 有没有这个属性,有的话才自动填充
boolean createTime = metaObject.hasSetter("createTime");
if (createTime) {
strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
}
}
当我更新的时候有设置好值,你就别帮我跟新,这么怎么设置呢
@Override
public void updateFill(MetaObject metaObject) {
// 3.3.0过期了 替代方法是 strictUpdateFill
// setUpdateFieldValByName("updateTime",LocalDateTime.now(),metaObject);
// 等效于
// setFieldValByName("updateTime",LocalDateTime.now(),metaObject);
// 优化: 只有这个为null的时候才进行自动填充
Object updateTime = getFieldValByName("updateTime", metaObject);
if (ObjectUtils.isEmpty(updateTime)) {
strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
}
测试类
@Test
void updateById() {
User user = new User();
// 更新我逻辑删掉的数据,英雄行数为0 更新失败
// user.setId(1087982257332887553L);
// 更新没删除的别人,就可以
user.setId(1383353200797118465L);
user.setAge(10);
// user.setUpdateTime(LocalDateTime.now().plusDays(1));
int i = userMapper.updateById(user);
System.out.println("影响行数: " + i);
}
乐观锁插件
简介
意图: 当要更新一条记录的时候,希望这条数据没有被别人更新过,是为了防止更新冲突的问题
应用场景:
一般是悲观锁和乐观锁
悲观锁是通过数据库的锁机制实现 ----多写,少读
乐观锁是通过表的版本号实现 ---写比较少的场景,多读的场景
实现原理
1.版本号
a) 取出记录时,获取当前的version
b) 更新这条记录时,带上这个version
c) 版本正确,更新成功,版本错误,更新失败