多种插件
Mybatis-plus给我们提供了各种各样的插件,方便我们快捷开发。
一. 插件配置
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 配置分页插件, 针对 MySQL
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor()); // 阻止全表更新全表删除
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); // 乐观锁
return interceptor;
}
}
二. 分页插件(PaginationInnerInterceptor)
分页查询是自带Limit关键字
三. 防止全表更新和删除插件(BlockAttackInnerInterceptor)
这里仅模拟删除所有。全表更新是一样的。
四. 乐观锁插件(OptimisticLockerInnerInterceptor)
乐观锁插件会在我们设置version的值后,只更新与其version值对应的一次。修改一次后会自动+1
数据库字段与实体类都需要加上version字段。记得初始化为0
模拟并发场景,假设两个线程同时修改user的信息
@Test
void testVersion() throws InterruptedException {
User user1 = new User();
user1.setId(1);
User user2 = new User();
user2.setId(1);
Integer version = user1.selectById().getVersion();
CountDownLatch countDownLatch = new CountDownLatch(2);
new Thread(()->{
user1.setUsername("666");
user1.setVersion(version);
boolean flag = user1.updateById();
System.out.println("666是否执行:" + flag);
countDownLatch.countDown();
},"t1").start();
new Thread(()->{
user2.setUsername("777");
user2.setVersion(version);
boolean flag = user2.updateById();
System.out.println("777是否执行:" + flag);
countDownLatch.countDown();
},"t2").start();
countDownLatch.await();
}
结果为
只有一个完成修改。
自动填充数据
MyBatis-Plus 提供了一个便捷的自动填充功能,用于在插入或更新数据时自动填充某些字段,如创建时间、更新时间等。
一. 实现MetaObjectHandler接口
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject,"create_time", LocalDateTime.class, LocalDateTime.now());
this.setFieldValByName("update_time", LocalDateTime.now(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject,"update_time", LocalDateTime.class, LocalDateTime.now());
}
}
实体类添加@TableField注解
@Data
@Builder
@TableName("`user`")
@AllArgsConstructor
@RequiredArgsConstructor
public class User extends Model<User> {
@TableId(type = IdType.AUTO)
private Integer id;
private String username;
private String password;
private Boolean enabled;
@Version
private Integer version;
@TableLogic(value = "false",delval = "true")
private Boolean is_deleted;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime create_time;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime update_time;
}
二.测试
- 插入一条数据
@Test
void testAdd() {
User user = User.builder()
.username("999")
.password(encoder.encode("123456"))
.enabled(true)
.build();
user.insert();
}
测试结果
- 更新数据
@Test
void testUpdate(){
User user = User.builder()
.id(6)
.username("Coffee")
.build();
user.updateById();
}
SQL注入器
MyBatis-Plus 提供了灵活的机制来注入自定义的 SQL 方法,这通过 sqlInjector
全局配置实现。通过实现 ISqlInjector
接口或继承 AbstractSqlInjector
抽象类,你可以注入自定义的通用方法到 MyBatis 容器中。
一. 注册自定义方法
定义类继承AbstractMethod,重写方法
public class DeleteAll extends AbstractMethod {
=
protected DeleteAll(String methodName) {
super(methodName);
}
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
String sql = "update " + tableInfo.getTableName() + " set is_deleted = true";
String methodName = "deleteAll";
//1. 创建sqlSource, 通过sqlSource可以获取sql
SqlSource sqlSource = this.languageDriver.createSqlSource(configuration, sql, modelClass);
//2. 添加到mappedStatement中
return this.addUpdateMappedStatement(mapperClass,Boolean.class,methodName, sqlSource);
}
}
二. 创建sql注入器
将刚刚自定义的方法注入到注入器中.
继承AbstactSqlInjector类,重写getMethodList方法。
注意: 如果是实现AbstractSqlInjector类,将会导致Mybatis-plus自带的所有方法全部失效
@Component
public class MySglInject extends AbstractSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
List<AbstractMethod> methods = new ArrayList<>();
methods.add(new DeleteAll("deleteAll"));
return methods;
}
}
要想仅仅只是多出我们的自定义方法,需要继承DefaultSqlInject类,并且获取到父类的MethodList集合
@Component
public class MySglInject extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
methodList.add(new DeleteAll("deleteAll"));
return methodList;
}
}
三. Mapper层定义方法
在mapper层写入我们自定义的方法,必须和自定义的方法名保持一致。
@Mapper
public interface UserMapper extends BaseMapper<User> {
void deleteAll();
}
四. 测试
@Test
void testDeleteALLSQLInject(){
userMapper.deleteAll();
}