MyBatis Plus 遇到的坑,update只能全量更新所有字段,无法实现只更新部分字段
创始人
2025-05-28 20:02:13

目录

    • 一、BaseMapper.update(entity, updateWrapper) 入参说明
    • 二、踩坑代码
      • 1. t_user.sql
      • 2. TUserMapper.java
      • 3. TUserMapper.java
      • 4. TUserMapper.xml
      • 5. SQL 执行日志
      • 6. 报错信息
      • 7. 报错分析
      • 8. 解决方案

一、BaseMapper.update(entity, updateWrapper) 入参说明

首先,我们先来看下 BaseMapper 中 update(entity, updateWrapper) 的方法签名:

/*** 根据 whereEntity 条件,更新记录** @param entity        实体对象* @param updateWrapper 实体对象封装操作类*/
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper updateWrapper);

参数说明如下:

  • T entity 入参:用于传入 update 时需要 set 的值。

    可以为 null,为 null 时通过 updateWrapper 指定 set 值;

  • Wrapper updateWrapper 入参:主要用于传入 update 时需要的 where 值,也可以指定需要 set 的值。

    可以为 null,为 null 时更新全表。

二、踩坑代码

1. t_user.sql

CREATE TABLE `t_user` (`id` BIGINT(16) NOT NULL AUTO_INCREMENT COMMENT '主键',`username` VARCHAR(64) NOT NULL COMMENT '用户名' COLLATE 'utf8_general_ci',`password` VARCHAR(64) NOT NULL COMMENT '密码' COLLATE 'utf8_general_ci',`age` INT(8) NULL DEFAULT NULL COMMENT '年龄',`salary` INT(8) NULL DEFAULT NULL COMMENT '工资',`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`) USING BTREE
)
COMMENT='用户表'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;

2. TUserMapper.java

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.demo.module.entity.TUser;
import com.demo.module.mapper.TUserMapper;
import com.demo.module.service.TUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;/*** 用户表 服务实现类** @author ACGkaka* @since 2021-04-25*/
@Service
public class TUserServiceImpl extends ServiceImpl implements TUserService {@Autowiredprivate TUserMapper userMapper;@Overridepublic void updateUser(String username) {UpdateWrapper updateWrapper = new UpdateWrapper<>();updateWrapper.lambda().set(TUser::getUsername, username).eq(TUser::getId, 7);userMapper.update(null, updateWrapper);}
}

3. TUserMapper.java

import com.demo.module.entity.TUser;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;/*** 用户表 Mapper 接口** @author ACGkaka* @since 2021-04-25*/
@Mapper
public interface TUserMapper extends BaseMapper {int update(TUser user);
}

4. TUserMapper.xml



UPDATE t_userSET username = #{username},password = #{password},create_time = #{createTime},update_time = #{updateTime}WHERE id = #{id}

5. SQL 执行日志

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3946f66d] was not registered for synchronization because synchronization is not active
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@378b61ea] will not be managed by Spring
==>  Preparing: UPDATE t_user SET username = ?, password = ?, create_time = ?, update_time = ? WHERE id = ?
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3946f66d]

6. 报错信息

控制台报错:org.apache.ibatis.binding.BindingException: Parameter 'username' not found. Available parameters are [ew, param1, et, param2]

详细报错日志如下:

2023-03-16 10:37:59.493 ERROR 29760 --- [nio-8081-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.BindingException: Parameter 'username' not found. Available parameters are [ew, param1, et, param2]] with root causeorg.apache.ibatis.binding.BindingException: Parameter 'username' not found. Available parameters are [ew, param1, et, param2]at org.apache.ibatis.binding.MapperMethod$ParamMap.get(MapperMethod.java:212) ~[mybatis-3.5.6.jar:3.5.6]at org.apache.ibatis.reflection.wrapper.MapWrapper.get(MapWrapper.java:45) ~[mybatis-3.5.6.jar:3.5.6]at org.apache.ibatis.reflection.MetaObject.getValue(MetaObject.java:122) ~[mybatis-3.5.6.jar:3.5.6]at com.baomidou.mybatisplus.core.MybatisParameterHandler.setParameters(MybatisParameterHandler.java:205) ~[mybatis-plus-core-3.4.1.jar:3.4.1]at org.apache.ibatis.executor.statement.PreparedStatementHandler.parameterize(PreparedStatementHandler.java:94) ~[mybatis-3.5.6.jar:3.5.6]at org.apache.ibatis.executor.statement.RoutingStatementHandler.parameterize(RoutingStatementHandler.java:64) ~[mybatis-3.5.6.jar:3.5.6]at com.baomidou.mybatisplus.core.executor.MybatisSimpleExecutor.prepareStatement(MybatisSimpleExecutor.java:99) ~[mybatis-plus-core-3.4.1.jar:3.4.1]at com.baomidou.mybatisplus.core.executor.MybatisSimpleExecutor.doUpdate(MybatisSimpleExecutor.java:55) ~[mybatis-plus-core-3.4.1.jar:3.4.1]at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117) ~[mybatis-3.5.6.jar:3.5.6]at com.baomidou.mybatisplus.core.executor.MybatisCachingExecutor.update(MybatisCachingExecutor.java:85) ~[mybatis-plus-core-3.4.1.jar:3.4.1]at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:197) ~[mybatis-3.5.6.jar:3.5.6]at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_60]at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_60]at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_60]at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_60]at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:426) ~[mybatis-spring-2.0.5.jar:2.0.5]at com.sun.proxy.$Proxy56.update(Unknown Source) ~[na:na]at org.mybatis.spring.SqlSessionTemplate.update(SqlSessionTemplate.java:287) ~[mybatis-spring-2.0.5.jar:2.0.5]at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:65) ~[mybatis-plus-core-3.4.1.jar:3.4.1]at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) ~[mybatis-plus-core-3.4.1.jar:3.4.1]at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) ~[mybatis-plus-core-3.4.1.jar:3.4.1]at com.sun.proxy.$Proxy57.update(Unknown Source) ~[na:na]at com.demo.module.service.impl.TUserServiceImpl.updateUser(TUserServiceImpl.java:29) ~[classes/:na]at com.demo.module.service.impl.TUserServiceImpl$$FastClassBySpringCGLIB$$361c0747.invoke() ~[classes/:na]at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.6.jar:5.3.6]at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.3.6.jar:5.3.6]at com.demo.module.service.impl.TUserServiceImpl$$EnhancerBySpringCGLIB$$32d6ea41.updateUser() ~[classes/:na]at com.demo.module.controller.TUserController.update(TUserController.java:39) ~[classes/:na]at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_60]at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_60]at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_60]at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_60]at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197) ~[spring-web-5.3.6.jar:5.3.6]at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:141) ~[spring-web-5.3.6.jar:5.3.6]at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.3.6.jar:5.3.6]at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894) ~[spring-webmvc-5.3.6.jar:5.3.6]at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.6.jar:5.3.6]at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.6.jar:5.3.6]at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1060) ~[spring-webmvc-5.3.6.jar:5.3.6]at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:962) ~[spring-webmvc-5.3.6.jar:5.3.6]at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.6.jar:5.3.6]at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.6.jar:5.3.6]at javax.servlet.http.HttpServlet.service(HttpServlet.java:626) ~[tomcat-embed-core-9.0.45.jar:4.0.FR]at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.6.jar:5.3.6]at javax.servlet.http.HttpServlet.service(HttpServlet.java:733) ~[tomcat-embed-core-9.0.45.jar:4.0.FR]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.45.jar:9.0.45]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.45.jar:9.0.45]at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.45.jar:9.0.45]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.45.jar:9.0.45]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.45.jar:9.0.45]at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.6.jar:5.3.6]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.6.jar:5.3.6]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.45.jar:9.0.45]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.45.jar:9.0.45]at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.6.jar:5.3.6]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.6.jar:5.3.6]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.45.jar:9.0.45]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.45.jar:9.0.45]at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.6.jar:5.3.6]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.6.jar:5.3.6]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.45.jar:9.0.45]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.45.jar:9.0.45]at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.45.jar:9.0.45]at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) [tomcat-embed-core-9.0.45.jar:9.0.45]at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) [tomcat-embed-core-9.0.45.jar:9.0.45]at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143) [tomcat-embed-core-9.0.45.jar:9.0.45]at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.45.jar:9.0.45]at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) [tomcat-embed-core-9.0.45.jar:9.0.45]at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) [tomcat-embed-core-9.0.45.jar:9.0.45]at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374) [tomcat-embed-core-9.0.45.jar:9.0.45]at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.45.jar:9.0.45]at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893) [tomcat-embed-core-9.0.45.jar:9.0.45]at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1707) [tomcat-embed-core-9.0.45.jar:9.0.45]at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.45.jar:9.0.45]at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_60]at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_60]at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.45.jar:9.0.45]at java.lang.Thread.run(Thread.java:745) [na:1.8.0_60]

7. 报错分析

结合 4.SQL 执行日志5.报错信息,我们可以发现是因为我们在调用 userMapper.update() 方法更新的时候,只指定了更新 username 字段,但是 SQL 中却 setpassword 字段,我们没有指定 password 字段要更新的值,所以报错了。

为什么我只指定了更新 username 字段,但是却更新了所有字段呢?

推测 MyBatis Plus 框架应该是使用了 模板模式 来实现了 BaseMapper.update() 方法,当我们在自己的 Mapper 中继承了 BaseMapper,又自己实现了 update() 方法的时候,BaseMapper 中原生的 update() 方法就不会生效。

8. 解决方案

有两种方式来解决这个问题:

方法一: 删除 TUserMapper.java 中的 update() 方法,改为统一使用 MyBatis Plus 提供的默认实现方式。

方法二: 继续使用 TUserMapper.java 中的 update() 方法,但是需要在 TUserMapper.xml 中通过 标签来支持只更新部分字段。

整理完毕,完结撒花~ 🌻

相关内容

热门资讯

福山八景——仙峰夜月 古人《出郡城东门晚眺》诗中,有“此去丹崖知不远,乘云直拟访仙宫”的诗句。这里的丹崖即蓬莱仙阁所在之处...
你也在纽约过节?出行交通指南请... 今晚就是平安夜啦,纽约的节日氛围已经拉满,先祝大家平安顺心,圣诞快乐~ 今明两天都是全城过节的日子,...
“粤游戏”拿下全国八成营收 广东是全国游戏产业重镇。图为深圳景区用《黑神话:悟空》中的人物装点。(受访者供图) 【深圳商报讯】(...
非洲杯焦点战:尼日利亚VS坦桑... 作为非洲足坛的传统劲旅与新兴力量,尼日利亚与坦桑尼亚的这场对决注定充满看点。一方是拥有深厚底蕴的非洲...