springBoot-MyBatis-Plus逻辑删除@TableLogic

前言:在开发过程中,如果在删除数据时,只是通过改变数据中某个字段的值,来达到逻辑删除的目的,但是又不想每次都手动对改字段进行设置,改如何实现;

1 MyBatis-Plus逻辑删除@TableLogic:

MyBatis-Plus 的 @TableLogic 注解是用于标记逻辑删除字段的注解,用于实现逻辑删除功能。并且开启之后使用MyBatis-Plus 自带的CRUD 在最终执行sql 时都会为其追加 一个数据正常的条件,
即: and 定义的逻辑删除字段 = 定义的正常值;

2 SpirngBoot MyBatis-Plus 实现:

2.1 引入 MyBatis-Plus 的包:

<dependency>
   <groupId>com.baomidougroupId>
    <artifactId>mybatis-plus-boot-starterartifactId>
 
dependency>

<dependency>
    <groupId>mysqlgroupId>
    <artifactId>mysql-connector-javaartifactId>
dependency>

2.2 在表和实体类中需要增加逻辑删除字段 :

sql:

ALTER TABLE `user`
ADD COLUMN `deleted` tinyint(1) not  NULL DEFAULT 0 COMMENT '是否删除(1-删除;0-未删除)';

实体:

/**
* 状态[0:未删除,1:删除]
*/
@TableLogic
private Integer deleted;

2.3 为了看到效果,对日志输出级别进行调整:

2.3.1 首先定义mybatisPlus 输出sql 到控制台的类:

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

2.3.2 然后调整日志输出级别为debug:

logging:
  level:
    root: debug

  • log-impl: 在 MyBatis Plus 中,可以通过配置日志实现类来控制 SQL 语句是否输出到控制台。可以使用 org.apache.ibatis.logging.stdout.StdOutImpl 作为日志实现类,这是 MyBatis 自带的一个日志实现类,用于将日志信息输出到标准输出流中(也就是控制台);

  • 在 Spring Boot 中,logging.level.root 是用来配置整个应用程序的默认日志级别。如果没有为特定的日志类别定义日志级别,则该类别将使用默认的日志级别。默认情况下,logging.level.root 的值为 INFO,也就是说,如果没有为特定的日志类别指定日志级别,则该类别将使用 INFO 级别的日志输出。这意味着,只有 INFO 级别及以上的日志信息才会被输出,而低于 INFO 级别的日志信息将被忽略。

  • StdOutImpl 只会将日志输出到控制台而不输出到日志文件中;

  • 控制台输出的日志级别和 MyBatis Plus 执行的 SQL 语句是否输出到控制台是分开控制的。即使开启了控制台日志输出,也需要设置对应的日志级别才能在控制台上看到 SQL 语句的输出;

  • 需要注意的是,开启 SQL 输出会泄漏 SQL 语句,因此建议在生产环境中关闭 SQL 输出或者使用安全的日志配置方式。同时,SQL 输出的数量和内容可能会对性能和安全性产生影响,需要根据具体情况进行权衡和优化。

3 调试和验证:

3.1 定义好User 对应的Maper,service;
3.2 测试代码:

public User getUser(String userId) {
     User user1 = this.getById(userId);
     System.out.println("====this.getById===");
     LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
     wrapper.eq(User::getId,userId);
     User user2 = this.getOne(wrapper);
     System.out.println("====this.query one wrapper ===");
     List<User>users = this.list(wrapper);
     System.out.println("====this.query list wrapper ===");
     LambdaUpdateWrapper<User> wrapper1 = new LambdaUpdateWrapper<>();
     wrapper1.eq(User::getId,userId);
     wrapper1.set(User::getName,"test");
     this.update(wrapper1);
     System.out.println("====this.update wrapper ===");
     LambdaQueryWrapper<User> wrapperDel = new LambdaQueryWrapper<>();
     wrapperDel.eq(User::getName,user1.getName());
     this.remove(wrapperDel);
     System.out.println("====this.delete wrapper ===");
     // 自定义sql
     User user3 =  userMapper.getUserOne(userId);
     System.out.println("====this.query one xml ===");
     return user2;
 }

自定义sql:

<select id="getUserOne" resultType="com.example.uidconsumer.entity.User">
   select * from user where id =#{userId}
select>

3.3 测试结果:

c.e.u.mapper.UserMapper.selectById       : ==>  Preparing: SELECT id,name,age,create_by,create_time,update_by,update_time,status,deleted FROM user WHERE id=? AND deleted=0
 c.e.u.mapper.UserMapper.selectById       : ==> Parameters: 167081924395884544(String)
c.e.u.mapper.UserMapper.selectById       : <==      Total: 1
====this.getById===
c.e.u.mapper.UserMapper.selectOne        : ==>  Preparing: SELECT id,name,age,create_by,create_time,update_by,update_time,status,deleted FROM user WHERE deleted=0 AND (id = ?)
c.e.u.mapper.UserMapper.selectOne        : ==> Parameters: 167081924395884544(String)
c.e.u.mapper.UserMapper.selectOne        : <==      Total: 1
====this.query one wrapper ===
c.e.u.mapper.UserMapper.selectList       : ==>  Preparing: SELECT id,name,age,create_by,create_time,update_by,update_time,status,deleted FROM user WHERE deleted=0 AND (id = ?)
c.e.u.mapper.UserMapper.selectList       : ==> Parameters: 167081924395884544(String)
c.e.u.mapper.UserMapper.selectList       : <==      Total: 1
====this.query list wrapper ===
c.e.u.mapper.UserMapper.update           : ==>  Preparing: UPDATE user SET name=? WHERE deleted=0 AND (id = ?)
c.e.u.mapper.UserMapper.update           : ==> Parameters: test(String), 167081924395884544(String)
c.e.u.mapper.UserMapper.update           : <==    Updates: 0
====this.update wrapper ===
c.e.u.mapper.UserMapper.delete           : ==>  Preparing: UPDATE user SET deleted=1 WHERE deleted=0 AND (name = ?)
c.e.u.mapper.UserMapper.delete           : ==> Parameters: test(String)
c.e.u.mapper.UserMapper.delete           : <==    Updates: 1
====this.delete wrapper ===
### 
c.e.u.mapper.UserMapper.getUserOne       : ==>  Preparing: select * from user where id =?
c.e.u.mapper.UserMapper.getUserOne       : ==> Parameters: 167081924395884544(String)
c.e.u.mapper.UserMapper.getUserOne       : <==      Total: 1
====this.query one xml ===

从测试结果可以看到:

  • 使用MybatisPlus 自带的crud 方法其最终执行的sql 都追加了逻辑删除的字段,也即本例中的deleted=0;
  • 对于自定义的sql 语句,进行的查询是没有追加逻辑删除的字段,这是因为逻辑删除只对自动注入的 sql 起效(自动注入sql 解释见文中的扩展 4.2 小节);

4 扩展:

4.1 日志系统的输出级别:
在日志系统中,常见的日志级别按照从高到低的顺序包括:

  • ERROR 错误级别:表示严重的错误事件、或者系统不可用事件。
  • WARN 警告级别:表示潜在的错误事件、或者不符合预期的事件。
  • INFO 信息级别:表示普通的操作事件、例如用户登录、网络连接等。
  • DEBUG 调试级别:表示详细的操作信息,通常用于开发和测试环境。
  • TRACE 追踪级别:表示非常详细的操作信息,通常用于故障排除和问题解决。

在配置日志输出时,可以为每个类别指定不同的日志级别,例如:

logging:
  level:
    com.example.service: DEBUG
    com.example.dao: INFO
    org.springframework: WARN
 

4.2 MyBatis Plus 自动注入的 sql :
MyBatis Plus 自动注入的 SQL 是指使用 MyBatis Plus 提供的通用方法进行数据库操作时,MyBatis Plus 会自动填充一些查询条件;也即我们不能手写sql,需要使用MyBatis Plus 提供的方法进行CRUD操作。

4.3 @TableLogic 注解的作用:
@TableLogic 注解是用于标记一个字段为逻辑删除字段,被标记的字段的值为逻辑删除字段的值时,会被视为空,表示该记录被逻辑删除。在使用 MyBatis Plus 进行操作时,可以通过设置全局的逻辑删除属性配置来开启逻辑删除功能。

但是,@TableLogic 注解只对 MyBatis Plus 自动注入的 SQL 生效,不针对手写 SQL 生效,这是因为逻辑删除的原理是在 MyBatis Plus 自动注入的 SQL 中做了特殊处理,实现了逻辑删除功能。而手写 SQL 是无法进行这种处理的,因此 @TableLogic 注解对手写 SQL 没有作用。

需要注意的是,通过手写 SQL 进行更新或删除操作时,需要手动设置逻辑删除字段的值为逻辑删除值,才能实现逻辑删除功能。具体实现上,可以通过在 SQL 中使用占位符的方式将逻辑删除字段的值设置为逻辑删除值,例如 UPDATE table SET deleted = ? where id = ?,然后在执行 SQL 语句时传入逻辑删除值和具体的 id 值,从而实现逻辑删除操作。

总的来说,@TableLogic 注解只能对 MyBatis Plus 自动注入的 SQL 生效,不能对手写 SQL 生效,如果需要使用逻辑删除功能,就需要选用 MyBatis Plus 的自动注入 SQL 功能来实现。同时,在使用手写 SQL 进行更新或删除操作时,需要手动设置逻辑删除字段的值为逻辑删除值,从而实现逻辑删除的功能。

5 参考:

5.1 Mybatis-plus 逻辑删除;

你可能感兴趣的:(db数据库,java工具篇,#,spring-boot,mybatis,spring,boot,java)