@TableLogic导致update失效

714 阅读4分钟

前言

1.为什么要使用TableLogic?

(1) 在某些业务需求场景下,删除数据需要采用逻辑删除而不是物理删除

(2) 方便以后数据审计、历史数据的分析、保证多表数据的完整性

然而,这一功能在某些情况下会导致更新操作失效。本文将详细讨论 @TableLogic 如何影响更新操作,并提供相应的解决方案。

开始

@TableLogic 是 MyBatis-Plus 提供的一种注解,用于标记逻辑删除字段。逻辑删除即在数据库中保留数据,只是通过修改特定字段(如 is_delete)的值来标记记录为已删除状态。

.....如何发现这个问题的?

....一天,产品经理突然宣布要将物理删除改成逻辑删除。我对屎山进行了大刀阔斧的改造,自信满满地认为一切都很顺利。

再一段时间后,在天气晴朗的日子中,我发现删除掉一条用户数据后,再进行添加该数据,发现不管添加几次,数据库中就是看不到新的记录。

“这一定是个小问题,”我心想。于是,我信心满满地开始排查 BUG,认为这不过是分分钟的事情。然而,时间一秒一秒地过去……

10分钟,没找到问题;

30分钟,依然没头绪;

1小时,依旧毫无进展。

................

................

直到我注意到了我实体类上的 is_delete 字段上多了个 @TableLogic 注解。

不对劲,很有可能问题出现在这里,我去查阅了各种资料。

果然,问题就是出现在这里。

原来是我同事将 is_delete 这个字段加入了 @TableLogic 注解,导致了更新操作不生效,所以在进行新增数据时始终无法添加。

问题解决了!

@TableName("syg.syg_believer")
@Data
public class Believer implements Serializable {
 
    private Long userId;

    private String  openId;
    
    private String level;
    
    .........

//    @TableLogic(delval = "1")
    private Integer isDelete;

}

在这个示例中,isDelete 字段被标记为逻辑删除字段。@TableLogic 注解告诉 MyBatis-Plus 在执行删除操作时,将该字段的值设置为 1 而不是物理删除记录。


由于is_delete 这个字段加入了 @TableLogic 注解,所以我在更新用户数据的时候,这个注解导致了updateById这个方法失效了,所以怎么添加数据都不会成功。

//信众存在并且处于删除状态
if (Objects.nonNull(believer) && believer.getIsDelete()==BELIEVER_DELETED){
    believer.setIsDelete(BELIEVER_NOT_DELETED);
    BeanUtils.copyProperties(addBelieverPO, believer);
    believer.setMerit(addBelieverPO.getMerit());
    believer.setRegTime(new Date());
    believer.setOpenId(String.valueOf(DEFAULT_OPENID));
    believer.setAge(age.getYears());
    believer.setUserId(sysUser.getUserId());
    //判断信众等级
    LevelEnums level = LevelEnums.getLevel(believer.getGrowth(), believer.getMerit());
    believer.setLevel(String.valueOf(level));

    if (!updateById(believer)){
        return AjaxResult.error(BELIEVER_ADD_ERROR);
    }
}

@TableLogic 是 MyBatis-Plus 提供的一种注解,用于标记逻辑删除字段。逻辑删除即在数据库中保留数据,只是通过修改特定字段(如 is_delete)的值来标记记录为已删除状态。

更新操作为何失效

使用 @TableLogic 注解后,当我们尝试更新记录时,MyBatis-Plus 会自动将逻辑删除字段加入 where 子句,以确保只操作未被逻辑删除的记录。如果记录已经被逻辑删除(如 is_delete = 1),那么更新操作将不会匹配到任何记录,从而导致更新不生效。如在这个示例中执行UpdateById的操作,对其他字段的设置忽略,只关心is_delete这个字段

UPDATE syg_believer SET age = #{age} (其它字段忽略....) WHERE id = #{userId} AND is_delete = 0;

如果 user_id 的记录 is_delete 为 1,则此更新操作不会生效。


解决方案

方案 1:通过 UpdateWrapper 手动指定更新逻辑删除字段
UpdateWrapper<Believer> updateWrapper = new UpdateWrapper<>();
updateWrapper.set("is_delete", 1).eq("user_id", userId);
userMapper.update(null, updateWrapper);
方案 2:自定义 SQL 更新
<update id="believerUpdateByUserId">
    UPDATE syg_believer
    SET is_delete = #{isDelete}
    WHERE user_id = #{userId}
</update>

结语

通过理解和使用 MyBatis-Plus 提供的 @TableLogic 注解,我们可以有效地实现逻辑删除,同时避免由于逻辑删除字段导致的更新操作失效问题。

为了避免类似的问题再次发生,建议大家在遇到更新操作不生效的情况时,除了排查常规原因外,也要注意检查是否有类似 @TableLogic 的注解影响了操作逻辑。这个小知识点可以帮助大家扩大排查范围,减少排查时间,提高工作效率。