MyBatis-Plus中update修改成功,但实际数据并未被修改的解决办法
前言
关于这篇文章,主要针对通过调用 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);
}
如下图:
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 的核心思想或者目的就是 “ 为简化开发而生 ”,官方宣言如下图:
解决办法
该问题的解决办法分为两步:
- 启动字段的自动填充功能;
- 开启字段的验证策略,能根据 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 |
版权声明: | 本文为博主原创文章,请在转载时务必注明博文出处! |
下一篇: P1996 约瑟夫问题