V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
lixyz
V2EX  ›  Android

三个存储着相同数据的列表,如何同步效率比较高呢?

  •  
  •   lixyz · Mar 27, 2019 · 12956 views
    This topic created in 2602 days ago, the information mentioned may be changed or developed.

    条件:

    首先存储的列表字段有 id(String 类型) 和 status(只有 1 和 -1 两个状态,且状态只能从 1 修改为 -1,反之不行) 只有 id 和 status 都相同才算是同一个对象 如何保证三个数据库的数据一样呢?


    因为数据库一个是手机日历,一个是手机 SQLite,一个是服务器 Mysql,所以也没有办法在数据库上想办法

    想问下大伙儿,有更好的方法吗?我感觉我这个就是一个最基础的笨方法

    我是这样做的,先拿 A 和 B 同步,保证 A\B 数据是一致的 再拿 A 和 C 做同步,当需要修改 A 的时候,同时也修改 B

    大致代码是这样的:

    public class Test {
    	public static void main(String[] args) {
    		HashMap<String, Bean> mapA = new HashMap<>(16);
    		HashMap<String, Bean> mapB = new HashMap<>(16);
    		HashMap<String, Bean> mapC = new HashMap<>(16);
    		// A、B 两个数据库同步
    		for (String key : mapA.keySet()) {
    			if (mapB.containsKey(key)) {
    				if (mapA.get(key).getStatus() != mapB.get(key).getStatus()) {
    					if (mapB.get(key).getStatus() == 1) {
    						// 将 B 数据库当中的 status 修改为 -1
    					}
    				}
    			} else {
    				// 将 mapA 中 key 对应的 value 插入到 数据库 B 当中
    			}
    		}
    		for (String key : mapB.keySet()) {
    			if (mapA.containsKey(key)) {
    				if (mapB.get(key).getStatus() != mapA.get(key).getStatus()) {
    					if (mapA.get(key).getStatus() == 1) {
    						// 将 A 数据库当中的 status 修改为 -1
    					}
    				}
    			} else {
    				// 将 mapB 中 key 对应的 value 插入到 数据库 A 当中
    			}
    		}
    		//以上操作保证了 A、B 两个数据库是同步的
    		//然后再拿 A 和 C 两个数据库做同步
    		//还是同样的逻辑,但是当需要修改 A 的数据的时候,同时也修改 B 数据库
    		for (String key : mapA.keySet()) {
    			if (mapC.containsKey(key)) {
    				if (mapA.get(key).getStatus() != mapC.get(key).getStatus()) {
    					if (mapC.get(key).getStatus() == 1) {
    						// 将 C 数据库当中的 status 修改为 -1
    					}
    				}
    			} else {
    				// 将 mapA 中 key 对应的 value 插入到 数据库 C 当中
    			}
    		}
    		for (String key : mapC.keySet()) {
    			if (mapA.containsKey(key)) {
    				if (mapC.get(key).getStatus() != mapA.get(key).getStatus()) {
    					if (mapA.get(key).getStatus() == 1) {
    						// 将 A 数据库当中的 status 修改为 -1
    						// 将 B 数据库当中的 status 修改为 -1
    					}
    				}
    			} else {
    				// 将 mapC 中 key 对应的 value 插入到 数据库 A 当中
    				// 将 mapC 中 key 对应的 value 插入到 数据库 B 当中
    			}
    		}
    	}
    }
    
    class Bean {
    	private String key;
    	private int status;
    
    	public String getKey() {
    		return key;
    	}
    
    	public void setKey(String key) {
    		this.key = key;
    	}
    
    	public int getStatus() {
    		return status;
    	}
    
    	public void setStatus(int status) {
    		this.status = status;
    	}
    }
    
    15 replies    2019-04-01 18:50:31 +08:00
    yuikns
        1
    yuikns  
       Mar 27, 2019
    我理解日历和 sqlite 都是在本地?那么从结构上说,那么是有一些特别的查询必须用 sqlite 么?本地可以只取手机日历作为数据源么?
    MoHen9
        2
    MoHen9  
       Mar 27, 2019 via Android
    不太理解问题,但还是说一下吧,可以根据 ID 和 status 复写 entity 的 hashcode 和 equals 方法,这样 map 中的 A/B/C 三张表的数据只有一份被放在 HashMap 或 HashSet 中。
    mooncakejs
        3
    mooncakejs  
       Mar 27, 2019 via iPhone
    多加一个 seq 字段,version 更新的时候顺便更新版本号。同步对比版本号就行
    lixyz
        4
    lixyz  
    OP
       Mar 27, 2019
    @yuikns 使用场景是这样的
    一个手机 APP,使用到了日历的功能,所以需要日历数据库,同时又添加了一些其他的功能,所以需要本机 SQLite,考虑到了有可能会更换手机,所以要讲数据上传到服务器,以便更换手机时同步数据,所以用到了 Mysql,三个数据库的字段是相同的,所以需要确保三个数据库数据是同步的
    lixyz
        5
    lixyz  
    OP
       Mar 27, 2019
    @mooncakejs 添加版本号还需要修改数据库添加字段,可能是最后考虑的手段了
    lixyz
        6
    lixyz  
    OP
       Mar 27, 2019
    @MoHen9 你的意思是将三个数据库的数据先全部存在一个 Map 当中,然后再拿这个 Map 依次和三个数据库做比较
    之前想过这么做,但是存在一个问题,因为 Map 的 key 是不能重复的,所以 MapAll 只能存一条 ID,而这条 ID 的 status 有可能是 1 也有可能是 -1,那么在和 A B C 做比较的时候,还挺麻烦的,因为你需要确定 ABC 总是否包含 MapAll 的 key,还需要确定这个 key 对应的 Value 是不是相同,这么做好像没比我的方法简单多少。

    不知道对于你的方法理解的是不是对的?
    mooncakejs
        7
    mooncakejs  
       Mar 27, 2019
    @lixyz 那就写日志,把数据库的更新操作 append 到文件中,同步的时候替换掉 log 文件,从 log 回复数据
    lixyz
        8
    lixyz  
    OP
       Mar 28, 2019
    @mooncakejs 哈哈哈哈这么操作更麻烦了。。。
    thesharjah
        9
    thesharjah  
       Mar 28, 2019
    怎么感觉题目有点悖论?
    thesharjah
        10
    thesharjah  
       Mar 28, 2019
    status 只能从 1 改为- 1,日历、sqlite、mysql 三个库,总会有主次对吧? 如果主的 status =- 1,次的 status = 1,请问如何保证三个数据库数据一致呢?
    如果业务上不会出现这种场景,那么直接把主同步至次就是了
    hayanami
        11
    hayanami  
       Mar 29, 2019
    同意楼上,你 A,B,C 三个库都是以 A 的数据为主,B,C 做从库定时同步就可以了。
    而且你 mysql 是为了更换手机时同步数据,基本上使用量不大,没有必要即时同步。另外两个库可以通过异步操作,A 库数据变动,异步方法变动 B 库,或者数据库记录更新 log,B,C 可以根据 log 变更
    lixyz
        12
    lixyz  
    OP
       Mar 31, 2019
    @thesharjah @hayanami
    我没有给这三个数据库分主次
    首先 APP 运行的设备肯定是随时联网的,所以在往这三个数据库保存数据的时候,会同时往这三个数据库插入相同的数据,修改(将 status 从 1 修改为 -1 )也是一样的同时进行
    但有可能用户在点击了保存的时候网络突然出现了问题,或者是突然关机,这就有可能会导致本地 SQLite 或者 本地日历 或者云端 MySQL 数据没有保存(更新)成功
    所以就需要在每次打开 APP 的时候检查一下是否有数据可以同步,并提醒用户进行同步
    就按照上面的情形,没有办法确定哪一个数据库是主哪个是次
    只需要保证每一个 ObjectId 都存在于 MySQL\SQLite\手机日历当中,并且他们对应的 status 也是相同的
    lixyz
        13
    lixyz  
    OP
       Mar 31, 2019
    顶楼的代码做的就是分别拿每个数据库和其他两个数据库做比较,然后做出修改

    但是我感觉有点儿太费劲了,所以想来请教一下有没有其他比较好的比较简单的方法
    thesharjah
        14
    thesharjah  
       Apr 1, 2019
    @lixyz 所以你设计的时候应该分主次,以某一个为主,另外两个为从库,写入数据时应该首先写入主,写入成功表示本次操作成功,写入失败则操作失败;操作失败可以有一套失败之后的流程,成功之后才是你需要考虑的同步的问题;此时同步就不会有 status 只能 1 改为- 1 的问题了,同步只是需要保证从库与主库一致,不需要关心任何业务逻辑关系
    lixyz
        15
    lixyz  
    OP
       Apr 1, 2019
    @thesharjah 说的有道理。。。感谢感谢
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   3151 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 41ms · UTC 14:44 · PVG 22:44 · LAX 07:44 · JFK 10:44
    ♥ Do have faith in what you're doing.