Smart Client中客户端数据缓存的思考
问题的背景:
最近在写一个基于Smart Client的Bug跟踪软件(BugTiger),在整个系统中有一张核心的表(Bug表),表中大部分列都是外键.因此每次读Bug表的时候需要和其他表进行联接操作,客户端需要的是联接后的Bug表(为方便以下简称BugDetails表).客户端如何取得BugDetails表并进行缓存就是一个很关键的问题.
为什么要进行数据缓存:
1. 为了允许用户进行离线工作.
为了能让客户端在脱机或无法连接到服务器时依旧能够工作,需要对数据进行缓存.这时客户端是对缓存的数据进行操作,网络重新连接时再进行数据同步.
2. 提高应用程序的响应速度.
当用户在客户端进行操作时,不用每次从服务器上读取数据,而是读取本地的数据缓存,这样将有效提高应用程序的响应速度.
3. 减轻服务器负担.
客户端定时从服务器上读取”新”的数据,然后与本地数据进行合并,而不是每次读取全部数据,从而减轻网络和服务器的负担.
如何进行数据缓存:
为便于对问题的讨论,把数据库中的表结构简化如下:
方案一:
在服务器上进行数据表的联结(为方便讨论以下把联结后的表称BugDetails表),客户端下载BugDetails保存在DataSet中. BugDetails中既有SeverityID列,又有SeverityName列.为什么要这么设计?SeverityName在Bug列表时需要使用,显示给用户时当然要使用SeverityName,而不是SeverityID; SeverityID在用户编辑Bug时需要用到,因为不能保证Severity表中的SeverityName是唯一的.多个表的联接使得BugDetails字段非常多.
缺点:
1. 数据下载的冗余非常巨大.如每条记录都有SeverityName,但此属性已经包含在Severity表中.实际BugTiger的Bug表的关系远比示例复杂,数据的冗余是非常的大的,冗余数据超过了1/2.
2. 当父表更改时, BugDetails表中大量数据将成为新的数据,客户端需要重新下载.如Severity表中某条记录更改了SeverityName时,与此记录相关的Bug记录将和Severity表重新联接,生成新的BugDetails记录,客户端需要重新下载这些记录.
3. 客户端增加Bug记录时是先添加到数据缓存中的,当与服务器进行数据同步时再上传数据,而不是直接向服务器上传数据.这样做主要是为了在离线时也能增加Bug.对客户端的BugDetails表进行增加记录时,由于BugDetails表字段非常多,增加操作时需要填写的字段很多,
方案二:
在服务器上不进行联接操作,客户端下载各个Table的数据到DataSet后(把数据库中的Table映射成DataSet中的DataTable),再对DataSet中的DataTable进行联接从而产生新的BugDetails表.
注:多个表的合并可以参见《如何把一个DataTable中的某列通过表关系加到另外一个DataTable中》http://www.cnblogs.com/pcbhyy/archive/
缺点:
1. 需要从多个DataTable生成BugDetails,这个过程涉及的DataTable如果较多时,十分复杂.
2. 任意一张表的数据变化都将导致BugDetails表的重新构建.
方案三:
在客户端增加一个小型的数据库,把服务器上的数据存储到客户端的数据库上.
缺点:
需要维护和操作两个数据库.
目前在BugTiger中使用了第一种方案,想听听大家对这三种方案的看法 .