目前很多软件厂商针对移动设备的数据库同步解决方案,这些方案主要分为两种:第一种,是针对某种特定数据库提供的数据同步方案,比如
SQL Sever的
RDA和
Replication、
Oracle Lite和
Sybase SQL Anywhere等;第二种是
ISV开发的针对不同数据库的数据同步方案。
SQL Mobile支持两种数据同步的方法:
Remote data access(
RDA)和
Replication。这两种方法都支持从远程的
SQL Server服务器中下载数据到设备端的
SQL Mobile数据库中,在本地对数据进行浏览和修改,再将修改结果更新到
SQL Server服务器中。
RDA和
Replication都需要配置
SQL Mobile Server Tools,也就是说,必须要有一个运行
IIS的
Web Server。
Server Tools的主要作用是将移动设备通过网络发送的数据库访问请求,转发给
SQL Server数据库,并将结果集发送回移动设备中。
移动设备使用
RDA和
Replication时,
SQL Mobile只需要连接
IIS上的
Server Tools。而数据同步需要
HTTP或
HTTPS的网络连接支持。网络连接可以是无线局域网(
Wi-Fi)、无线网或通过
AtiveSync连接的
PC网络。
1 RDA架构
RDA使用了
SQL Mobile中的三个组件:
SQL Mobile Database Engine、
SQL Mobile Client Agent和
SQL Mobile Server Agent。
RDA的运行过程如下图:
SQL Mobile Database Engine用于管理存储于
SQL Mobile数据库中的数据。如果这些数据来自于远程
SQL Server数据库,并且在调用
Pull操作时设置了跟踪改变的选项,
Database Engine还将跟踪整个程序运行过程中数据表的变化情况,比如
insert、
update和
delete等操作。
Database Engine将为每条记录维护更新记录。如果
SQL Server数据表建有索引,那么
RDA也支持在
SQL Mobile数据表中建立索引。
SQL Mobile Client Agent是运行于
Windows Mobile上的一个组件,主要负责与
Server Agent的通讯。
Client Agent实现了
RDA对象的
API,应用程序通过
API来操作
RDA。
RDA的
Pull方法被调用时,
Client Agent会通过
HTTP向
SQL Mobile Server Agent发送请求。当接收到从
SQL Server返回的结果集后,
Client Agent将结果集保存到
SQL Mobile数据库中。
Push方法被调用时,
Client Agent从
SQL Mobile数据库中取出所有插入、更新和删除的记录,将它们发送给
Server Agent。
SubmitSQL方法,将
SQL语句通过
HTTP发送给
Server Agent。
RDA使用运行于
IIS上的
Server Agent作为
SQL Server数据库与
SQL Mobile数据之间的通信代理。
Server Agent负责监听来自
SQL Mobile Client Agent的
HTTP请求。
Server Agent使用临时消息文件
(*.in和
*.out)来管理
SQL Server与
SQL Mobile的交换数据。
当
Client Agent调用
Pull方法时,
Server Agent会收到请求,然后通过
OLE DB连接
SQL Server数据库,调用
SQL语句。
Server Agent会将返回的结果集通过
HTTP发送给
Client Agent。
Push方法,
Server Agent会收到所有被客户端修改的记录,通过
OLE DB连接
SQL Server数据库,然后对
SQL Server中相应记录进行
insert、
update和
delete操作。如果发生错误,
Server Agent会向
Client Agent报告这个错误。
SubmitSQL方法,接受指定的
SQL语句,通过
OLE DB连接
SQL Server数据库,然后调用
SQL语句。
2 创建RDA程序
在
.NET Compact Framework中有一个
SqlCeRemoteDataAccess对象,提供了
RDA的应用程序编程接口。
SqlCeRemoteDataAccess类的命名空间是
System.Data.SqlServerCe。
SqlCeRemoteDataAccess类中包括了三个最主要的方法:
1)
Pull方法:从
SQL Server数据库中获取一个数据表,储存在
SQL Mobile数据表中
2)
Push方法:将
Pull方法获得的
SQL Mobile数据表,在设备端的修改传回到
SQL Server 数据库中
3)
SubmitSql方法:将
SQL语句直接提交到
SQL Server数据库中执行。
2.1 Pull方法
在调用
Pull方法之前,我们必须创建
SqlCeRemoteDataAccess的对象,并对
RDA的属性进行设置。
我们通过下面的一段代码来说明如何创建一个
SqlCeRemoteDataAccess对象,并调用
Pull方法。
//
Connection String to the SQL Server.
string
rdaOleDbConnectString
=
"
Provider=sqloledb; Data Source=MySqlServer;Initial Catalog=Northwind;
"
+
"
User Id=username;Password = <password>
"
;
//
Initialize RDA Object.
SqlCeRemoteDataAccess rda
=
null
;
try

...
{
//Try the Pull Operation.
rda = new SqlCeRemoteDataAccess();
rda.InternetLogin = "MyLogin";
rda.InternetPassword = "<password>";
rda.InternetUrl = "<[url]http://www.northwindtraders.com/sqlce/sscesa20.dll>[/url]";
rda.LocalConnectionString = @"Provider=Microsoft.SQLSERVER.OLEDB.CE.2.0;Data Source=\ssce.sdf";
rda.Pull(
"Employees",
"Select * from Employees",
rdaOleDbConnectString,
RdaTrackOption.TrackingOnWithIndexes,
"ErrorTable");
}
catch
(SqlCeException)

...
{
//Use you own Error Handling Routine.
}
finally

...
{
//Dispose of the RDA Object.
rda.Dispose();
}
SqlCeRemoteDataAccess对象创建后,我们需要设置
InternetUrl属性,该属性是指定
SQL Mobile Server Tools的
URL,也就是我们在
IE中输入的
URL。
如果
Server Tools所在的
IIS设置了访问用户名和密码的话,我们还需要设置
InternetLogin和
InternetPassword属性,这两个属性分别对应
IIS访问用户名和密码。除此之外,我们还需要设置
LocalConnectionString属性,该属性提供一个
SQL Mobile的数据库连接字符串。我们可以不必在连接字符串中设置
Provider,这样系统就会默认使用
SQL Mobile数据库支持库了,但是
Data Source必须指定
SQL Mobile数据库在
Windows Mobile设备中的绝对路径。
大家也可以看到,
SqlCeRemoteDataAccess对象中的属性主要是和
SQL Mobile数据库、
SQL Mobile Server Tools有关,而没有
SQL Server的相关设置,我们稍后会进行说明。
当
SqlCeRemoteDataAccess对象所需要的属性被设置完成后,我们就可以调用
Pull方法了。
Pull方法最多可以包括五个参数,我们依次来看一下函数原型和相关参数:
public
void
Pull (
string
localTableName,
string
sqlSelectString,
string
oleDBConnectionString,
RdaTrackOption trackOption,
string
errorTable
)
localTableName参数指定了在
SQL Mobile数据库中的数据表名称,该数据表用于存放
Pull方法从
SQL Server获得的数据。
sqlSelectString参数,用于设置从
SQL Server获取的数据集的
SQL语句,我们可以通过这个
SQL语句设置获得结果集是某个数据表的子集。我们可以通过设置
WHERE子句来获得某个数据表的子集。
oleDBConnectionString参数指定
SQL Server的数据库连接字符串,在
Pull方法指定
SQL Server数据库连接字符串,而不是在
SqlCeRemoteDataAccess对象属性中设置,是因为我们可以在一个
SqlCeRemoteDataAccess对象中指定从多个
SQL Server中获取数据。
trackOption参数用于
SQL Mobile数据表的数据跟踪设置,指定
RdaTrackOption枚举变量。
errorTable属性用于设置一个数据表的名称,该数据表用于在
Push方法的时候发生数据冲突时,会将数据错误信息放到
Error Table中。
下面我们来讨论下
trackOption参数,如果从
SQL Server中获取的数据需要在设备端进行修改,并且要将修改结果提交回
SQL Server数据库的话,就需要将该参数设置为
TrackingOn;如果数据不需要提交回
SQL Server数据库的话,就需要设置为
TrackingOff,比如需要获得商品的价格信息,而这些信息不需要在设备端修改,我们就可以设置为
TrackingOff,这样做还可以节省一部分空间。
TrackingOff
|
SQL Mobile不会跟踪本地数据改变,
PRIMARY KEY约束在本地创建
|
TrackingOffWithIndexes
|
SQL Mobile不会跟踪本地数据改变,存在于
SQL Server数据表中的索引和
PRIMARY KEY约束会被在本地表创建。
|
TrackingOn
|
SQL Mobile会跟踪本地数据改变,
PRIMARY KEY约束在本地创建,这是默认设置
|
TrackingOnWithIndexes
|
SQL Mobile会跟踪本地数据改变,存在于
SQL Server数据表中的索引和
PRIMARY KEY约束会被在本地表创建。
|
这里需要注意的是,
Pull方法一次只可以从
SQL Server获取一个数据表,而设置的本地表名称,
SQL Mobile数据库不能存在同名的数据表,所以每次通过
Pull方法获取新的数据时,必须先删除上次
Pull方法获得的本地表。
2.2 Push方法
我们下边来看一下
Push方法。
Push方法用来把
SQL Mobile本地表的修改结果传递回
SQL Server数据库中。下面的代码相对比较简单:
rda.Push(
"
MyLocalTable
"
,
rdaOleDbConnectString,
RdaBatchOption.BatchingOn);
我们先来看下函数原型与参数:
public
void
Push (
string
localTableName,
string
oleDBConnectionString,
RdaBatchOption batchOption
)
localTableName是
SQL Mobile数据库中的通过
Pull方法获取的数据表,这个表不能是一个
SQL Mobile普通的本地数据表;也不能是
Pull方法设置为
TrackingOff时获取的表。
oleDBConnectionString和
Pull方法中同名的参数作用相同,用于连接
SQL Server的数据库连接字符串,该字符串必须和对应
Pull方法的
oleDBConnectionString相同。
batchOption参数是用于设置我们的数据是否批量提交,该参数是一个
RdaBatchOption枚举变量。如果设置成
BatchingOff,被修改的数据将被逐条提交,如果其中某些数据产生冲突,将不会影响另外数据的提交,但是这样的问题是数据量会增加,这也是默认选项;
BatchingOn会将所有发生改变的数据记录批量提交。
2.3 SubmitSQL方法
最后来看
SubmitSQL方法,该方法会将一个
SQL语句提交到
SQL Server服务器中执行。为什么还需要这样的方法呢。如果我们需要写一个数据捕捉的程序,将捕捉到的数据提交到
SQL Server服务器中。如果使用
Pull方法从
SQL Server获取一个数据表,然后向其中添加新数据,然后再使用
Push方法提交到
SQL Server中,这样十分麻烦,所以直接使用
SubmitSql方法直接将
SQL语句提交到
SQL Server中执行就可以了。
rda.SubmitSql(
"
CREATE TABLE MyRemoteTable (colA int)
"
,
rdaOleDbConnectString);
我们来看
SubmitSQL的原型:
public
void
SubmitSql (
string
sqlString,
string
oleDBConnectionString
)
sqlString参数需要指定
SQL语句,该
SQL语句是在远程
SQL Server中执行,而不是在
SQL Mobile数据库中执行。另外由于
SubmitSql方法不会返回一个结果集,所以我们可以用
SubmitSql方法提交一个
insert、
update、
delete和
create table等
SQL语句,但是提交
select的
SQL语句将没有任何效果。
oleDBConnectionString与
Pull、
Push方法中的同名属性相同,用于设置
SQL Server数据库的连接字符串。
3 RDA局限性
SQL Mobile的
RDA主要有下面的几个限制:
1) 在使用
RDA的
Pull方法从
SQL Server数据库中复制数据时,
SQL语句不能使用
*号代替数据字段,也就是说,我们应该将
SQL语句写成“
SELECT CompanyName, ContactName FROM Customers”,而不是“
SELECT * FROM Customers”。
2)
SQL Mobile不支持触发器。
3) 如果需要跟踪数据表的改变,数据表中字段的个数作为为
1017(
1024个字段减去七个系统字段),那七个系统字段用于跟踪
RDA数据的变化。
4) 如果
Pull方法的
SQL语句中包括
Computed column,方法调用将失败。
5) 如果
SQL Server数据表中包含
IDENTITY字段。
RDA无法自动管理
IDENTITY字段,因为
IDENTITY字段默认起始值是
1,每次增量为
1。可是在多个
SQL Mobile数据库执行
RDA的情况下,不同数据子集插入记录的
IDENTITY字段可能相同。所以我们必须手工处理可能的冲突。我们可以通过“
ALTER TABLE”
SQL语句来修改数据表的“
SEED”和“
INCREMENT”的值。
例如,
SQL Server数据表中最大的
IDENTITY值为
99,我们执行下面的
SQL语句,再次插入记录时,
IDENTITY值将为
100。
6)
对于
SQL Mobile本地表结构改变,从上边的例子可以看到,我们可以对
Pull方法产生的本地数据表
schema进行一些改变。比如,改变数据表
IDENTITY字段的初始值和增长量。除此之外,我们还可以添加或删除字段的默认值约束、添加或删除外键、添加或删除索引,以及删除表。这些操作是不会影响
RDA的
Push方法正常执行的。
但是,我们不能进行诸如增加、删除字段或修改字段名称、修改表名称、删除主键、改变数据类型定义等操作。这些
Schema的改变将造成
Push方法不能正常执行。
当这些
Schema改变之后,我们必须删除这些
SQL Mobile数据表,通过
Pull方法再次获得该数据表。
ALTER TABLE Orders ALTER COLUMN OrderId IDENTITY (
100
,
1
)
4 RDA错误处理
在
RDA将
SQL Mobile数据库中的修改数据上传到
SQL Server中的过程中,如果发生错误,
RDA提供了一个
Error Table,
Push方法发生的错误将被记录在该表中。在调用
Push方法时,我们可以指定一个
Error Table的名称,如果
Push过程中发生错误,
SQL Mobile将自动在
SQL Mobile数据库中创建
Error Table,记录错误信息。
当
SQL Mobile中的一条记录无法被
Push到
SQL Server中时,
RDA会产生一个错误。产生错误的原因可能是:
1)在
SQL Mobile数据库中插入的记录主键在
SQL Server数据表中已经存在。
2)
SQL Mobile试图更新一条已经被其他用户删除的记录时。
3)如果
Push过程因为网络原因发生中断,但是一些
insert操作已经被插入到
SQL Mobile数据库中,第二个
Push时,会因为记录主键重复而失败。
为了跟踪这些错误,我们在
Pull方法的使用指定
TRACKINGON 或者
TRACKINGON_INDEXES,然后指定
Error Table的名称。在
Push的时候如果有错误发生的话,
SQL Mobile将在
Error Table里创建一条记录。该表主要有三个字段:
s_ErrorDate,设置错误发生的日期和时间;
s_OLEDBErrorNumber,为
OLEDB中返回该错误的
HResult;
s_OLEDBErrorString,则是该错误的描述字符串。
我们可以根据这些错误提示,来修改错误数据。如果相关连的
SQL Mobile数据表被删除,
Error Table也将自动被删除。所以,我们可以将这些数据暂存到其他数据表中,或者下次
Pull时使用另外的本地表名称,以保留这些错误数据。
5 多用户访问
SQL Mobile数据库支持多用户访问,本节我们要讨论在
RDA过程中,多用户访问需要注意的一些问题。应用程序只需要通过
Database Engine与
SQL Mobile数据库进行连接,
Database Engine控制来自应用程序的访问请求,应用程序不需要对数据库访问进行控制。如果需要
SQL Mobile Database Engine可以锁定指定的数据,防止数据被其他应用程序修改。
SQL Mobile RDA的
Server端没有提供并发访问控制机制,也就是说,
SQL Server不会将被下载的数据记录锁定。当应用程序调用
Push方法时,如果
SQL Server中的数据已经发生了变化,
Push过程会将
SQL Mobile中的数据覆盖
SQL Server中已经改变的记录。当然,这会造成被修改数据的丢失。
你可以在程序中通过获取不同数据子集的方式来控制这种情况的发生。也可以通过一个单独的应用程序来操作数据库,使用该应用程序来跟踪记录被修改的情况。
在
RDA过程中,
Database Engine允许其他用户对同一个数据库进行访问。因为
Pull方法会在本地创建一个数据表,以存储来自
SQL Server上的数据。所以,在
Pull方法完成之前,其他用户无法访问该表。当数据被
Push回
SQL Server中时,如果在
Push方法开始之后,
SQL Mobile数据库中的数据发生改变,新的改变将在下一次
Push方法中被提交。如果
SQL Mobile在执行
Push方法后必须再次通过
Pull方法获取新数据,应用程序则必须保证在
Push和
Pull方法调用过程中,不会改变
SQL Mobile数据库中的数据。这样可以保证在
SQL Mobile数据库中的变化不会在删除数据表时丢失。
最后呢,感谢马宁大哥的这篇文章!