MyBatis-Plus 进阶学习笔记记录
-
- 一、 MyBatis Plus 七大功能
- 0. 数据准备
- 1. 逻辑删除
- 2. 自动填充
-
- 2.1 优化1 自动填充 有的类没有更新和创建时间字段
- 2.2 优化2 自己设置时间时填充自己设置的,不设置时自动填充
- 3. 乐观锁插件 注:wrapper不能服用
- 4. 性能分析插件
-
- 4.1 PerformanceInterceptor 3.2.0版本被废除
- 4.2 p6spy 使用
- 5. 多租户SQL解析器
- 6. 动态表名SQL解析器
- 7. SQL注入器
一、 MyBatis Plus 七大功能
0. 数据准备
数据库表:
CREATE TABLE `user` (
`id` bigint(20) 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已删除)',
PRIMARY KEY (`id`),
KEY `manager_fk` (`manager_id`),
CONSTRAINT `manager_fk` FOREIGN KEY (`manager_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
实体类:
@Data
@Accessors(chain = true)
@TableName("user")
public class User extends Model<User> implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id",type = IdType.AUTO)
private Long id;
@TableField("name")
private String name;
@TableField("age")
private Integer age;
@TableField("email")
private String email;
@TableField("manager_id")
private Long manageId;
@TableField("create_time")
private LocalDateTime createTime;
@TableField("update_time")
private LocalDateTime updateTime;
@TableField("version")
private Integer version;
@TableLogic
@TableField("deleted")
private Integer deleted;
}
xml配置:
server:
port: 8088
spring:
# 配置数据源信息
datasource:
# 配置连接数据库信息
#本地地址:“127.0.0.1”
#数据库名称:“db2”
url: jdbc:mysql://127.0.0.1:3306/db2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
#数据库账户
username: root
#数据库密码
password: root
mybatis-plus:
global-config:
db-config:
#逻辑删除字段
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
1. 逻辑删除
逻辑删除语句:
int i = userMapper.deleteById(2);
System.out.println(i);
真实执行语句:
==> Preparing: UPDATE user SET deleted=1 WHERE id=? AND deleted=0
==> Parameters: 2(Integer)
<== Updates: 1
实际未删除,只修改删除字段的值
这时候如果执行查询语句,则只会展示逻辑删除为0的字段记录:
List<User> list = userMapper.selectList(null);
list.forEach(System.out::println);
虽然库中有三条记录但是有两条删除字段为1,则list中只展示一条
@TableField(value = "deleted",select = false)
private Integer deleted;
select=false; 查询语句将不出现deleted字段
2. 自动填充
自动填充 创建和 更新时间
@TableField(value = "create_time",fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(value = "update_time",fill = FieldFill.UPDATE)
private LocalDateTime updateTime;
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
System.out.println("==============insertFill");
setFieldValByName("createTime", LocalDateTime.now(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
setFieldValByName("updateTime", LocalDateTime.now(),metaObject);
System.out.println("==============updateFill");
}
}
2.1 优化1 自动填充 有的类没有更新和创建时间字段
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
boolean hasSetter = metaObject.hasSetter("createTime");
if (hasSetter){
System.out.println("==============insertFill");
setFieldValByName("createTime", LocalDateTime.now(),metaObject);
}
}
@Override
public void updateFill(MetaObject metaObject) {
boolean hasSetter = metaObject.hasSetter("updateTime");
if (hasSetter){
setFieldValByName("updateTime", LocalDateTime.now(),metaObject);
System.out.println("==============updateFill");
}
}
}
2.2 优化2 自己设置时间时填充自己设置的,不设置时自动填充
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
Object createTime = getFieldValByName("createTime", metaObject);
if (ObjectUtils.isNull(createTime)){
boolean hasSetter = metaObject.hasSetter("createTime");
if (hasSetter){
System.out.println("==============insertFill");
setFieldValByName("createTime", LocalDateTime.now(),metaObject);
}
}
}
@Override
public void updateFill(MetaObject metaObject) {
Object updateTime = getFieldValByName("updateTime", metaObject);
if (ObjectUtils.isNull(updateTime)){
boolean hasSetter = metaObject.hasSetter("updateTime");
if (hasSetter){
setFieldValByName("updateTime", LocalDateTime.now(),metaObject);
System.out.println("==============updateFill");
}
}
}
}
3. 乐观锁插件 注:wrapper不能服用
乐观锁和悲观锁是在并发编程中用来处理资源竞争和保证数据一致性的两种不同策略。它们各自适用于不同的使用场景:
乐观锁:
乐观锁的核心思想是假设并发访问的操作不会发生冲突,因此在读取资源时不会进行加锁,而是在更新资源时进行冲突检测。如果发现有其他线程已经对资源进行修改,则放弃当前操作或尝试重新执行。
使用场景:
并发写入操作较少的情况下,冲突发生的概率较低。
数据库表中的数据很少被修改,在持续时间较短的事务中进行读取操作。
适合处理乐观并发控制机制,如版本号或时间戳等。
悲观锁:
悲观锁的核心思想是假设并发访问的操作会发生冲突,因此在访问资源之前会进行加锁操作,确保在整个操作期间资源不被其他线程修改。
使用场景:
并发写入操作较多的情况下,冲突发生的概率较高。
数据库表中的数据经常被修改,在持续时间较长的事务中进行读取操作。
适合使用数据库的行级锁、表级锁或者分布式锁等来实现。
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
实体类字段:
@TableField("version")
@Version
private Integer version;
测试:
int version=2;
User user = new User();
user.setId(1683667832465985538L);
user.setEmail("[email protected]");
user.setName("lwx");
user.setVersion(version);
int update = userMapper.updateById(user);
System.out.println(update);
4. 性能分析插件
4.1 PerformanceInterceptor 3.2.0版本被废除
@Bean
@Profile({"dev","test"})
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor interceptor = new PerformanceInterceptor();
interceptor.setFormat(true);
interceptor.setMaxTime(500);
performanceInterceptor.setFormat(true);
return interceptor;
}
4.2 p6spy 使用
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>3.8.7</version>
</dependency>
#3.2.1以上使用
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
#3.2.1以下使用或者不配置
#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 设置 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
#driverlist=org.h2.Driver
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2
server:
port: 8088
spring:
# 配置数据源信息
datasource:
# 配置连接数据库信息
#本地地址:“127.0.0.1”
#数据库名称:“db2”
driver-class-name: com.p6spy.engine.spy.P6SpyDriver
url: jdbc:p6spy:mysql://localhost:3306/db2?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
#数据库账户
username: root
#数据库密码
password: root
mybatis-plus:
global-config:
db-config:
#逻辑删除字段
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
5. 多租户SQL解析器
6. 动态表名SQL解析器
7. SQL注入器