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

版权声明:本文为博主原创文章,如果觉得写的不错需要转载,在转载时请注明博文出处! https://blog.csdn.net/Hello_World_QWP/article/details/88056976

前言

关于这篇文章,主要针对通过调用 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 [email protected]
 *          <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 [email protected]
 *          <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 [email protected]
 *          <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);
}

如下图:

 

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 的核心思想或者目的就是 “ 为简化开发而生 ”,官方宣言如下图:

解决办法

 

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

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

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

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

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


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


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

猜你喜欢

转载自blog.csdn.net/Hello_World_QWP/article/details/88056976