需求:
需求:将SQL Server库表中,某一个Date类型字段更新为null 环境:
Microsoft SQL Server 2016 (SP2-CU17) (KB5001092) - 13.0.5888.11 (X64)
Mar 19 2021 19:41:38
Copyright (c) Microsoft Corporation
Enterprise Edition: Core-based Licensing (64-bit) on Windows Server 2016 Datacenter 10.0 <X64> (Build 14393: ) (Hypervisor)
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
官网文档:
选择:
- 官网三种解决方案各有优缺点
方案一: 全局设置可能会影响其他功能,这种方案不考虑,兼容性差,危险性极高。试想如果你把全局设置改了,项目经理没有做代码审查直接上线了(特别是小团队,人人都有管理员权限),运行期间出现很多数据丢失或异常,排查问题发现是你把MyBatis-Plus全局空处理策略设为了启用。接下来就是数据恢复工作,严重点的要整个团队一起恢复数据,对于没有做数据库备份和系统操作日志记录等安全措施的项目,简直就是地狱。 方案二: 限制粒度降低到字段,看情况考虑是否使用,可维护性较差。对于独立模块,改完配置后不会影响现有功能,且以后不会被其他模块引用,这种情况下可以使用,但这个比较隐藏配置可能会给后面的开发和维护引入问题。 方案三: 最优解,只影响这一个操作。
实现
@Data
@TableName("NOTICE_RECEIPT")
public class NoticeReceipt {
@TableId(type = IdType.AUTO)
private Integer id;
private String stockNumber;
@TableField(updateStrategy = FieldStrategy.IGNORED)
private Date validityPeriod;
@TableLogic(value = "0", delval = "1")
private Integer isDelete;
}
@Service
public class NoticeReceiptServiceImpl extends ServiceImpl<NoticeReceiptMapper, NoticeReceipt> implements NoticeReceiptService {
@Override
public R update(NoticeReceiptVO noticeReceiptVO) {
NoticeReceipt noticeReceipt = new NoticeReceipt();
noticeReceipt.setId(23);
noticeReceipt.setStockNumber("SN20211001");
noticeReceipt.setValidityPeriod(null);
updateById(noticeReceipt);
}
}
MyBatis Log:
UPDATE NOTICE_RECEIPT SET stock_number='SN20211001', validity_period=null WHERE id=23 AND is_delete=0;
异常:
org.apache.ibatis.exceptions.PersistenceException:
### Error updating database. Cause: com.microsoft.sqlserver.jdbc.SQLServerException: 不允许从数据类型 varbinary 到 date 的隐式转换。请使用 CONVERT 函数来运行此查询。
@Override
public R update(NoticeReceiptVO noticeReceiptVO) {
NoticeReceipt noticeReceipt = new NoticeReceipt();
noticeReceipt.setId(23);
noticeReceipt.setStockNumber("SN20211001");
noticeReceipt.setValidityPeriod(null);
baseMapper.update(
noticeReceipt,
Wrappers.<NoticeReceipt>lambdaUpdate()
.set(NoticeReceipt::getValidityPeriod, noticeReceipt.getValidityPeriod())
.eq(NoticeReceipt::getId, noticeReceipt.getId())
);
}
MyBatis Log:
UPDATE NOTICE_RECEIPT SET stock_number='SN20211001', validity_period=null, validity_period=null WHERE id=23 AND is_delete=0;
和直接update没什么区别,依然报类型转换异常。
- SQL方案实现(可行方案)
看来锅不在MyBatis-Plus,可能出在MyBatis底层类型转换上,没招了,下下策自己手写SQL,直接将null写死,问题解决了,但是没有发现问题原因,后续如果有更好的方案再补上。
<update id="cusUpdate">
UPDATE YUNYAN_NOTICE_RECEIPT
SET stock_number = #{noticeReceipt.stockNumber},
<choose>
<when test="noticeReceipt.validityPeriod == null">
validity_period = NULL,
</when>
<otherwise>
validity_period = #{noticeReceipt.validityPeriod},
</otherwise>
</choose>
WHERE
is_delete = 0 AND id = #{noticeReceipt.id}
</update>
|