mybitis-puls FieldStrategy 字段策略 排障记录

错误描述

一个新的应用在更新表(mysql)数据时,出现异常。

异常日志:

java.sql.SQLIntegrityConstraintViolationException: Column 'total_delivery_quantity_of_current_month' cannot be null

即有null值 对表进行更新 或插入,而该字段在mysql的定义是 非null。

问题已经定位,开始定位问题产生的原因:

找到执行异常的类:

  if (org.apache.commons.lang3.StringUtils.isBlank(updateLastDeliveryCommand.getCode())) {
            throw new ServiceException("编码不能为空!");
        }
        LambdaUpdateWrapper<CrmDeliveryQuantityInfoEntity> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(CrmDeliveryQuantityInfoEntity::getDeliveryQuantityRatioOf7Days, updateLastDeliveryCommand.getDeliveryQuantityRatioOf7Days());
        wrapper.set(CrmDeliveryQuantityInfoEntity::getTotalDeliveryQuantityOfCurrentMonth, updateLastDeliveryCommand.getTotalDeliveryQuantityOfCurrentMonth());
        wrapper.set(CrmDeliveryQuantityInfoEntity::getTotalDeliveryQuantityOfPreviousMonth, updateLastDeliveryCommand.getTotalDeliveryQuantityOfPreviousMonth());
        wrapper.set(CrmDeliveryQuantityInfoEntity::getDayAvgDeliveryQuantityOfPreviousMonth, updateLastDeliveryCommand.getDayAvgDeliveryQuantityOfPreviousMonth());
        wrapper.set(CrmDeliveryQuantityInfoEntity::getMonthDeliveryQuantityOfSiteRatio, updateLastDeliveryCommand.getMonthDeliveryQuantityOfSiteRatio());
        wrapper.set(CrmDeliveryQuantityInfoEntity::getMonthDeliveryQuantityOfManagerAreaRatio, updateLastDeliveryCommand.getMonthDeliveryQuantityOfManagerAreaRatio());
        wrapper.set(CrmDeliveryQuantityInfoEntity::getMonthDeliveryQuantityOfTransferRatio, updateLastDeliveryCommand.getMonthDeliveryQuantityOfTransferRatio());
        wrapper.set(CrmDeliveryQuantityInfoEntity::getTotalDeliveryQuantityOf7Days, updateLastDeliveryCommand.getTotalDeliveryQuantityOf7Days());
        wrapper.set(CrmDeliveryQuantityInfoEntity::getDeliveryRateOfDecline, updateLastDeliveryCommand.getDeliveryRateOfDecline());
        wrapper.eq(CrmDeliveryQuantityInfoEntity::getCode, updateLastDeliveryCommand.getCode());
        update(wrapper);
        
        

使用mybatis-plus 的 update 进行更新,其中空字段是 deliveryRateOfDecline。

解决思路

1、 在wrapper.set 的时候进行非空判定,如果是null, 不进行set。

但是这种做法又臭又长。

2、mysql-plus 本身应该有类似  Mapper.updateByPrimaryKeySelective() 的API,

在生成sql 语句时,只拼接非空的参数。

选用第二种方法,开始寻找方案。通过mybatis-plus 的主站 注解 | MyBatis-Plus

FieldStrategy(opens new window)

描述
IGNORED忽略判断
NOT_NULL非 NULL 判断
NOT_EMPTY非空判断(只对字符串类型字段,其他类型字段依然为非 NULL 判断)
DEFAULT追随全局配置
NEVER不加入SQL
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface TableField {
    String value() default "";

    boolean exist() default true;

    String condition() default "";

    String update() default "";

    FieldStrategy insertStrategy() default FieldStrategy.DEFAULT;

    FieldStrategy updateStrategy() default FieldStrategy.DEFAULT;

    FieldStrategy whereStrategy() default FieldStrategy.DEFAULT;

    FieldFill fill() default FieldFill.DEFAULT;

    boolean select() default true;

    boolean keepGlobalFormat() default false;

    String property() default "";

    JdbcType jdbcType() default JdbcType.UNDEFINED;

    Class<? extends TypeHandler> typeHandler() default UnknownTypeHandler.class;

    boolean javaType() default false;

    String numericScale() default "";
}
 @TableField(value = "delivery_rate_of_decline" , updateStrategy =   FieldStrategy.NOT_EMPTY)
    private BigDecimal deliveryRateOfDecline;

该注解可以直接配置字段上,在执行更新操作时,忽略 null 或 空 字符串。

配置完成后,进行调试。发现确实能忽略null 。但是产生了新的,问题我不想在每个字段上都增加配置,这个工作量也很大。还时想找到 Mapper.updateByPrimaryKeySelective() 的替代方案。

在csdn 发现一篇新的文章 Mybatis-Plus字段策略FieldStrategy详解_斗者_2013的博客-CSDN博客_fieldstrategy

所有字段 更新策略 默认是  DEFAULT,即跟随全局配置,而全局配置默认是 NOT_NULL。

那按理来说是在使用 service.update 的时候应该会对 null 的字段进行过滤。

仔细核对后发现,文章里面使用的都是 updateById,而不是 update ,增加单元测试进行尝试

         // code是主键,所有使用code进行更新
        CrmDeliveryQuantityInfoEntity entity = new CrmDeliveryQuantityInfoEntity();
        entity.setCode(updateLastDeliveryCommand.getCode());
        entity.setDeliveryRateOfDecline(null);
        entity.setDeliveryQuantityRatioOf7Days(new BigDecimal(22));
        updateById(entity);

生成的sql 语句如下

==>  Preparing: UPDATE crm_delivery_quantity_info SET delivery_quantity_ratio_of_7_days=? WHERE code=?
[2022-12-13 20:04:22.499] 
DEBUG   ==> Parameters: 22(BigDecimal), DM221213008001(String)

成功~~~,但现在仍然不知道为什么update 和 updateById 在执行上有啥区别

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值