V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
lixyz
V2EX  ›  Android

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

  •  
  •   lixyz · 2019-03-27 05:19:36 +08:00 · 9201 次点击
    这是一个创建于 2087 天前的主题,其中的信息可能已经有所发展或是发生改变。

    条件:

    首先存储的列表字段有 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 条回复    2019-04-01 18:50:31 +08:00
    yuikns
        1
    yuikns  
       2019-03-27 07:50:01 +08:00
    我理解日历和 sqlite 都是在本地?那么从结构上说,那么是有一些特别的查询必须用 sqlite 么?本地可以只取手机日历作为数据源么?
    MoHen9
        2
    MoHen9  
       2019-03-27 08:44:24 +08:00 via Android
    不太理解问题,但还是说一下吧,可以根据 ID 和 status 复写 entity 的 hashcode 和 equals 方法,这样 map 中的 A/B/C 三张表的数据只有一份被放在 HashMap 或 HashSet 中。
    mooncakejs
        3
    mooncakejs  
       2019-03-27 08:49:16 +08:00 via iPhone
    多加一个 seq 字段,version 更新的时候顺便更新版本号。同步对比版本号就行
    lixyz
        4
    lixyz  
    OP
       2019-03-27 17:55:05 +08:00
    @yuikns 使用场景是这样的
    一个手机 APP,使用到了日历的功能,所以需要日历数据库,同时又添加了一些其他的功能,所以需要本机 SQLite,考虑到了有可能会更换手机,所以要讲数据上传到服务器,以便更换手机时同步数据,所以用到了 Mysql,三个数据库的字段是相同的,所以需要确保三个数据库数据是同步的
    lixyz
        5
    lixyz  
    OP
       2019-03-27 17:56:53 +08:00
    @mooncakejs 添加版本号还需要修改数据库添加字段,可能是最后考虑的手段了
    lixyz
        6
    lixyz  
    OP
       2019-03-27 18:03:17 +08:00
    @MoHen9 你的意思是将三个数据库的数据先全部存在一个 Map 当中,然后再拿这个 Map 依次和三个数据库做比较
    之前想过这么做,但是存在一个问题,因为 Map 的 key 是不能重复的,所以 MapAll 只能存一条 ID,而这条 ID 的 status 有可能是 1 也有可能是 -1,那么在和 A B C 做比较的时候,还挺麻烦的,因为你需要确定 ABC 总是否包含 MapAll 的 key,还需要确定这个 key 对应的 Value 是不是相同,这么做好像没比我的方法简单多少。

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

    但是我感觉有点儿太费劲了,所以想来请教一下有没有其他比较好的比较简单的方法
    thesharjah
        14
    thesharjah  
       2019-04-01 14:46:09 +08:00
    @lixyz 所以你设计的时候应该分主次,以某一个为主,另外两个为从库,写入数据时应该首先写入主,写入成功表示本次操作成功,写入失败则操作失败;操作失败可以有一套失败之后的流程,成功之后才是你需要考虑的同步的问题;此时同步就不会有 status 只能 1 改为- 1 的问题了,同步只是需要保证从库与主库一致,不需要关心任何业务逻辑关系
    lixyz
        15
    lixyz  
    OP
       2019-04-01 18:50:31 +08:00
    @thesharjah 说的有道理。。。感谢感谢
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1177 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 23:50 · PVG 07:50 · LAX 15:50 · JFK 18:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.