我正在寻找一些将中央服务器上的数据与不总是在线的客户端应用程序同步的一般策略。
在我的特定情况下,我有一个带有sqlite数据库的android手机应用程序和带有MySQL数据库的PHP Web应用程序。
用户可以在手机应用程序和Web应用程序上添加和编辑信息。我需要确保即使手机无法立即与服务器通信,在一个地方进行的更改也会反映出来。
我不关心如何将数据从手机传输到服务器,反之亦然。我只提到我的特定技术,因为我不能使用,例如,MySQL可用的复制功能。
我知道客户端 - 服务器数据同步问题已经存在了很长时间,并且需要有关处理问题的模式的信息 - 文章,书籍,建议等。我想知道处理同步的一般策略,以比较优势,劣势和权衡。
答案 0 :(得分:81)
答案 1 :(得分:7)
我建议您在每个表中都有 timestamp 列,每次插入或更新时,都要更新每个受影响行的时间戳值。然后,迭代所有表,检查时间戳是否比目标数据库中的时间戳更新。如果它更新,请检查是否必须插入或更新。
观察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将丢弃这些消息,并在设备重新联机时发送特殊消息。在这种情况下,客户端必须与服务器完全同步。
同时检查this tutorial以开始使用CGM客户端。
答案 3 :(得分:5)
这回答了使用Xamarin框架的开发人员(请参阅https://stackoverflow.com/questions/40156342/sync-online-offline-data)
使用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>();
4)然后推送和提取您的数据以确保我们有最新的更改:
await this.MobileService.SyncContext.PushAsync();
await this.saleItemsTable.PullAsync("allFoos", fooTable.CreateQuery());
答案 4 :(得分:0)
我建议你也看看Symmetricds。它是一个可供Android系统使用的SQLite复制库。您可以使用它来同步您的客户端和服务器数据库,我还建议在服务器上为每个客户端分别设置数据库。试图将所有用户的数据保存在一个mysql数据库中并不总是最好的主意。特别是如果用户数据将快速增长。
答案 5 :(得分:0)
我们称其为 CUDR同步问题(我不喜欢CRUD,因为“创建/更新/删除”是写操作,应该配对)
也可以从先写offliine优先或先写在线优先的角度看问题。脱机写入方法存在唯一标识符冲突的问题,并且同一事务的多个网络调用增加了风险(或成本)...
我个人发现在线优先写入方法更易于管理(因此它将是唯一的真理来源-从那里同步所有其他事物)。在线写入方法将不要求用户先脱机写入-他们将通过获得良好的在线写入响应表来脱机写入。
他可能首先脱机阅读,并且只要网络可用,就可以从联机获取数据并更新本地数据库,然后更新ui。...
避免唯一标识符冲突的一种方法是使用唯一用户ID +表名或表ID +行ID(由sqlite生成)的组合...,然后使用同步的布尔标志列。但仍然必须先在线注册才能获取将在其上生成所有其他ID的唯一ID ...在这里,问题还在于如果时钟未同步-上面提到的有人...