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的记录?(这会使冲突解决更容易,但可能对您的情况不可行).
总结一下,主要问题是:
参考书目:
SyncML®:同步和管理您的移动数据(在O'Reilly Safari上预订)
乐观复制靖斋藤(HP实验室)和MARC SHAPIRO(微软研究院有限公司) - ACM计算调查,卷.V,No.N,3 2005.
Alexander Traud,Juergen Nagler-Ihlein,Frank Kargl和Michael Weber.2008.通过重用SyncML进行循环数据同步.在第九届移动数据管理国际会议论文集(MDM '08)中.IEEE计算机学会,华盛顿特区,美国,165-172.DOI = 10.1109/MDM.2008.10 http://dx.doi.org/10.1109/MDM.2008.10
Lam,F.,Lam,N.和Wong,R.2002.移动XML数据的高效同步.在第十一届信息与知识管理国际会议论文集(美国弗吉尼亚州麦克莱恩,2002年11月4日至9日).CIKM '02.ACM,纽约,纽约,153-160.DOI = http://doi.acm.org/10.1145/584792.584820
Cunha,PR和Maibaum,TS 1981. Resource&equil; 抽象数据类型+同步 - 面向消息的编程方法 - .在第五届国际软件工程会议论文集(美国加利福尼亚州圣地亚哥,1981年3月9日至12日).国际软件工程会议.IEEE Press,Piscataway,NJ,263-272.
(最后三个来自ACM数字图书馆,不知道你是否是会员或者你是否可以通过其他渠道获得这些).
来自Dr.Dobbs网站:
来自arxiv.org:
我建议你有时间戳记在每个表列,每次插入或更新一次,更新每个受影响的行的时间戳值.然后,迭代所有表,检查时间戳是否比目标数据库中的时间戳更新.如果它更新,请检查是否必须插入或更新.
观察1:请注意物理删除,因为从源db中删除了行,您必须在服务器db上执行相同的操作.您可以解决这个问题,避免物理删除或使用时间戳记录表中的每个删除.这样的事情:DeletedRows = (id, table_name, pk_column, pk_column_value, timestamp)所以,你必须读取DeletedRows表的所有新行,并使用table_name,pk_column和pk_column_value在服务器上执行删除.
观察2:注意FK,因为在与另一个表相关的表中插入数据可能会失败.您应该在数据同步之前停用每个FK.
小智 5
如果有人遇到类似的设计问题并需要在多个Android设备上同步更改,我建议您检查Google Cloud Messaging for Android(GCM).
我正在研究一种解决方案,其中必须将在一个客户端上完成的更改传播到其他客户端.我刚刚实现了一个概念验证实现(服务器和客户端),它就像一个魅力.
基本上,每个客户端都会向服务器发送增量更改.例如,资源ID ABCD1234已从值100更改为99.
服务器根据其数据库验证这些增量更改,并批准更改(客户端同步)并更新其数据库或拒绝更改(客户端不同步).
如果服务器批准了更改,则服务器然后通过GCM通知其他客户端(不包括发送增量更改的客户端),并发送携带相同增量更改的多播消息.客户端处理此消息并更新其数据库.
很酷的是,这些变化几乎瞬间传播!如果这些设备在线.我不需要在这些客户端上实现任何轮询机制.
请记住,如果设备离线时间过长且GCM队列中有超过100条消息等待传递,GCM将丢弃这些消息,并在设备重新联机时发送特殊消息.在这种情况下,客户端必须与服务器完全同步.
还请查看本教程以开始使用CGM客户端.
这回答了使用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)