自定义数据库同步程序

最近在做一个数据库同步的项目,数据库都是sql,编程语言是c#。

如果是两个实体服务器之间的数据库同步,利用sql的发布订阅就可实现。但是现在这个是要同步服务器和微软azure上的数据库,发布订阅是不行了,只有手动编写数据库同步程序。

而且,我们的数据库比较复杂,各个表之间都有关联,而且ID都是自动增长类型的。查阅了很多资料,都不可行,最后终于找到了一篇文献资料,然后完美的解决了我的问题。

1)、首先,不要循环把每条数据更新到数据库。这种方法不很现实,哪怕数据量非常小,而且还要保证网络连接非常的好。即使满足这些,长时间运行还是会出现连接的timeout超时,等等...

2)、所以,最好用批量导入更新数据的方法,就是SqlDataAdapter。如果单纯的是导入数据,也可以用bulk了,网上代码很多,但是如果有导入和更新那就最好用SqlDataAdapter了。


下面上代码,

1、首先把查询的数据库记录保存下来,查询语句类似于以下语句:

SqlConnection conn = new SqlConnection(ConnectionString);//ConnectionString是数据库连接语句字符串,包含服务器名,数据库名,用户名,密码等

string Querystr=“select * from 表名”;//查询语句字符串。

(复杂一点的语句,灵活运用sql查询语句,现在sql运行一下,没问题就放心写入c#里面。

Querystr = "select * from 表A join 表B on 表A.EfficiencyID=表B.EfficiencyID where left(表A.ShiftCode,8)>CONVERT(varchar(100), GETDATE()-" + day + ", 112)";)

SqlDataAdapter da=new SqlDataAdapter(Querystr, conn);

DataSet ds=new DataSet();

da.Fill(ds);//填充数据集
 ids.Add(str, ds);

2、获得了查询结果,程序里怎么摆布都行,我的是从ds里面辨别出哪条语句是插入的insert,哪条语句是更新的update。

插入代码如下:

DataSet dss = new DataSet();
            adapter = new SqlDataAdapter(cmd);
            commandBulider = new SqlCommandBuilder(adapter);
            commandBulider.ConflictOption = ConflictOption.OverwriteChanges; 

                adapter.SelectCommand = new SqlCommand("select ShiftCode,StartTime,EndTime,StartPlanDownTime,EndPlanDownTime,Overtime,IsClosed from Shift", conn);
                adapter.InsertCommand = new SqlCommand("insert into Shift (ShiftCode,StartTime,EndTime,StartPlanDownTime,EndPlanDownTime,Overtime,IsClosed) values (RTRIM(@ShiftCode),@StartTime,@EndTime,@StartPlanDownTime,@EndPlanDownTime,@Overtime,@IsClosed)", conn);
                adapter.InsertCommand.Parameters.Add("@ShiftCode", SqlDbType.Char, 10, "ShiftCode");
                adapter.InsertCommand.Parameters.Add("@StartTime", SqlDbType.DateTime, 8, "StartTime");
                adapter.InsertCommand.Parameters.Add("@EndTime", SqlDbType.DateTime, 8, "EndTime");
                adapter.InsertCommand.Parameters.Add("@StartPlanDownTime", SqlDbType.DateTime, 8, "StartPlanDownTime");
                adapter.InsertCommand.Parameters.Add("@EndPlanDownTime", SqlDbType.DateTime, 8, "EndPlanDownTime");
                adapter.InsertCommand.Parameters.Add("@Overtime", SqlDbType.Decimal, 5, "Overtime");
                adapter.InsertCommand.Parameters.Add("@IsClosed", SqlDbType.Bit, 1, "IsClosed");
                adapter.InsertCommand.UpdatedRowSource = UpdateRowSource.None;
                adapter.UpdateBatchSize = 0;

                adapter.Fill(dss);
                for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
                {
                    object[] row = {ds.Tables[0].Rows[i].ItemArray.GetValue(1).ToString().Trim(),
                               ds.Tables[0].Rows[i].ItemArray.GetValue(2).ToString().Trim(),
                               ds.Tables[0].Rows[i].ItemArray.GetValue(3).ToString().Trim(),
                               ds.Tables[0].Rows[i].ItemArray.GetValue(5).ToString().Trim(),
                               ds.Tables[0].Rows[i].ItemArray.GetValue(6).ToString().Trim(),
                               ds.Tables[0].Rows[i].ItemArray.GetValue(8).ToString().Trim(),
                               ds.Tables[0].Rows[i].ItemArray.GetValue(9).ToString().Trim()};
                    dss.Tables[0].Rows.Add(row);
                }
            try
            {             
                int nn = adapter.Update(dss.Tables[0]);//返回影响的行数
                if (nn != ds.Tables[0].Rows.Count)
                {
                    Console.WriteLine("-------------" + tableName + "插入不成功--------------");
                }
            }
            catch (Exception e)
            {
                if (sw != null)
                {
                    sw.WriteLine(tableName + "插入数据到数据库出错:" + e.ToString()  );
                }
                return false;
            }
            finally
            {
                dss.Dispose();
                adapter.Dispose();
                commandBulider.Dispose();
            }


更新代码如下:

DataSet dss = new DataSet();
            adapter = new SqlDataAdapter(cmd);
            commandBulider = new SqlCommandBuilder(adapter);
            commandBulider.ConflictOption = ConflictOption.OverwriteChanges;
            
                adapter.SelectCommand = new SqlCommand("select top "+ds.Tables[0].Rows.Count.ToString()+" ShiftCode,StartTime,EndTime,StartPlanDownTime,EndPlanDownTime,Overtime,IsClosed from Shift", conn);
                adapter.Fill(dss);
                adapter.UpdateCommand = new SqlCommand("update Shift set StartTime=@StartTime,EndTime=@EndTime,StartPlanDownTime=@StartPlanDownTime,EndPlanDownTime=@EndPlanDownTime,Overtime=@Overtime,IsClosed=@IsClosed where RTRIM(ShiftCode)=RTRIM(@ShiftCode)", conn);
                adapter.UpdateCommand.Parameters.Add("@ShiftCode", SqlDbType.Char, 10, "ShiftCode");
                adapter.UpdateCommand.Parameters.Add("@StartTime", SqlDbType.DateTime, 8, "StartTime");
                adapter.UpdateCommand.Parameters.Add("@EndTime", SqlDbType.DateTime, 8, "EndTime");
                adapter.UpdateCommand.Parameters.Add("@StartPlanDownTime", SqlDbType.DateTime, 8, "StartPlanDownTime");
                adapter.UpdateCommand.Parameters.Add("@EndPlanDownTime", SqlDbType.DateTime, 8, "EndPlanDownTime");
                adapter.UpdateCommand.Parameters.Add("@Overtime", SqlDbType.Decimal, 5, "Overtime");
                adapter.UpdateCommand.Parameters.Add("@IsClosed", SqlDbType.Bit, 1, "IsClosed");
                adapter.UpdateCommand.UpdatedRowSource = UpdateRowSource.None;
                adapter.UpdateBatchSize = 0;
               
                for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
                {
                    dss.Tables[0].Rows[i].BeginEdit();
                    dss.Tables[0].Rows[i]["ShiftCode"] = ds.Tables[0].Rows[i]["ShiftCode"].ToString().Trim();
                    dss.Tables[0].Rows[i]["StartTime"] = ds.Tables[0].Rows[i]["StartTime"];
                    dss.Tables[0].Rows[i]["EndTime"] = ds.Tables[0].Rows[i]["EndTime"];
                    dss.Tables[0].Rows[i]["StartPlanDownTime"] = ds.Tables[0].Rows[i]["StartPlanDownTime"];
                    dss.Tables[0].Rows[i]["EndPlanDownTime"] = ds.Tables[0].Rows[i]["EndPlanDownTime"];
                    dss.Tables[0].Rows[i]["Overtime"] = ds.Tables[0].Rows[i]["Overtime"];
                    dss.Tables[0].Rows[i]["IsClosed"] = ds.Tables[0].Rows[i]["IsClosed"];
                    dss.Tables[0].Rows[i].EndEdit();
                }
            try
            { 
                int nn = adapter.Update(dss.Tables[0]);//返回影响的行数
                if (nn != ds.Tables[0].Rows.Count)
                {
                    Console.WriteLine("-------------" + tableName + "插入不成功--------------");
                }
            }
            catch (Exception e)
            {
                if (sw != null)
                {
                    sw.WriteLine(tableName + "插入数据到数据库出错:" + e.ToString()  );
                }
                return false;
            }
            finally
            {
                dss.Dispose();
                adapter.Dispose();
                commandBulider.Dispose();
            }


有一种sql的CLR的类型,c#识别不了,就是hierarchyid类型,它是sql里的树形结构类型,在c#里面可以用SqlDbType.Char来处理,插入数据库的时候用CAST(@SiteNode as HierarchyId)语句就可以了,类似于:

adapter.InsertCommand = new SqlCommand("insert into SiteNode (SiteCode,SiteNode,SiteGroup,IsLeaf,IsParentInput,IsParentOutput,TargetRunRate,TargetCycleTime,MeasuredCycleTime) "
                    + "values (RTRIM(@SiteCode),CAST(@SiteNode as HierarchyId),RTRIM(@SiteGroup),@IsLeaf,@IsParentInput,@IsParentOutput,@TargetRunRate,@TargetCycleTime,@MeasuredCycleTime)", conn);
                adapter.InsertCommand.Parameters.Add("@SiteNode", SqlDbType.Char, 20, "SiteNode");//hierarchyid

但是update的时候用类似的方法就不行了,我目前还没找到解决方法,用的另外的方法解决的。就是上面提到的一条一条的插入,因为只有这一个表,基本不怎么变化,所以只好采用这种方法了。代码如下:

for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
                {
                    string strUpdate = "update SiteNode set SiteNode='" + ds.Tables[0].Rows[i].ItemArray.GetValue(2).ToString().Trim()
                            + "',SiteGroup='" + ds.Tables[0].Rows[i].ItemArray.GetValue(3).ToString().Trim()
                            + "',IsLeaf='" + ds.Tables[0].Rows[i].ItemArray.GetValue(4).ToString().Trim()
                            + "',IsParentInput='" + ds.Tables[0].Rows[i].ItemArray.GetValue(5).ToString().Trim()
                            + "',IsParentOutput='" + ds.Tables[0].Rows[i].ItemArray.GetValue(6).ToString().Trim()
                            + "',TargetRunRate=" + ds.Tables[0].Rows[i].ItemArray.GetValue(7).ToString().Trim()
                            + ",TargetCycleTime=" + ds.Tables[0].Rows[i].ItemArray.GetValue(8).ToString().Trim()
                            + ",MeasuredCycleTime=" + ds.Tables[0].Rows[i].ItemArray.GetValue(9).ToString().Trim()
                            + " where SiteCode='" + ds.Tables[0].Rows[i].ItemArray.GetValue(1).ToString().Trim() + "'";
                    SqlCommand mycommand = new SqlCommand(strUpdate, conn);
                    mycommand.ExecuteNonQuery();
                    mycommand.Dispose();
                }


目前,数据库同步就做好了,测试了一下,同步一次的时间大概在30S左右。之前的本方法一条一条处理到数据库,时间大概4min左右,同步效率提高了很多。后续有待进一步提高效率,看看还有没有其他的方法。

最后提一下参考的文献资料,对我非常有帮助http://bbs.csdn.net/topics/370090507



你可能感兴趣的:(c#)