六、MyBatisPlus逻辑删除
6.1 逻辑删除概念
在实际开发中,由于数据十分重要,为了避免误删除数据导致数据无法找回,我们往往不会使用物理删除,即从数据库中直接删除数据。而是采用逻辑删除的方式,即不会真正在数据库删除数据,而是通过一个变量代表它被删除。
deleted属性代表该数据是否删除,0代表未删除,1代表已删除。此时增删改查的Sql语句发生变化:
- 插入: 不作限制
- 查找: 追加where条件过滤掉已删除数据。
- 更新: 追加where条件防止更新到已删除数据。
- 删除: 转变为更新
例如:
- 删除:
update user set deleted=1 where id = 1 and deleted=0
- 查找:
select id,name,deleted from user where deleted=0
6.2 逻辑删除使用
1、在配置文件配置逻辑删除
# mybatis-plus相关配置 mybatis-plus: # 全局配置 global-config: db-config: # 全局逻辑删除的字段名 logic-delete-field: deleted # 逻辑已删除值(默认为 1) logic-delete-value: 1 # 逻辑未删除值(默认为 0) logic-not-delete-value: 0
2、修改实体类,添加逻辑删除属性
@Data @AllArgsConstructor @NoArgsConstructor @TableName("tb_user") public class User extends Model<User> { @TableId(value = "id",type = IdType.AUTO) public Integer UserId; @TableField("username") public String userName; @TableField("sex") public String userSex; @TableField("address") public String userAddress; @TableField("account") public Integer userAccount; @Version private Integer version; /*逻辑删除*/ @TableLogic private Integer deleted; }
3、修改数据库表,添加一列整型deleted字段并设置默认值为0
4、测试删除和查询方法,会看到删除时将deleted字段变为1,查询时添加条件deleted=0
@Test public void testDelete() { User user = new User(); user.deleteById(23); }
==> Preparing: UPDATE tb_user SET deleted=1 WHERE id=? AND deleted=0 ==> Parameters: 23(Integer) <== Updates: 1
bug:
Caused by: org.yaml.snakeyaml.error.YAMLException: java.nio.charset.MalformedInputException: Input length = 1 at org.yaml.snakeyaml.reader.StreamReader.update(StreamReader.java:218) at org.yaml.snakeyaml.reader.StreamReader.ensureEnoughData(StreamReader.java:176) at org.yaml.snakeyaml.reader.StreamReader.ensureEnoughData(StreamReader.java:171) at org.yaml.snakeyaml.reader.StreamReader.peek(StreamReader.java:126) at org.yaml.snakeyaml.scanner.ScannerImpl.scanToNextToken(ScannerImpl.java:1177) at org.yaml.snakeyaml.scanner.ScannerImpl.fetchMoreTokens(ScannerImpl.java:287) at org.yaml.snakeyaml.scanner.ScannerImpl.checkToken(ScannerImpl.java:227) at org.yaml.snakeyaml.parser.ParserImpl$ParseImplicitDocumentStart.produce(ParserImpl.java:195) at org.yaml.snakeyaml.parser.ParserImpl.peekEvent(ParserImpl.java:158) at org.yaml.snakeyaml.parser.ParserImpl.checkEvent(ParserImpl.java:148) at org.yaml.snakeyaml.composer.Composer.checkNode(Composer.java:72) at org.yaml.snakeyaml.constructor.BaseConstructor.checkData(BaseConstructor.java:114) at org.yaml.snakeyaml.Yaml$1.hasNext(Yaml.java:543) at org.springframework.beans.factory.config.YamlProcessor.process(YamlProcessor.java:160) at org.springframework.beans.factory.config.YamlProcessor.process(YamlProcessor.java:134) at org.springframework.boot.env.OriginTrackedYamlLoader.load(OriginTrackedYamlLoader.java:75) at org.springframework.boot.env.YamlPropertySourceLoader.load(YamlPropertySourceLoader.java:50) at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.loadDocuments(ConfigFileApplicationListener.java:562) at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.load(ConfigFileApplicationListener.java:518) ... 37 common frames omitted Caused by: java.nio.charset.MalformedInputException: Input length = 1
这里要将编码格式设置为utf-8,然后再删除yml配置文件,再重新写一个yml。
七、MyBatisPlus扩展
7.1 自动填充
由于有了逻辑删除字段,那么向数据库插入数据时候,都需要设置deleted=0,而每次插入数据时都要设置该值十分繁琐,于是MyBatisPlus提供了自动填充功能。
1、为实体类的自动填充字段添加@TableField
@TableLogic // 自动填充字段 @TableField(fill = FieldFill.INSERT) private Integer deleted;
填充策略:
值 | 描述 |
DEFAULT | 默认不处理 |
INSERT | 插入操作填充字段 |
UPDATE | 更新操作填充字段 |
INSERT_UPDATE | 插入操作和更新操作均填充字段 |
2、自定义填充类实现MetaObjectHandler接口
package com.zj.meta; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component; @Component public class MyMetaObjectHandler implements MetaObjectHandler { /* 插入时填充逻辑 * metaObject 元对象 * */ @Override public void insertFill(MetaObject metaObject) { /* 参数1:填充字段名 * 参数2:参数值 * 参数3:元对象*/ this.setFieldValByName("deleted",0,metaObject); } @Override public void updateFill(MetaObject metaObject) { } }
3、测试插入数据
@Test public void testAdd() { User user = new User(); user.setUserName("小刚"); user.setUserAddress("淄博市"); user.setUserSex("男"); user.setUserAccount(4000); user.insert(); }
==> Preparing: INSERT INTO tb_user ( username, sex, address, account, deleted ) VALUES ( ?, ?, ?, ?, ? ) ==> Parameters: 小刚(String), 男(String), 淄博市(String), 4000(Integer), 0(Integer) <== Updates: 1: 1
在插入数据的时候,如果将数据库的deleted字段设置默认值为0的话,其实不需要使用mybatisplus的自动填充,因为在添加数据的时候自动就赋值为0了。
7.2 SQL注入器
MyBatisPlus方法是有限的,我们可以使用SQL注入器自定义全局方法,注入到全局中,这样所有的Mapper类都能使用该方法,接下来我们自定义一个deleteAll方法。
1、创建注入方法类,继承AbstractMethod
public class DeleteAll extends AbstractMethod { @Override public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) { //1.定义sql语句 String sql = "delete from "+tableInfo.getTableName(); //2.定义方法名 String methodName = "deleteAll"; //3.构建sqlSource对象,负责将sql传递到数据库 SqlSource sqlSource = this.languageDriver.createSqlSource(this.configuration, sql, modelClass); //4.构建删除方法 return this.addDeleteMappedStatement(mapperClass,methodName,sqlSource); } }
2、创建SQL自动注入器,继承AbstractSqlInjector
@Component public class MySqlInject extends AbstractSqlInjector { //注入自定义方法集合 @Override public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) { ArrayList<AbstractMethod> abstractMethods = new ArrayList<>(); abstractMethods.add(new DeleteAll()); return abstractMethods; } }
3、注销防止全表更新与删除插件
4、在Mapper接口中定义deleteAll方法
public interface UserMapper extends BaseMapper<User> { void deleteAll(); }
5、测试deleteAll方法,测试的时候不能使用AR模式,因为该方法不存在User类中,而是自定义的。
@Test public void testDeleteAll() { userMapper.deleteAll(); }
7.3 代码生成器
如果不想手动编写实体类等文件,MyBaitsPlus提供了代码生成器,它可以读取数据库的表信息,生成MyBaitsPlus代码供我们使用,之前我们学过MyBatis的代码生成器MyBatis Generator,这二者的区别是:
- MBG基于xml文件配置的,MyBaitsPlus代码生成器是基于Java代码配置的。
- MBG可生成实体类、Mapper接口、Mapper映射文件;MyBaitsPlus代码生成器可生成实体类、Mapper接口、Mapper映射文件、Service类、Controller类
1、添加代码生成器所需的依赖
<!-- MyBatisPlus代码生成器 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.5.1</version> </dependency> <!-- MyBatisPlus代码生成器需要的模板引擎 --> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>2.2</version> </dependency>
2、编写代码生成器
package com.zj.Generator; import com.baomidou.mybatisplus.generator.FastAutoGenerator; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; public class MyGenerator { public static void main(String[] args) { FastAutoGenerator.create("jdbc:mysql:///mybatis", "root", "123456") // 全局配置 .globalConfig(builder -> { builder.author("zhangjin") // 设置作者 .commentDate("MM-dd") // 注释日期格式 .outputDir(System.getProperty("user.dir") + "/src/main/java") // 指定输出目录 .fileOverride(); //覆盖文件 }) // 包配置 .packageConfig(builder -> { builder.parent("com.zj") // 包名前缀 .entity("pojo") //实体类包名 .mapper("mapper") //mapper接口包名 .service("service") //service包名 .controller("controller") //controller包名 .xml("mapper"); //映射文件包名 }) // 策略配置 .strategyConfig(builder -> { builder.addInclude("tb_user") // 设置需要生成的表名,可以有多个 .addTablePrefix("tb_") // 设置表名前缀 .entityBuilder() // 开始实体类配置 .enableLombok() // 开启lombok模型 .naming(NamingStrategy.underline_to_camel) //表名下划线转驼峰 .columnNaming(NamingStrategy.underline_to_camel);//列名下划线转驼峰 }) .execute(); } }
3、运行代码生成器即可生成代码
7.4 MybatisX生成代码
MybatisX是一款基于IDEA的快速开发插件,为效率而生。
安装方法:打开 IDEA,进入 File -> Settings -> Plugins -> Marketplace,输入 mybatisx
搜索并安装。
1、在IDEA中连接数据库
2、如下操作可以根据数据库表生成Mybaits代码
7.5 MybatisX生成映射配置、代码跳转
1、在Mapper接口中编写方法
public interface StudentMapper extends BaseMapper<Student> { List<Student> selectAllBySname(String sname); }
2、如下操作即可在映射文件中自动生成映射配置
代码跳转
点击Mapper接口或映射文件前的小鸟图案,即可快速在Mapper接口与映射文件间跳转