欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

MyBatis-Plus中update修改成功,但实际数据并未被修改的解决办法

程序员文章站 2022-06-05 18:03:50
...

前言

关于这篇文章,主要针对通过调用 MyBatis-Plus API 实现动态修改数据时遇到的,不是使用的SQL,如果你使用的是SQL则建议移步到相关文章,以免耽误你的工作时间,如果是SQL,在移步前博主给两个关注点可以尝试去解决:一个是事务方面,有可能数据已经修改成功,但是在下一步的操作中,可能在某步失败后导致全局数据回滚,所以修改失败;二一个是设置自动提交openSession( autoCommit=true),在CRUD的业务逻辑代码后加上 sqlSession.commit() 即可。

再次声明,本篇博文主要针对 MyBatis-Plus API 调用跟新时,失败的解决办法,下面很长。

 

问题概述

当实体的所有字段都不为空时,修改是成功的,但是,当某个字段的值不传时,修改成功后,该字段还是显示原来的值。目的,希望此时该字段的实际数据被修改为空,但实际数据未作任何改变。

关于这个问题,网上没有可行的解决办法,只能将问题结合源码进行分析并找到合适的解决方案,下面是博主的源码分析,不到之处望指正。

 

问题前奏(示例性代码,目的为阐述问题):

1、接收数据

package com.travel.etcp.controller;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * 
 * @author HuaZai
 * @contact aaa@qq.com
 *          <ul>
 * @description
 *              <li>一号服务器
 *              </ul>
 * @className EmployeeController
 * @package com.travel.etcp.controller
 * @createdTime 2018年05月05日 下午5:52:07
 *
 * @version V1.0.0
 */
@Slf4j
@RestController
@Api(value = "/emp")
@RequestMapping("/emp")
public class EmployeeController
{
	@Autowired
	public EmployeeService employeeService;

	@SysLog("用户模块-修改用户")
	@PutMapping("/updateEmployeeById")
	@ApiOperation(value = "/updateEmployeeById", notes = "通过EmployeeId更新用户信息")
	public ResponseData updateEmployeeById(
			@ApiParam(name = "employee", value = "Employee 实体") @RequestParam(name = "employee") Employeee employee)
	{
		try
		{
			String header = HttpContextUtils.getHttpServletRequest().getHeader(Constant.TERMINAL_TYPE_HEADER);
			employeeService.updateEmployeeById(employee);
		} catch (Exception e)
		{
			log.info(Constant.INFO_LOG_MSG, e.getMessage()); // 这个需要配置插件
			return ResponseData.error(RespCodeEnum.ERROR_INTERNAL_SERVER.getCode(), "用户修改失败");
		}
		return ResponseData.ok();
	}
}

2、服务接口:

package com.travel.etcp.service;

import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.IService;

import java.util.List;

/**
 * 
 * @author HuaZai
 * @contact aaa@qq.com
 *          <ul>
 * @description
 *              <li>TODO
 *              </ul>
 * @className EmployeeService
 * @package com.travel.etcp.service
 * @createdTime 2018年05月05日 下午4:32:07
 *
 * @version V1.0.0
 */
public interface EmployeeService extends IService<Employee>
{

	void updateEmployeeById(Employee employee);

}

 

3、 数据处理:

package com.travel.etcp.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 
 * @author HuaZai
 * @contact aaa@qq.com
 *          <ul>
 * @description
 *              <li>TODO
 *              </ul>
 * @className EmployeeServiceImpl
 * @package com.travel.etcp.service.impl
 * @createdTime 2018年05月05日 下午4:58:13
 *
 * @version V1.0.0
 */
@Slf4j
@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService
{

	@Autowired
	private EmployeeService employeeService;

	@Autowired
	private EmployeeMapper employeeMapper;

	@Transactional
	@Override
	public void updateEmployeeById(Employee employee)
	{
		try
		{
			// 这儿因为继承了MyBatis的ServiceImpl类,而在ServiceImpl中实现了IService类,
			// 所以这儿可以去掉employeeService 而直接调用API:updateById(employee);
			employeeService.updateById(employee);

		} catch (Exception e)
		{
			log.error(Constant.INFO_LOG_MSG, e.getMessage());
		}
	}
}

 

源码解析:

1、以直接调用 API 的方式,所以从 ServiceImpl 类开始,如下:

package com.baomidou.mybatisplus.service.impl;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.binding.MapperMethod.ParamMap;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

public class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T>
{
	@Autowired
	protected M baseMapper;

	public ServiceImpl()
	{
	}

	protected static boolean retBool(Integer result)
	{
		return SqlHelper.retBool(result);
	}

	protected Class<T> currentModelClass()
	{
		return ReflectionKit.getSuperClassGenricType(this.getClass(), 1);
	}

	protected SqlSession sqlSessionBatch()
	{
		return SqlHelper.sqlSessionBatch(this.currentModelClass());
	}

	protected String sqlStatement(SqlMethod sqlMethod)
	{
		return SqlHelper.table(this.currentModelClass()).getSqlStatement(sqlMethod.getMethod());
	}

	/**
	 * 省略部分代码
	 */

	@Transactional(rollbackFor =
	{ Exception.class })
	public boolean updateById(T entity)
	{
		return retBool(this.baseMapper.updateById(entity));
	}

	/**
	 * 省略部分代码
	 */
}

 

2、查看API接口 IService 类 ,如下:

package com.baomidou.mybatisplus.service;

import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;

public interface IService<T>
{
	boolean insert(T var1);

	boolean insertAllColumn(T var1);

	boolean insertBatch(List<T> var1);

	boolean insertBatch(List<T> var1, int var2);

	boolean insertOrUpdateBatch(List<T> var1);

	boolean insertOrUpdateBatch(List<T> var1, int var2);

	boolean insertOrUpdateAllColumnBatch(List<T> var1);

	boolean insertOrUpdateAllColumnBatch(List<T> var1, int var2);

	boolean deleteById(Serializable var1);

	boolean deleteByMap(Map<String, Object> var1);

	boolean delete(Wrapper<T> var1);

	boolean deleteBatchIds(Collection<? extends Serializable> var1);

	boolean updateById(T var1);

	boolean updateAllColumnById(T var1);

	boolean update(T var1, Wrapper<T> var2);

	boolean updateBatchById(List<T> var1);

	boolean updateBatchById(List<T> var1, int var2);

	boolean updateAllColumnBatchById(List<T> var1);

	boolean updateAllColumnBatchById(List<T> var1, int var2);

	boolean insertOrUpdate(T var1);

	boolean insertOrUpdateAllColumn(T var1);

	T selectById(Serializable var1);

	List<T> selectBatchIds(Collection<? extends Serializable> var1);

	List<T> selectByMap(Map<String, Object> var1);

	T selectOne(Wrapper<T> var1);

	Map<String, Object> selectMap(Wrapper<T> var1);

	Object selectObj(Wrapper<T> var1);

	int selectCount(Wrapper<T> var1);

	List<T> selectList(Wrapper<T> var1);

	Page<T> selectPage(Page<T> var1);

	List<Map<String, Object>> selectMaps(Wrapper<T> var1);

	List<Object> selectObjs(Wrapper<T> var1);

	Page<Map<String, Object>> selectMapsPage(Page var1, Wrapper<T> var2);

	Page<T> selectPage(Page<T> var1, Wrapper<T> var2);
}

如下图:

MyBatis-Plus中update修改成功,但实际数据并未被修改的解决办法

 

3、@TableField 源码如下

package com.baomidou.mybatisplus.annotation;

import java.lang.annotation.*;

/**
 * 表字段标识
 *
 * @author hubin sjy tantan
 * @since 2016-09-09
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TableField
{

	/**
	 * 字段值(驼峰命名方式,该值可无)
	 */
	String value() default "";

	/**
	 * 当该Field为类对象时, 可使用#{对象.属性}来映射到数据表.
	 * <p>
	 * 支持:@TableField(el = "role, jdbcType=BIGINT)
	 * </p>
	 * <p>
	 * 支持:@TableField(el = "role,
	 * typeHandler=com.baomidou.springcloud.typehandler.PhoneTypeHandler")
	 * </p>
	 */
	String el() default "";

	/**
	 * 是否为数据库表字段
	 * <p>
	 * 默认 true 存在,false 不存在
	 * </p>
	 */
	boolean exist() default true;

	/**
	 * 字段 where 实体查询比较条件
	 * <p>
	 * 默认 `=` 等值
	 * </p>
	 */
	String condition() default "";

	/**
	 * 字段 update set 部分注入, 该注解优于 el 注解使用
	 * <p>
	 * 例如:@TableField(.. , update="%s+1") 其中 %s 会填充为字段
	 * </p>
	 * <p>
	 * 输出 SQL 为:update 表 set 字段=字段+1 where ...
	 * </p>
	 * <p>
	 * 例如:@TableField(.. , update="now()") 使用数据库时间
	 * </p>
	 * <p>
	 * 输出 SQL 为:update 表 set 字段=now() where ...
	 * </p>
	 */
	String update() default "";

	/**
	 * 字段验证策略
	 * <p>
	 * 默认追随全局配置
	 * </p>
	 */
	FieldStrategy strategy() default FieldStrategy.DEFAULT;

	/**
	 * 字段自动填充策略
	 */
	FieldFill fill() default FieldFill.DEFAULT;

	/**
	 * 是否进行 select 查询
	 * <p>
	 * 大字段可设置为 false 不加入 select 查询范围
	 * </p>
	 */
	boolean select() default true;

}

 

在上面的源码的解析中,已知 MyBatis-Plus 已经能满足所有的一般业务需求,如果对MyBatis-Plus不熟悉,或者知其然而不知其所以然,则会处处碰壁,MyBatis-Plus 的核心思想或者目的就是 “ 为简化开发而生 ”,官方宣言如下图:

MyBatis-Plus中update修改成功,但实际数据并未被修改的解决办法

 

 

解决办法

 

该问题的解决办法分为两步:

  1. 启动字段的自动填充功能;
  2. 开启字段的验证策略,能根据 Entity 产出 SQL 的字段验证策略,这个就有点类似于SQL里面的if标签;

 

所以API调用的通过以上两步即可轻松解决,如果是SQL则还需要移步到相关文章了。

 

 

 

参考MyBatis-Plus源码:MyBatis-Plus源码地址

MyBatis-Plus文档:MyBatis-Plus文档地址


好了,关于 MyBatis-Plus中update修改成功,但实际数据并未被修改的解决办法 就写到这儿了,如果还有什么疑问或遇到什么问题欢迎扫码提问,也可以给我留言哦,我会一一详细的解答的。 
歇后语:“ 共同学习,共同进步 ”,也希望大家多多关注CSND的IT社区。


作       者: 华    仔
联系作者: aaa@qq.com
来        源: CSDN (Chinese Software Developer Network)
原        文: https://blog.csdn.net/Hello_World_QWP/article/details/88056976
版权声明: 本文为博主原创文章,请在转载时务必注明博文出处!