同步客户端 - 服务器数据库

Sco*_*ers 78 sql database design-patterns client-server data-synchronization

我正在寻找一些将中央服务器上的数据与不总是在线的客户端应用程序同步的一般策略.

在我的特定情况下,我有一个带有sqlite数据库的android手机应用程序和带有MySQL数据库的PHP Web应用程序.

用户将能够在电话应用程序和Web应用程序上添加和编辑信息.我需要确保即使手机无法立即与服务器通信,在一个地方进行的更改也会反映在任何地方.

我不关心如何将数据从手机传输到服务器,反之亦然.我只提到我的特定技术,因为我不能使用MySQL可用的复制功能.

我知道客户端 - 服务器数据同步问题已经存在很长很长时间了,并且希望获得有关处理问题的模式的信息 - 文章,书籍,建议等.我想知道处理同步的一般策略,以比较优势,劣势和权衡.

p.m*_*ino 86

您必须决定的第一件事是关于在发生冲突的情况下哪一方被视为"权威"的一般政策.

即:假设1月5日晚上10点在服务器上更改记录#125,并且在1月5日晚上11点在其中一部电话上更改相同的记录(让我们称之为客户端A).最后一次同步是在1月3日.然后用户重新连接,比如1月8日.

在客户端和服务器都知道最后同步的日期的意义上,识别需要更改的内容是"简单的",因此需要协调自上次同步以来创建或更新的任何内容(有关此内容的更多信息,请参见下文).

所以,假设唯一改变的记录是#125.您要么决定两者中的一个自动"赢"并覆盖另一个,要么您需要支持协调阶段,用户可以决定哪个版本(服务器或客户端)是正确的,覆盖另一个版本.

这个决定非常重要,您必须权衡客户的"角色".特别是如果不仅客户端和服务器之间存在潜在冲突,而且如果不同的客户端可以更改相同的记录.

[假设#125可以被第二个客户端(客户端B)修改,那么尚未同步的客户端B可能会提供相同记录的另一个版本,使之前的冲突解决方案没有实际意义]

关于上面的" 创建或更新 "点...如果记录来自其中一个客户端,您如何正确识别记录(假设这在您的问题域中有意义)?假设您的应用管理商家联系人列表.如果客户A说你必须添加一个新创建的John Smith,并且服务器有一个由客户D昨天创建的John Smith ...你是否创建了两个记录,因为你不能确定他们不是不同的人?你会要求用户协调这个冲突吗?

客户是否拥有数据子集的"所有权"?即如果客户端B被设置为区域#5的数据的"权限",客户端A是否可以修改/创建区域#5的记录?(这会使冲突解决更容易,但可能对您的情况不可行).

总结一下,主要问题是:

  • 考虑到分离的客户端在创建新记录之前可能没有访问过服务器,如何定义"身份".
  • 以前的情况,无论解决方案多么复杂,都可能导致数据重复,因此您必须预见如何定期解决这些问题以及如何通知客户他们认为"记录#675"实际上已被合并/取代记录#543
  • 决定是否通过命令解决冲突(例如"如果前者自上次同步以来已经更新,服务器版本总是胜过客户端")或者通过人工干预
  • 对于命令,特别是如果您决定客户端优先,您还必须处理如何处理可能会有更多更改的其他尚未同步的客户端.
  • 前面的项目没有考虑数据的粒度(为了使事情更容易描述).我只想说,在"记录"级别,而不是在我的例子中,您可能会发现更适合在字段级别记录更改.或者一次处理一组记录(例如人员记录+地址记录+联系人记录),将其汇总视为一种"元记录".

参考书目:

(最后三个来自ACM数字图书馆,不知道你是否是会员或者你是否可以通过其他渠道获得这些).

来自Dr.Dobbs网站:

  • 使用SQL Server CE和SQL RDA创建应用程序Bill Wagner 2004年5月19日(设计桌面和移动PC应用程序的最佳实践--Windows/.NET)

来自arxiv.org:

  • 无冲突复制JSON数据类型 - 本文描述了JSON CRDT实现(无冲突复制数据类型 - CRDT - 是一系列支持并发修改并保证此类并发更新收敛的数据结构).

  • 我倾向于将"删除"视为"更新"的特殊情况,特别是因为在这种情况下我倾向于"逻辑删除"而不是"物理删除".因此,对于我来说,主要或从属方面的"删除"意味着"特殊布尔被删除标志已被翻转"比其他任何东西都要多. (7认同)
  • +1这是一篇很棒的帖子,其中包含有关该问题的重要信息.缺少一点:同步已删除的记录. (3认同)

Fra*_*ein 8

我建议你有时间戳记在每个表列,每次插入或更新一次,更新每个受影响的行的时间戳值.然后,迭代所有表,检查时间戳是否比目标数据库中的时间戳更新.如果它更新,请检查是否必须插入或更新.

观察1:请注意物理删除,因为从源db中删除了行,您必须在服务器db上执行相同的操作.您可以解决这个问题,避免物理删除或使用时间戳记录表中的每个删除.这样的事情:DeletedRows = (id, table_name, pk_column, pk_column_value, timestamp)所以,你必须读取DeletedRows表的所有新行,并使用table_name,pk_column和pk_column_value在服务器上执行删除.

观察2:注意FK,因为在与另一个表相关的表中插入数据可能会失败.您应该在数据同步之前停用每个FK.

  • 时钟必须同步 (2认同)

小智 5

如果有人遇到类似的设计问题并需要在多个Android设备上同步更改,我建议您检查Google Cloud Messaging for Android(GCM).

我正在研究一种解决方案,其中必须将在一个客户端上完成的更改传播到其他客户端.我刚刚实现了一个概念验证实现(服务器和客户端),它就像一个魅力.

基本上,每个客户端都会向服务器发送增量更改.例如,资源ID ABCD1234已从值100更改为99.

服务器根据其数据库验证这些增量更改,并批准更改(客户端同步)并更新其数据库或拒绝更改(客户端不同步).

如果服务器批准了更改,则服务器然后通过GCM通知其他客户端(不包括发送增量更改的客户端),并发送携带相同增量更改的多播消息.客户端处理此消息并更新其数据库.

很酷的是,这些变化几乎瞬间传播!如果这些设备在线.我不需要在这些客户端上实现任何轮询机制.

请记住,如果设备离线时间过长且GCM队列中有超过100条消息等待传递,GCM将丢弃这些消息,并在设备重新联机时发送特殊消息.在这种情况下,客户端必须与服务器完全同步.

还请查看本教程以开始使用CGM客户端.


Ben*_*evy 5

这回答了使用Xamarin框架的开发人员(请参阅/sf/ask/2810943971/)

使用xamarin框架实现此目的的一种非常简单的方法是使用Azure的脱机数据同步,因为它允许根据需要从服务器推送和提取数据.读操作在本地完成,写操作按需推送; 如果网络连接中断,则写入操作将排队,直到连接恢复,然后执行.

实现相当简单:

1)在Azure门户中创建移动应用程序(您可以在这里免费试用https://tryappservice.azure.com/)

2)将您的客户端连接到移动应用程序. https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-xamarin-forms-get-started/

3)设置本地存储库的代码:

const string path = "localrepository.db";

//Create our azure mobile app client
this.MobileService = new MobileServiceClient("the api address as setup on Mobile app services in azure");

//setup our local sqlite store and initialize a table
var repository = new MobileServiceSQLiteStore(path);

// initialize a Foo table
store.DefineTable<Foo>();

// init repository synchronisation
await this.MobileService.SyncContext.InitializeAsync(repository);
var fooTable = this.MobileService.GetSyncTable<Foo>();
Run Code Online (Sandbox Code Playgroud)

4)然后推送和提取您的数据以确保我们有最新的更改:

await this.MobileService.SyncContext.PushAsync();
await this.saleItemsTable.PullAsync("allFoos", fooTable.CreateQuery());
Run Code Online (Sandbox Code Playgroud)

https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-xamarin-forms-get-started-offline-data/