zoukankan      html  css  js  c++  java
  • 公司数据同步程序的设计思路(二)

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

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

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

    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         }

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

  • 相关阅读:
    硬盘分区、格式化及文件系统的管理一
    系统监控
    系统的初始化和服务
    正文处理命令及tar命令
    Salesforce: getContentAsPDF()在lightning mode下报错
    Salesforce: 无法在trigger中取到Country或State的更新
    Salesforce: Safe Navigation Operator
    Salesforce: INVALID_QUERY_LOCATOR简析
    Salesforce: Trigger使用注意事项
    Salesforce: 设置用户默认访问Lightning Mode
  • 原文地址:https://www.cnblogs.com/Aaxuan/p/12095503.html
Copyright © 2011-2022 走看看