前言
开发中写链式调用的时候,经常会碰到这个编译报错:Cannot invoke setCreatedAt(Long) on the primitive type void。第一眼容易懵,其实根源非常简单,本文把原因、错误示例、正确写法、避坑方案一次性整理清楚,MyBatis-Plus 项目高频遇到。
报错核心原因
你在一个返回值为 void(或者 int) 的方法返回结果上,继续链式调用
.setCreatedAt()。void不是对象,没有实例,不支持.调用任何成员方法,编译器直接报错。
最常见场景:保存 / 插入方法 save() / insert() 执行之后,想链式给实体设置字段。 save()、mapper.insert() 这类方法返回 void /int(影响行数),不是实体对象,不能继续链式 set。
❌ 错误示例
场景 1:MyBatis-Plus Mapper insert 后链式 set
// 错误代码
userMapper.insert(user)
.setCreatedAt(System.currentTimeMillis());
insert 返回 int(数据库受影响行数),不是 User 对象,后面不能跟 .setCreatedAt()。
场景 2:自定义 Service 方法返回 void
// 方法定义
public void saveUser(User user) {
userMapper.insert(user);
}
// 调用处,直接报错
saveUser(user).setCreatedAt(System.currentTimeMillis());
场景 3:链式顺序颠倒(高频踩坑)
先执行保存,再去设置实体属性,顺序完全反了。
// 错误
user.setCreatedAt(1L).insert();
✅ 正确写法
方式 1:普通写法,先 set 再保存
User user = new User();
user.setCreatedAt(System.currentTimeMillis());
user.setUserName("test");
userMapper.insert(user);
方式 2:Lombok 链式实体(推荐)
实体类加上注解 @Accessors(chain = true),支持 setter 链式返回自身:
@Data
@Accessors(chain = true)
public class User {
private Long id;
private String userName;
private Long createdAt;
}
业务代码:
User user = new User()
.setCreatedAt(System.currentTimeMillis())
.setUserName("test");
userMapper.insert(user);
🚀 进阶方案:自动填充时间(推荐生产使用)
每次手动 setCreatedAt 很繁琐,MyBatis-Plus 自带自动填充,不用业务代码手动赋值。
- 实体字段加注解
@TableField(fill = FieldFill.INSERT)
private Long createdAt;
- 实现 MetaObjectHandler 填充处理器
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createdAt", System::currentTimeMillis, Long.class);
}
@Override
public void updateFill(MetaObject metaObject) {
// 更新时间填充,按需开启
this.strictUpdateFill(metaObject, "updatedAt", System::currentTimeMillis, Long.class);
}
}
配置完成后,新增数据自动填充 createdAt,业务代码完全不用写 setCreatedAt。
✅ 快速自查清单
- 定位报错行:看
.setCreatedAt()前面的方法,确认返回值是不是void/int - 调整执行顺序:先给实体 set 字段,再执行 insert /save/update
- 想要链式:实体开启
@Accessors(chain = true),保存方法放在链式最后一行 - 时间字段优先使用 MyBatis-Plus 自动填充,减少样板代码
小结
这个报错本质不是框架 bug,是链式调用顺序理解错误:setter 是实体对象的方法,保存方法是执行数据库操作,二者不能在保存之后继续链式。只要记住:先组装实体,再入库,基本就能避开这个坑。