Javers

在开发过程中遇到需求,比较数据库中的原数据与新修改要写入库中的数据。这个实体类是比较复杂的。例如有基本类型,BigDecimal类型,自定义类型,Date类型,List集合,Set集合,Map集合等。在比较复杂的类的情况下,使用Objects的equals是不适用的。所以为了解决这个问题,可以使用Javers库中的compare方法来解决该问题

引入

 <!-- https://mvnrepository.com/artifact/org.javers/javers-core -->
<dependency>
<groupId>org.javers</groupId>
<artifactId>javers-core</artifactId>
<version>6.6.2</version>
</dependency>

方法:

Javers javers = JaversBuilder.javers().build();
Diff diff = javers.compare(oldObject,newObject)
boolean flag = diff.hasChange();
//diff会在控制台打印出两个类之间的异同,相同不打印数据,不同会展示出修改前后的数据
//diff.hasChange(); 如果两个类完全相同,返回值为flase,两个类不同,返回值为true

示例

public static void main(String[] args) {
Javers build = JaversBuilder.javers().build();
//A系统的类
//数据库中的数据
PromotionDetail promotionDetail = new PromotionDetail();
promotionDetail.setCanEditFlag(true);
promotionDetail.setAllGoodsCountType(1);
promotionDetail.setName("name1");
PromotionGoods promotionGoods = new PromotionGoods();
promotionGoods.setCount(1);
promotionGoods.setDeptName("deptname1");
PromotionGoods promotionGoods1 = new PromotionGoods();
promotionGoods1.setCount(2);
promotionGoods1.setDeptName("deptname2");
List<PromotionGoods> list = new ArrayList<>();
list.add(promotionGoods);
list.add(promotionGoods1);
promotionDetail.setGoods(list); //新数据
PromotionDetail promotionDetail1 = new PromotionDetail();
promotionDetail1.setCanEditFlag(true);
promotionDetail1.setAllGoodsCountType(1);
promotionDetail1.setName("name2");
PromotionGoods promotionGoods2 = new PromotionGoods();
promotionGoods2.setCount(5);
promotionGoods2.setDeptName("deptname3");
PromotionGoods promotionGoods3 = new PromotionGoods();
promotionGoods3.setCount(4);
promotionGoods3.setDeptName("deptname3");
List<PromotionGoods> list0 = new ArrayList<>();
list0.add(promotionGoods2);
list0.add(promotionGoods3);
promotionDetail1.setGoods(list0); Diff compare = build.compare(promotionDetail, promotionDetail1);
boolean b = compare.hasChanges();
System.out.println(compare);
System.out.println(b);
}
//控制台输出
Diff:
* changes on com.ef.admin.data.controller.promotion.np.param.PromotionDetail/ :
- 'goods/0.count' changed: '1' -> '5'
- 'goods/0.deptName' changed: 'deptname1' -> 'deptname3'
- 'goods/1.count' changed: '2' -> '4'
- 'goods/1.deptName' changed: 'deptname2' -> 'deptname3'
- 'name' changed: 'name1' -> 'name2' true ====》为true说明有改变

遇到的问题:

  • BigDecimal

    在比较BigDecimal类型的不同数据时,会出现问题。由于javer.compare()底层是使用的objects的equals方法来判断两个数据是否相等,而BigDecimal类型比较时使用equals方法比较存在问题,应该使用BigDecimal类中的compareTo方法比较,详见https://blog.csdn.net/molihuaya/article/details/79139418

    BigDecimalComparatorWithFixedEquals类实现了CustomValueComparator<>接口并重写equals方法

    public class BigDecimalComparatorWithFixedEquals implements CustomValueComparator<BigDecimal> {
    @Override
    public boolean equals(BigDecimal a, BigDecimal b) {
    return a.compareTo(b) == 0;
    }

    所以创建javers对象时:

    Javers javers = JaversBuilder.javers().registerValue(BigDecimal.class,new BigDecimalComparatorWithFixedEquals()).build();
  • Date

    在比较Date类型的不同数据时,会出现问题。假设在数据中查出的日期类型为Date,新修改的数据为TimeStamp类型。此时使用javers.compare()比较时即使时间点相同,比较出来仍有问题。

    数据库中的数据  2022-02-25 23:59:59.0
    新修改的数据 Fri Feb 25 23:59:59 CST 2022

    可以通过实现CustomValueComparator<>接口来重写equals方法

    public class EfDateComparator implements CustomValueComparator<Date> {
    @Override
    public boolean equals(Date a, Date b) {
    return a.getTime() == b.getTime();
    }

    所以创建javers对象时:

    Javers javers = JaversBuilder.javers().registerValue(BigDecimal.class,new BigDecimalComparatorWithFixedEquals()).build();
Javers javers = JaversBuilder.javers()
.registerValue(BigDecimal.class,new BigDecimalComparatorWithFixedEquals())
.registerValue(BigDecimal.class,new BigDecimalComparatorWithFixedEquals())
.build();

相关注解

在比较两个类时,可能需要只比较部分字段或不比较部分字段,可以考虑使用以下两个注解

//在一个类中,在字段上添加该注解,该类中只比较有注解的字段
@DiffInclude //在一个类中,在字段上添加该注解,该类中忽略比较有注解的字段
@DiffIgnore //PS:两个注解不可以同时出现在一个类中

如果有没说明白的地方可以留言

Javers 比较两个类的差异的更多相关文章

  1. 通过实现System.IComparable接口的CompareTo方法对两个类进行比较

    假设现在有一个学生类 class Student { int age; public Student(int age) { this.age = age; } } 要使学生类之间能进行比较,实现Sys ...

  2. 【java回调】java两个类之间的回调函数传递

    背景交代:熟悉用js开发的cordovaAPP:对java一窍不通的我,老师让做一个监测用户拍照事件的功能,无奈没有找到现成的库,无奈自己动手开发java插件~~0基础java GreenHand,祝 ...

  3. ORACLE如何比较两个数据库的差异

    ORACLE怎么比较两个数据库的差异 方法1:使用PL-SQL工具 点击 工具->比较用户对象

  4. diff 比较两个文件的差异

    功能:比较两个文件的差异,并把不同地方的信息显示出来.默认diff格式的信息. diff比较两个文件或文件集合的差异,并记录下来,生成一个diff文件,这也是我们常说的补丁文件.也使用patch命令对 ...

  5. Reader与InputStream两个类中的read()的区别

    InputStream类的read()方法是从流里面取出一个字节,他的函数原型是 int read(); ,Reader类的read()方法则是从流里面取出一个字符(一个char),他的函数原型也是  ...

  6. 简单看看这两个类 String和StringBuilder

    我记得以前在园子里面讨论这两个类的文章有很多很多,并且还拿出了很多的测试报告,在什么情况下,谁比谁快,在什么情况下,该用谁 不该用谁等等这些,我这里就不比较了,我就简单看看他们里面的内部实现,那就先看 ...

  7. git日志输出格式及两个版本之间差异列表

    查看commit id git log --pretty=format:"%h" git log --pretty=format:"%H" 获取两个版本间差异的 ...

  8. C++学习笔记一 —— 两个类文件互相引用的处理情况

    先记录一些零碎的知识点: 1. 一个类可以被声明多次,但只能定义一次,也就是可以 class B;  class B;  class B; ……;  class B {……};  这样子. 2. 一个 ...

  9. 使用 Attribute +反射 来对两个类之间动态赋值

    看同事使用的 一个ORM 框架 中 有这样一个功能  通过特性(附加属性)的功能来 实现的两个类对象之间动态赋值的 功能 觉得这个功能不错,但是同事使用的 ORM 并不是我使用的  Dapper  所 ...

随机推荐

  1. SSRF服务器端请求伪造漏洞基础

    0x00 思考 1.什么是SSRF漏洞?2.SSRF漏洞的利用方式3.SSRF漏洞绕过4.SSRF漏洞加固 0x01 什么是SSRF漏洞 定义:SSRF漏洞,中文全称为服务端请求伪造漏洞,是一种由攻击 ...

  2. AVD模拟器怎么配置上网

    转自:http://blog.csdn.net/you_jinjin/article/details/7228303 方法一 首先,Windows下,配置Adroid环境变量(Win7为例) 1.桌面 ...

  3. java string 转化为json_java String 转Json报错

    缺少jar包依赖: java.lang.NoClassDefFoundError: org/apache/commons/beanutils/DynaBean 缺少commons-beanutils- ...

  4. 看看CSDN的吃相

    大伙快来看看CSDN的吃相.

  5. python类2

    #!/usr/bin/python #coding=utf-8 #好好学习,天天向上 class Car: """一次模拟汽车的简单尝试""" ...

  6. Java多线程专题5: JUC, 锁

    合集目录 Java多线程专题5: JUC, 锁 什么是可重入锁.公平锁.非公平锁.独占锁.共享锁 可重入锁 ReentrantLock A ReentrantLock is owned by the ...

  7. hashmap 实现 相同的key值时,value值叠加效果。

    一,了解一些基础 package com.ohs.demo; /** * * 一.需求是:停止相同的key值,覆盖效果,将重复的value值,叠加起来. * * 二.hash? 什么是hash? * ...

  8. RTSP实例解析

    以下是某地IPTV的RTSP协商过程: 1.DESCRIBE 请求: //方法和媒体URL DESCRIBE rtsp://118.122.89.27:554/live/ch1008312159479 ...

  9. 【免杀技术】Tomcat内存马-Filter

    Tomcat内存马-Filter型 什么是内存马?为什么要有内存马?什么又是Filter型内存马?这些问题在此就不做赘述 Filter加载流程分析 tomcat启动后正常情况下对于Filter的处理过 ...

  10. 如何在 pyqt 中解决国际化 tr() 函数不起作用的问题

    前言 有些时候我们在父类中使用了 self.tr('XXX'),使用 Qt Linguist 完成翻译并导出 qm 文件后,发现子类中仍然是英文原文.比如下面这段代码: class AlbumCard ...