公司持久层框架使用的是Mybatis增强版:Mybatis-Plus,再一次做更新操作时,报了一个错误,由于隔得时间太久,代码也已经进行过改动,所以只有采用其它方式重现一下。
首先新建一个表,很简单没什么说的: 新建一个实体类:
package com.aecc.smart.fire.server.entity; import com.baomidou.mybatisplus.annotations.TableField; import com.baomidou.mybatisplus.annotations.TableName; import lombok.Data; import java.io.Serializable; @Data @TableName("em_test") public class EmTest implements Serializable { private static final long serialVersionUID = 1L; private Long id; @TableField("name") private String name; @TableField("age") private int age; }然后创建空的service、serviceImpl、mapper:
public interface EmTestService extends IService<EmTest> { } @Service public class EmTestServiceImpl extends ServiceImpl<EmTestMapper, EmTest> implements EmTestService { } public interface EmTestMapper extends BaseMapper<EmTest> { }新建测试类:
package com.aecc.smart.fire.server; import com.aecc.smart.fire.server.entity.EmTest; import com.aecc.smart.fire.server.service.EmTestService; import com.alibaba.fastjson.JSON; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest public class EmTest1 { @Autowired private EmTestService emTestService; @Test public void insertOrUpdate(){ String emTestString = "{\n" + // " \"id\": \"1278618408770588673\",\n" + " \"name\": \"lisi\",\n" + " \"age\": 18\n" + "}"; EmTest emTest = JSON.parseObject(emTestString, EmTest.class); emTestService.insertOrUpdate(emTest); System.out.println("..."); } }执行测试,结果正常,关键输出信息如下: 表中多了一条记录: 再执行更新操作:
package com.aecc.smart.fire.server; import com.aecc.smart.fire.server.entity.EmTest; import com.aecc.smart.fire.server.service.EmTestService; import com.alibaba.fastjson.JSON; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest public class EmTest1 { @Autowired private EmTestService emTestService; @Test public void insertOrUpdate(){ String emTestString = "{\n" + " \"id\": \"1278623237685329921\",\n" + " \"name\": \"lisi\",\n" + " \"age\": 18\n" + "}"; EmTest emTest = JSON.parseObject(emTestString, EmTest.class); emTestService.insertOrUpdate(emTest); System.out.println("..."); } }报错了: 因为项目里面添加了自动填充处理器:
package com.aecc.smart.fire.server.config; import java.util.Date; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component; import com.aecc.smart.fire.server.feign.BaseContextUtils; import com.baomidou.mybatisplus.mapper.MetaObjectHandler; /** * 自动填充处理器 * @Description TODO * @date 2019年11月14日 下午1:41:10 */ @Component public class MyMetaObjectHandler extends MetaObjectHandler{ @Override public void insertFill(MetaObject metaObject) { // TODO Auto-generated method stub this.setFieldValByName("addTime", new Date(), metaObject); this.setFieldValByName("addPerson", BaseContextUtils.getUserID(), metaObject); this.setFieldValByName("deleted", 0, metaObject); } @Override public void updateFill(MetaObject metaObject) { // TODO Auto-generated method stub this.setFieldValByName("lastModifyTime", new Date(), metaObject); this.setFieldValByName("lastModifyPerson", BaseContextUtils.getUserID(), metaObject); } }但是添加的时候,实体类没有insertFill方法中执行setFieldValByName方法时不会报错。
分析如下:
首先看BaseMapper: updateById方法执行的时候,把entity中字段的值处理成"et_"+字段名来最后填充占位符的值。
MetaObjectHandler中方法: 可知,添加的时候在处理不存在字段addTime等时,两个if条件,都不满足,返回this;而更新的时候处理不存在字段lastModifyTime时,会进入到else if判断条件中。原因往下看: 在执行MetaObjectHandler的setFieldValByName方法前,MetaObject对象已经处理过,而MetaObject对象中的setValue其实就是给这些字段设置值,并且有一个(“et_”->object对象)的属性->值。 最后跟踪到如下方法: 从HashMap类型的setMethods属性中找propertyName为lastModify就会找不到,进而抛出异常。
解决方式有两个:
在实体类添加公共字段,数据库表也添加对应字段(不推荐,因为表中本来就不需要这些字段)修改的时候,手动写sql