基于guava的数据结构实现数据库增量同步

如何实现数据库的增量同步?

 1、背景介绍

   在开发中,针对数据需要批量操作时(一次批量操作中需要新增/修改/删除)。最直接的作法先在数据库中逻辑删除存在的数据,然后批量写入。或者对批量提交的数据进行遍历针对某些特性进行相关的操作。

2、guava的Sets.difference和Sets.intersection介绍

import com.google.common.collect.Sets;

import java.util.*;

public class Test {
    public static void main(String[] args) {
        List<String> oldList = Arrays.asList("1","2","3","5","7","9");
        List<String> newList = Arrays.asList("1","3","4","8","9","10");
        Set<String> oldSet = new HashSet<>(oldList);
        Set<String> newSet = new HashSet<>(newList);
        Set<String> difference = Sets.difference(oldSet, newSet);
        System.out.println(difference);
        Set<String> intersection = Sets.intersection(oldSet, newSet);
        System.out.println(intersection);
    }
}

输出:

difference:[2, 5, 7]
intersection:[1, 3, 9]

3、经测试可以得知

  • Sets.difference取两个集合中的差集(在A集合中存在,在B集合中不存在的数据)
  • Sets.intersection取两个集合的交集

4、由此可以构想,比较批量提交的数据和数据库中的数据通过构造数据特征来实现数据库的增量处理,直接上代码

/**
 * @author yanyapan
 */
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import java.util.List;
import java.util.Map;
import java.util.Set;

public class DiffUtil {

    /**
     *
     * @param newDataList
     * @param oldDataList
     * @param func
     * @param <T>  新提交的数据类型
     * @param <D>  从db查询出的数据类型
     * @param <K>  T,D 数据的唯一标示类型,一般使用 Integer或String
     * @return
     */
    public static <T, D, K> DiffResult<T, D> getDataDiff(List<T> newDataList, List<D> oldDataList, final DiffFunc<T, D, K> func) {
        if (newDataList == null) {
            newDataList = Lists.newLinkedList();
        }
        if (oldDataList == null) {
            oldDataList = Lists.newLinkedList();
        }
        DiffResult<T, D> result = new DiffResult<>();
        Map<K, T> newMap = Maps.uniqueIndex(newDataList, func::newUniqueIndex);
        Map<K, D> oldMap = Maps.uniqueIndex(oldDataList, func::oldUniqueIndex);
        Set<K> toDelete = Sets.difference(oldMap.keySet(), newMap.keySet());
        Set<K> toUpdate = Sets.intersection(newMap.keySet(), oldMap.keySet());
        Set<K> toInsert = Sets.difference(newMap.keySet(), toUpdate);
        if (toDelete != null && toDelete.size() > 0) {
            for (K key : toDelete) {
                result.getToDelete().add(oldMap.get(key));
            }
        }
        if (toUpdate != null && toUpdate.size() > 0) {
            for (K key : toUpdate) {
                result.getToUpdate().add(newMap.get(key));
            }
        }
        if (toInsert != null && toInsert.size() > 0) {
            for (K key : toInsert) {
                result.getToInsert().add(newMap.get(key));
            }
        }
        return result;
    }
}
/**
 * @author yanyapan
 * 构造数据特征实现数据库增量处理
 */
public interface DiffFunc<T, D, K> {

    /**
     *
     * @param data
     * @return
     */
    K newUniqueIndex(T data);

    /**
     * d
     * @param data
     * @return
     */
    K oldUniqueIndex(D data);
}
/**
* 用于增量处理的结果集 * @author yanyapan */ import com.google.common.collect.Lists; import java.io.Serializable; import java.util.List; public class DiffResult<T, D> implements Serializable { private List<T> toInsert = Lists.newLinkedList(); private List<T> toUpdate = Lists.newLinkedList(); private List<D> toDelete = Lists.newLinkedList(); public List<D> getToDelete() { return toDelete; } public void setToDelete(List<D> toDelete) { this.toDelete = toDelete; } public List<T> getToInsert() { return toInsert; } public void setToInsert(List<T> toInsert) { this.toInsert = toInsert; } public List<T> getToUpdate() { return toUpdate; } public void setToUpdate(List<T> toUpdate) { this.toUpdate = toUpdate; } }

 5、工具类使用

import java.util.*;

public class Test {
    public static void main(String[] args) {
        List<String> oldList = Arrays.asList("1","2","3","5","7","9");
        List<String> newList = Arrays.asList("1","3","4","8","9","10");
        DiffResult<String, String> dataDiff = DiffUtil.getDataDiff(newList, oldList, new DiffFunc<String, String, String>() {
            /**
             * @param data
             * @return
             */
            @Override
            public String newUniqueIndex(String data) {
                return data;
            }
            /**
             *
             * @param data
             * @return
             */
            @Override
            public String oldUniqueIndex(String data) {
                return data;
            }
        });
        System.out.println("dataDiff.getToInsert():" + dataDiff.getToInsert());
        System.out.println("dataDiff.getToUpdate():" + dataDiff.getToUpdate());
    }
}

dataDiff.getToInsert():[4, 8, 10]
dataDiff.getToUpdate():[1, 3, 9]

7、总结

  • 对不同的场景、合理使用数据结构以及相关的工具类
  • 了解不同数据结构的特性,可分析jdk中相关的集合

8、拓展

该工具类支持数据库一对一表结构,对于多对多表结构各位可以思考如何实现。关键点:如何构造多对多表结构下的数据特征?

posted @ 2020-03-27 15:02  yanyapan  阅读(519)  评论(0编辑  收藏  举报