返回顶部
首页 > 资讯 > 精选 >tk.mybatis通用插件updateByPrimaryKeySelective无法自动更新列怎么解决
  • 106
分享到

tk.mybatis通用插件updateByPrimaryKeySelective无法自动更新列怎么解决

2023-06-21 22:06:48 106人浏览 八月长安
摘要

本篇内容介绍了“tk.mybatis通用插件updateByPrimaryKeySelective无法自动更新列怎么解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大

本篇内容介绍了“tk.mybatis通用插件updateByPrimaryKeySelective无法自动更新列怎么解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

有一张表,结构如下(已经简化了):

CREATE TABLE `t_sample` (  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增ID',  `empcode` varchar(8) NOT NULL DEFAULT '' COMMENT '员工号',  `datachange_lasttime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '时间戳',  PRIMARY KEY (`id`),  UNIQUE KEY `idx_unique_empcode` (`empcode`),  KEY `idx_datachange_lasttime` (`datachange_lasttime`)) ENGINE=InnoDB AUTO_INCREMENT=561 DEFAULT CHARSET=utf8mb4 COMMENT='test'

有一列datachange_lasttime,设置了update时, 让mysql自动更新成当前时间,这样只要记录有变化,通过这一列就能知道什么时候变化的(这也是很多公司的数据库开发规范之一)

然后tk.mybatis里提供了一个很方便的方法:updateByPrimaryKeySelective,用法如下:

@Testpublic void testDataChangeLastTime() {    SampleEntity sample = sampleEntityMapper.selectByPrimaryKey(560);    long changeLastTime1 = sample.getDatachangeLasttime().getTime();    sample.setEmpcode("TEST");    int affectedRows = sampleEntityMapper.updateByPrimaryKeySelective(sample);    System.out.println(affectedRows);    long changeLastTime2 = sample.getDatachangeLasttime().getTime();     Assert.assertNotEquals(changeLastTime1, changeLastTime2);}

代码很简单,先根据主键id,取出一条记录,然后再根据业务要求,修改某一列,然后提交。运行后,发现datachange_lasttime这列并没按预期那样,更新成当前时间,仍然是旧的时间戳。(上面的单元测试将会失败)

日志级别调整成DEBUG,观察了下最终生成的update语句,如下:

23.933 [main] DEBUG  - ==> Preparing: UPDATE t_sample SET id = id,empcode = ?,datachange_lasttime = ? WHERE id = ? 
22:41:23.936 [main] DEBUG  - ==> Parameters: TEST(String), 2018-09-07 17:01:39.0(Timestamp), 560(Long)
22:41:23.981 [main] DEBUG  - <== Updates: 1

可能大家一眼就看出问题了,update语句里, datachange_lasttime这列,又用旧值重新更新回去了。

updateByPrimaryKeySelective的原理,是根据entity对象的属性值,是否为null,如果为null,则最终生成的update语句里,将忽略该列,否则会更新该列。

entity从数据库里取出来时,DatachangeLasttime属性上已经有值了,不为null,所以更新时,又把这个旧值给update回去了!解决办法:

@Testpublic void testDataChangeLastTime() {    SampleEntity sample = sampleEntityMapper.selectByPrimaryKey(560);    long changeLastTime1 = sample.getDatachangeLasttime().getTime();    //注意:就本例而言,如果empCode在数据库里的旧值本身是TEST,这一行不会被更新(datachange_lasttime列仍是旧值)    sample.setEmpcode("TEST");    //人为更新成null,以便让mybatis生成的update的语句忽略    sample.setDatachangeLasttime(null);    int affectedRows = sampleEntityMapper.updateByPrimaryKeySelective(sample);    System.out.println(affectedRows);    long changeLastTime2 = sample.getDatachangeLasttime().getTime();     Assert.assertNotEquals(changeLastTime1, changeLastTime2);}

手动把DatachangeLasttime属性设置为null即可,这次生成的udpate语句为:

06.298 [main] DEBUG  - ==> Preparing: UPDATE t_sample SET id = id,empcode = ? WHERE id = ? 
22:44:06.300 [main] DEBUG  - ==> Parameters: TEST(String), 560(Long)
22:44:06.342 [main] DEBUG  - <== Updates: 1

另外还有一个小细节,跟mybatis无关,是Mysql自己的机制,如果empcode这列在数据库里,这行上的旧值已经是TEST,java代码又把更新成TEST,即:这行的数据没有变化,updateByPrimaryKeySelective在java代码里返回的影响行数,仍然是1 ,但是在mysql里裸跑sql的话,影响行数是0,即:数据库层面这行没有更新,datachange_lasttime列当然仍是旧值(这倒也合理,毕竟数据更新前后的数据一样,所以mysql不更新也说得过去)

解决方案一:

最后,来点优雅的做法,毕竟大家都是有身份~~~~~"证"的人,怎么可能手动在每个需要更新的地方,手动设置null,这有点low,讲出去要被人笑话的^_~

mybatis提供了拦截器机制,搞一个拦截器在更新前拦截一下,用反射大法把这列设置成null,就万事大吉了。这里面

 @Intercepts({        @Signature(type = Executor.class, method = DataChangeLastTimeInterceptor.METHOD_UPDATE, args = {                MappedStatement.class, Object.class})}) public class DataChangeLastTimeInterceptor implements Interceptor {       Logger logger = LoggerFactory.getLogger(this.getClass());       public static final String METHOD_UPDATE = "update";     public static final String[] METHOD_SET_DATA_CHANGE_LAST_TIME = new String[]{"setDatachangeLasttime", "setDataChange_LastTime"};       @Override     public Object intercept(Invocation invocation) throws Throwable {         String methodName = invocation.getMethod().getName();         if (methodName.equalsIgnoreCase(DataChangeLastTimeInterceptor.METHOD_UPDATE)) {             Object parameter = invocation.getArgs()[1];             Date empty = null;             try {                 for (String s : METHOD_SET_DATA_CHANGE_LAST_TIME) {                     ReflectionUtils.callMethod(parameter, s, true, empty);                 }             } catch (Exception e) {                 logger.warn("setDatachangeLasttime error:" + e.getMessage() + ",class:" + parameter.getClass());             }         }         return invocation.proceed();     }    @Override     public Object plugin(Object o) {         return Plugin.wrap(o, this);     }    @Override     public void setProperties(Properties properties) {    }}

有一个自己写的反射工具类,代码如下:

import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Member;import java.lang.reflect.Method;import org.apache.commons.lang3.ArrayUtils; public class ReflectionUtils {     static Boolean checkName(Member member, String targetName, Boolean ignoreCase) {        if (ignoreCase) {            if (member.getName().equalsIgnoreCase(targetName)) {                return true;            }        } else if (member.getName().equals(targetName)) {            return true;        }         return false;    }     public static Method getMethod(Object target, String methodName, Boolean ignoreCase) {        if (target == null) {            return null;        } else {            Method[] methods = target.getClass().getDeclaredMethods();            if (ArrayUtils.isEmpty(methods)) {                return null;            } else {                Method[] arr$ = methods;                int len$ = methods.length;                 for(int i$ = 0; i$ < len$; ++i$) {                    Method method = arr$[i$];                    if (checkName(method, methodName, ignoreCase)) {                        return method;                    }                }                 return null;            }        }    }     public static Method getMethod(Object target, String methodName) {        return getMethod(target, methodName, false);    }     public static Field getField(Object target, String propertyName, Boolean ignoreCase) {        if (target == null) {            return null;        } else {            Field[] fields = target.getClass().getDeclaredFields();            if (ArrayUtils.isEmpty(fields)) {                return null;            } else {                Field[] arr$ = fields;                int len$ = fields.length;                 for(int i$ = 0; i$ < len$; ++i$) {                    Field f = arr$[i$];                    if (checkName(f, propertyName, ignoreCase)) {                        return f;                    }                }                 return null;            }        }    }     public static Field getField(Object target, String propertyName) {        return getField(target, propertyName, false);    }     public static void setField(Object target, String propertyName, Boolean ignoreCase, Object propertyValue) throws IllegalAccessException {        Field field = getField(target, propertyName, ignoreCase);        if (field != null) {            field.set(target, propertyValue);        }     }     public static void setField(Object target, String propertyName, Object propertyValue) throws IllegalAccessException {        setField(target, propertyName, false, propertyValue);    }     public static void callMethod(Object target, String methodName, Object... args) throws InvocationTargetException, IllegalAccessException {        callMethod(target, methodName, false, args);    }     public static void callMethod(Object target, String methodName, Boolean ignoreCase, Object... args) throws InvocationTargetException, IllegalAccessException {        Method method = getMethod(target, methodName, ignoreCase);        if (method != null) {            method.invoke(target, args);        }    }}

SpringBoot集成mybatis的配置(application.yml·)

mybatis:  type-aliases-package: com.efivestar.scs.back.api.scsp.domain.**  mapper-locations: classpath:mapper*.xml  config-location: classpath:mybatis/mybatis-config.xml

最后在mybatis-config.xml里启用该插件:

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""Http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!--<typeAliases>--><!--<package name="com.mybatis.domain"/>--><!--</typeAliases>--><!--<mappers>--><!--<mapper resource="sample/mybatis/mapper/CityMapper.xml"/>--><!--<mapper resource="sample/mybatis/mapper/HotelMapper.xml"/>--><!--</mappers>--><plugins><plugin interceptor="com.efivestar.scs.back.api.scsp.interceptor.SystemUpdateTimeInterceptor"></plugin></plugins></configuration>

解决方案二:

@TableField(value = "system_update_time", fill = FieldFill.INSERT_UPDATE)这个注解可以实现,需要自己实现填充策略。需要将自定义填充控制器注册为组件。实现字段填充控制器,编写自定义填充规则.实现 MetaObjectHandler 接口,实现 insertFill 和 updateFill 方法

@Slf4j @Component public class MyMetaObjectHandler implements MetaObjectHandler {      @Override     public void insertFill(MetaObject metaObject) {         this.setFieldValByName("systemCreateTime", new Timestamp(System.currentTimeMillis()), metaObject);     }      @Override     public void updateFill(MetaObject metaObject) {         this.setFieldValByName("systemUpdateTime", new Timestamp(System.currentTimeMillis()), metaObject);     }}

注意:

tk.mybatis通用插件updateByPrimaryKeySelective无法自动更新列怎么解决 

解决方案三:

也就是最笨的办法,每个update的时候通过代码setSystemUpdateTime

“tk.mybatis通用插件updateByPrimaryKeySelective无法自动更新列怎么解决”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: tk.mybatis通用插件updateByPrimaryKeySelective无法自动更新列怎么解决

本文链接: https://lsjlt.com/news/301043.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • tk.mybatis通用插件updateByPrimaryKeySelective无法自动更新列怎么解决
    本篇内容介绍了“tk.mybatis通用插件updateByPrimaryKeySelective无法自动更新列怎么解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大...
    99+
    2023-06-21
  • tk.mybatis通用插件updateByPrimaryKeySelective无法自动更新列的解决办法
    tk.mybatis是一个很好用的通用插件,把CRUD这些基本的数据操作全都用动态SQL语句自动生成了,mapper和xml里十分清爽,但是昨天发现有一个小坑,记录在此: 有一张表,...
    99+
    2024-04-02
  • Windows7中无法自动更新解决方法
      Windows update程序能更更好地使大家的电脑保持最新状态及系统稳定,可是有时会莫名地遇到无法更新的情况,那么又要怎样来解决呢通过本文大家就可以了解到需要如何解决Windows 7中无法UpDate   1...
    99+
    2023-06-14
    Windows7 无法自动更新 方法
  • springboot中自动建表无法更新字段怎么解决
    本篇内容主要讲解“springboot中自动建表无法更新字段怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“springboot中自动建表无法更新字段怎么解决”吧!关于自动建表,无法更新字...
    99+
    2023-06-29
  • Win8应用商店无法自动更新如何解决
    这篇文章主要讲解了“Win8应用商店无法自动更新如何解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Win8应用商店无法自动更新如何解决”吧!一、在win8系统打开自动更新,切换到桌面上,...
    99+
    2023-06-28
  • wordpress无法安装更新主题插件的解决办法
    最近一段时间,国内无法正常访问WordPress官网,经常提示“429 Too Many Requests”,后台程序版本升级、主题、插件升级时常失败。目前发现一款非常好用的插件:WP-China-Ye...
    99+
    2024-04-02
  • win7无法更新启动配置怎么解决
    如果Windows 7无法更新启动配置,你可以尝试以下方法解决问题: 运行系统维修:在开机时按下F8键进入高级启动选项,选择“修...
    99+
    2023-10-22
    win7
  • Win7自动更新失败后无法进入系统怎么解决
    这篇“Win7自动更新失败后无法进入系统怎么解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Win7自动更新失败后无法进入...
    99+
    2023-06-27
  • win10 1903无法更新怎么解决
    今天小编给大家分享一下win10 1903无法更新怎么解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。在Windows10...
    99+
    2023-07-01
  • win10自动更新怎么关闭的解决方法
      win10默认开启了系统自动更新的功能,每隔一段时间就会给系统进行更新和升级,令人感到反感,那么有什么方法可以关闭自动更新呢,很多小伙伴都不知道win10系统如何关闭自动更新,接下来小编就把win10系统关闭自动更新的方法教给大家。  ...
    99+
    2023-07-10
  • 怎么解决Nessus插件更新失败问题
    本篇内容主要讲解“怎么解决Nessus插件更新失败问题”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么解决Nessus插件更新失败问题”吧!当安装Nessus服务后,首次登录该服务将需要进行初...
    99+
    2023-06-05
  • win10更新后无法关机怎么解决
    如果在Windows 10更新后无法关机,可以尝试以下解决方法:1. 强制关机:按住电脑的电源按钮长按5秒钟,直到电脑完全关闭。这是...
    99+
    2023-08-31
    win10
  • win10更新后无法上网怎么解决
    本篇内容主要讲解“win10更新后无法上网怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“win10更新后无法上网怎么解决”吧!第一种解决方法: 首先按下【win】+【X】键,选择【控制面...
    99+
    2023-07-01
  • win10更新后键盘无法使用怎么解决
    如果您的Windows 10更新后键盘无法使用,您可以尝试以下解决方法:1. 重新启动计算机:有时候重新启动计算机可以解决临时的软件...
    99+
    2023-08-08
    win10
  • win10自动更新关闭不了怎么解决
    要解决Windows 10无法关闭自动更新的问题,可以尝试以下几种方法:1. 使用“组策略编辑器”禁用自动更新:- 按下Win + ...
    99+
    2023-08-19
    win10
  • win7自动更新失败无法进入系统的两种解决办法
    win7是现在的主流操作系统,在使用过程中,很多人都会遇到开机或关机提示"配置w 其实这是win7在联网的情况下,自动更新造成的,在开机或关机的时候会提示,一般正常更新完成即可,但可能是用户没有耐心到系统更新完...
    99+
    2023-06-17
    win7系统更新失败 win7系统还原失败 win7系统安装失败 解决办法 win7
  • win10商店无法获取更新怎么解决
    这篇文章主要介绍“win10商店无法获取更新怎么解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“win10商店无法获取更新怎么解决”文章能帮助大家解决问题。win10商店无法获取更新的解决方法在重...
    99+
    2023-07-01
  • win10更新后无法连接WiFi怎么解决
    今天小编给大家分享一下win10更新后无法连接WiFi怎么解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一、如果右下角的...
    99+
    2023-07-01
  • ultraedit无法新建文件怎么解决
    这篇“ultraedit无法新建文件怎么解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“ultraedit无法新建文件怎么...
    99+
    2023-07-01
  • iOS 17更新失败或无法更新怎么办?8 个解决方法快速解决!
    苹果即将在2023年9月19日发布iOS 17正式版,许多用户也都相当期待随之而来的iOS 17新功能,不过当你准备将iPhone 更新到iOS 17 版本时,可能会发生一些不可预测的iOS 17更新失败或更新卡住的问题,但不用担心,本文将...
    99+
    2023-10-12
    cocoa macos objective-c
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作