公司数据同步程序的设计思路(二)

果然 上一篇末尾我的“预言”实现了。

 

我现在不仅需要向云上拉取数据,还需要将云上的数据推送到内网数据库。

 

现在面临的相关的问题存在以下几点:

1.我希望每次修改配置无需去部署机更改配置。目前的配置框架,每增加一个服务圈都需要去部署机器上改配置文件。因为部署机器不是本部门的,所以限制挺大。每次登的时候要申请,还要开VPN,跳堡垒机。今早登上去就被顶下来了。然后听说是对接部门在跟客户演示,让我们先不要连。

2.向内网机同步数据的机制初步决定用每天全表更新,每天同步时清空表再添加,使用 ado sqlsever 的批量添加,速度很快。但有一个重要的问题是,内网数据库的结构需要同云上保持一致。云上由于业务需求可能需要随时改表,那么肯定不希望每次都再回来改一下这边的数据库结构,最好可以实现同步。

 

那么思路大概如下:

云上提供一个接口,该接口返回需要(可以)同步的表 Key 值。由部署机器上的同步程序调用,调用后获得一组可同步的表 Key。然后循环表 Key 请求云上的接口,每次获取一个表的真实表名和数据。

部署程序获取到一个表之后,

判断内网数据库是否存在该表,不存在的话则根据 table 生成建表语句并执行,若表存在,

则对比表的列与 datatable的列 是否一样,不同的话则生成修改语句并执行。

在确定结构相同后,则进行批量的导入。然后进行下个表。

 

总的来说,不存在什么难点,但我没实现过根据 datatable 去对比数据库的结构生成修改语句,趁着这个机会写一下,也算积累自己的代码了。

放些关键代码:

 1             using (var db = DBFactory.GetDB())
 2             {
 3                 var sb = new System.Text.StringBuilder();
 4 
 5                 Print.Info($"判断表是否存在: {table.TableName}");
 6                 var sql = $"SELECT COUNT(*) From sysobjects WHERE name = '{Program.TableName + key}'  AND xtype = 'u'";
 7                 var tableCount = db.ExecuteScalar<int>(sql);
 8                 if (tableCount < 1)
 9                 {
10                     Print.Info($"{table.TableName} 表不存在,生成建表语句");
11 
12                     // 新建表
13                     sb.Append($"create table {Program.TableName + key}(");
14                     for (int i = 0; i < table.Columns.Count; i++)
15                     {
16                         var colItem = table.Columns[i];
17                         sb.Append($"{colItem.ColumnName} {GetType(colItem)}");
18                         if (i + 1 != table.Columns.Count)
19                         { sb.Append(","); }
20                     }
21                     sb.Append($")");
22                     sql = sb.ToString();
23 
24                     Print.Info($" {table.TableName} 建表语句 : {sql}");
25                     Print.LogInfo("执行结果:" + db.Execute(sql).ToString());
26                 }
27                 else
28                 {
29                     sb.Clear();
30                     Print.Info($"表存在: {table.TableName}");
31                     Print.Info($"判断表列是否对应: {table.TableName}");
32                     foreach (DataColumn item in table.Columns)
33                     {
34                         //判断列是否存在
35                         sql = $"SELECT COUNT(*) FROM syscolumns WHERE id = object_id('{Program.TableName + key}') AND name = '{ item.ColumnName }'";
36                         var colCount = db.ExecuteScalar<int>(sql);
37                         if (colCount < 1)
38                         {
39                             sb.Append($"alter table {Program.TableName + key} add {item.ColumnName} {GetType(item)};");
40                         }
41                     }
42                     if (sb.Length > 0)
43                     {
44                         sql = sb.ToString();
45                         Print.Info($"执行建列语句: {sql.ToString()}");
46                         Print.LogInfo($"执行建列语句结果:" + db.Execute(sql).ToString());
47                     }
48                 }
49                 //删除数据
50                 Print.Info($"执行删除语句: {sql.ToString()}");
51                 db.Execute($"DELETE FROM {Program.TableName + key}");
52                 //插入数据
53                 SqlBulkCopyByDatatable(db.ConnectionString, $"{Program.TableName + key}", table);
54             }

这是同步一个表的代码,包括了生成建列和建表语句。

SQL Sever 批量同步的代码:

 1         public static bool SqlBulkCopyByDatatable(string connectionString, string TableName, DataTable dt)
 2         {
 3             bool isSuccess = false;
 4             using (SqlConnection conn = new SqlConnection(connectionString))
 5             {
 6                 using (SqlBulkCopy sqlbulkcopy = new SqlBulkCopy(connectionString))
 7                 {
 8                     try
 9                     {
10                         sqlbulkcopy.DestinationTableName = TableName;
11                         sqlbulkcopy.BulkCopyTimeout = 0;
12                         for (int i = 0; i < dt.Columns.Count; i++)
13                         {
14                             Print.Info((i + 1) + "/" + dt.Columns.Count + "  " + dt.Columns[i].ColumnName);
15                             sqlbulkcopy.ColumnMappings.Add(dt.Columns[i].ColumnName, dt.Columns[i].ColumnName);
16                         }
17                         sqlbulkcopy.WriteToServer(dt);
18                         isSuccess = true;
19                     }
20                     catch (System.Exception ex)
21                     {
22                         Print.Err(ex.Message);
23                         throw ex;
24                     }
25                 }
26             }
27             return isSuccess;
28         }

 

代码里还是有很多可以优化的地方的,但是我最近工期很紧。年底各种项目都要求最后的需求完结,还有年初新的项目。

 

posted @ 2020-01-07 16:07  Aaxuan  阅读(396)  评论(0编辑  收藏  举报