首页 > 数据库 >C# 后台服务监控SQL Server数据库表改动并同步到MySQL数据库表

C# 后台服务监控SQL Server数据库表改动并同步到MySQL数据库表

时间:2023-04-03 15:05:00浏览次数:63  
标签:string C# 数据库 System item ex MySQL using itemMstAllSyncDependency


需求

  1. 将A服务器的sql server数据库item_mst表的数据同步到MySQL数据库Part表
  2. 监控Item_mst表中item,description,overview 的更改并同步到MySQL数据库

 

针对需求一,基本就是执行一次,单独写了个winform用来做这事

针对需求二,写了个Windows service app

 

Nuget安装

 

C# 后台服务监控SQL Server数据库表改动并同步到MySQL数据库表_MySQL

Dapper就是个orm

Serilog用来记log

SQLTableDependency用来检测表的改动,文档地址:https://github.com/christiandelbianco/monitor-table-change-with-sqltabledependency

使用这个别忘了执行 alter database [<dbname>] set enable_broker with rollback immediate;

  1. 创建service
  2. 添加安装程序
  3. 如何安装service

Create a Windows service app

https://docs.microsoft.com/en-us/dotnet/framework/windows-services/walkthrough-creating-a-windows-service-application-in-the-component-designer

 

How to: Add Installers to Your Service Application

https://docs.microsoft.com/zh-cn/dotnet/framework/windows-services/how-to-add-installers-to-your-service-application

How to: Install and uninstall Windows services

https://docs.microsoft.com/en-us/dotnet/framework/windows-services/how-to-install-and-uninstall-services

源码

目录结构

C# 后台服务监控SQL Server数据库表改动并同步到MySQL数据库表_mysql_02

Models文件夹里的ItemMst.cs文件

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SyncItemMstAllService.Models
{
    /// <summary>
    /// table name: item_mst
    /// note: We do not need to specify all table columns but just the ones we are interested:
    /// </summary>
    public class ItemMst
    {
        // internalNumber
        public string Item { get; set; }
        // name
        public string Description { get; set; }
        // description
        public string Overview { get; set; }
    }
}

App.config

<appSettings>
    <add key="logFilesPath" value="C:\QMSCSyncData\logs\"/>
    <add key="webApiBaseAddress" value="http://localhost:5000/"/>
  </appSettings>
  <connectionStrings>
    <add name="JMP_APP_SqlServerConnStr" connectionString="data source=192.168.1.202\test;initial catalog=JMP_APP;User Id=sa;Password=pwd;"/>
    <add name="QMS_MySqlServerConnStr" connectionString="server=localhost;Port=3306;Database=qms_test;UID=root;PWD=pwd;Allow User Variables=True" />  </connectionStrings>
Allow User Variables=True"这个东西我不知道干啥的,但我知道没他就会出现错误- -
不加会出现这样的情况

QMSSyncTiemMstService.cs

using System;
using System.Configuration;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.ServiceProcess;
using System.Threading.Tasks;
using Dapper;
using SyncItemMstAllService.Models;
using MySql.Data.MySqlClient;
using Serilog;
using TableDependency.SqlClient;
using TableDependency.SqlClient.Base.Enums;
using TableDependency.SqlClient.Base.EventArgs;
using System.Collections.Generic;

namespace QMSCSyncService
{
    public partial class QMSSyncItemMstService : ServiceBase
    {
        private SqlTableDependency<ItemMst> _itemMstAllSyncDependency;
        private readonly string _jmp_app_ConnectionString;
        private readonly string _qms_mysql_ConnectionString;
        private readonly string _logFilesPath;
        private readonly string version = "1.0.20190730";

        public QMSSyncItemMstService()
        {
            InitializeComponent();
            _logFilesPath = ConfigurationManager.AppSettings["logFilesPath"];
            _jmp_app_ConnectionString = ConfigurationManager.ConnectionStrings["JMP_APP_SqlServerConnStr"].ConnectionString;
            _qms_mysql_ConnectionString = ConfigurationManager.ConnectionStrings["QMS_MySqlServerConnStr"].ConnectionString;

            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Debug()
                .WriteTo.File($"{_logFilesPath}serviceLog.txt", rollingInterval: RollingInterval.Day)
                .CreateLogger();
        }

        protected override void OnStart(string[] args)
        {
            initItemMstAllSyncDependency();
            Log.Information($"QMSSyncService Started.Version{version}");
        }

        protected override void OnStop()
        {
            Log.Information("QMSSyncService Stopped.");
            try
            {

                if (_itemMstAllSyncDependency != null)
                {
                    _itemMstAllSyncDependency.Stop();
                    _itemMstAllSyncDependency.Dispose();
                }
            }
            catch (Exception ex)
            {
                Log.Error($"Error occur when stopping service, {ex.Message} {ex.Source}");
            }
        }

        private void initItemMstAllSyncDependency()
        {
            Log.Information($"run initItemMstAllSyncDependency");
            try
            {
                if (_itemMstAllSyncDependency != null)
                {
                    _itemMstAllSyncDependency.Stop();
                    _itemMstAllSyncDependency.Dispose();
                }
                _itemMstAllSyncDependency = new SqlTableDependency<ItemMst>(_jmp_app_ConnectionString, "item_mst");
                _itemMstAllSyncDependency.OnChanged += ItemMstAllSyncDependency_OnChanged;
                _itemMstAllSyncDependency.OnError += ItemMstAllSyncDependency_OnError;
                _itemMstAllSyncDependency.Start();
            }
            catch (Exception ex)
            {
                Log.Error($"Init SqlTableDependency for ItemMstSyncs failed. {ex.Message} {ex.Source}");
                if (_itemMstAllSyncDependency != null)
                {
                    _itemMstAllSyncDependency.Stop();
                    _itemMstAllSyncDependency.Dispose();
                }
            } 
        private void ItemMstAllSyncDependency_OnChanged(object sender, RecordChangedEventArgs<ItemMst> e)
        {
            if (e.ChangeType != ChangeType.None)
            {
                switch (e.ChangeType)
                {
                    case ChangeType.Insert:
                    case ChangeType.Update:
                        saveItemMst(e.Entity.Item, e.Entity.Description, e.Entity.Overview);
                        break;
                }
            }
        }

        private void saveItemMst(string item, string name, string description)
        {
            string UUID = Guid.NewGuid().ToString("D");
            DateTime dt = DateTime.Now;
            bool hasExisted = isExisted(item);
            if (name == null)
            {
                name = item;
            }
            string insertSql = $@"INSERT INTO `part` (
	                        `ParentPartId`,
	                        `PublisherId`,
	                        `UUID`,
	                        `Type`,
	                        `InternalNumber`,
	                        `SupplierNumber`,
	                        `Name`,
                            `Description`,
	                        `Rev`,
	                        `RevType`,
	                        `Level`,
	                        `Category`,
	                        `Status`,
	                        `CreatedAt`,
	                        `CreatedBy`,
	                        `IsDeleted` 
                        )
                        VALUES
	                        (
		                        0,
		                        149,
		                        @UUID,
		                        1,
		                        @item,
		                        NULL,
		                        @name,
		                        @description,
		                        'A',
		                        1,
		                        1,
		                        '',
		                        1,
		                        '{dt}',
		                        701,
		                        0
	                        );";
            string updateSql = $@"UPDATE `part` 
                                            SET
                                            `Name` = @name,
                                            `Description` = @description,
                                            `UpdatedAt` = '{dt}',
                                            `UpdatedBy` = '701'
                                            WHERE InternalNumber = @item";
            try
            {
                using (MySqlConnection qmsDBConnection = new MySqlConnection(_qms_mysql_ConnectionString))
                {
                    qmsDBConnection.Open();
                    using (MySqlCommand cmd = qmsDBConnection.CreateCommand())
                    {
                        try
                        {
                            cmd.CommandText = hasExisted ? updateSql : insertSql;
                            cmd.Parameters.Add(new MySqlParameter("@UUID", UUID));
                            cmd.Parameters.Add(new MySqlParameter("@name", name));
                            cmd.Parameters.Add(new MySqlParameter("@description", description));
                            cmd.Parameters.Add(new MySqlParameter("@item", item));
                            cmd.ExecuteNonQuery();
                        }
                        catch (Exception ex)
                        {
                            Log.Error($"Sync from saveItemMst have error occur, {ex.Message} {ex.Source} { ex.StackTrace }");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Log.Error($"Sync from saveItemMst have error occur, {ex.Message} {ex.Source} { ex.StackTrace }");
            }
        }
        private bool isExisted(string item)
        {
            string sSql = @"SELECT * FROM Part P WHERE P.PublisherId=149 AND P.InternalNumber = @item AND P.IsDeleted=0";
            try
            {
                using (MySqlConnection qmsDBConnection = new MySqlConnection(_qms_mysql_ConnectionString))
                {
                    qmsDBConnection.Open();
                    using (MySqlCommand cmd = new MySqlCommand(sSql, qmsDBConnection))
                    {
                        try
                        {
                            cmd.Parameters.Add(new MySqlParameter("@item", item));
                            object result = cmd.ExecuteScalar();
                            if (result != null)
                            {
                                return true;
                            }
                            return false;
                        }
                        catch (Exception ex)
                        {
                            Log.Error($"IsExisted have error occur, {ex.Message} {ex.Source} { ex.StackTrace }");
                            return false;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Log.Error($"IsExisted have error occur, {ex.Message} {ex.Source} { ex.StackTrace }");
                return false;
            }
        }
        } 
        private void ItemMstAllSyncDependency_OnError(object sender, TableDependency.SqlClient.Base.EventArgs.ErrorEventArgs e)
        {
            string innerException = e.Error.InnerException != null ? e.Error.InnerException.Message + e.Error.InnerException.Source : "";
            Log.Error($"ItemMstAllSyncDependency have error occur, {e.Error.Message} {e.Error.Source} { innerException }");
            try
            {
                this.OnStop();
                this.OnStart(null);
            }
            catch (Exception ex)
            {
                Log.Debug("Restart failed " + ex.Message + ex.Source);
            }
        }
    }
}

 

 

 

标签:string,C#,数据库,System,item,ex,MySQL,using,itemMstAllSyncDependency
From: https://blog.51cto.com/u_15976398/6166425

相关文章

  • 零基础Go语言从入门到精通(数据库编程:02-Gorm 操作 MySQL 数据库)
    gin-gorm-api-example/main.goatmaster·cgrant/gin-gorm-api-example·GitHubhttps://github.com/cgrant/gin-gorm-api-example/blob/master/main.goGorm介绍ThefantasticORMlibraryforGolangGo语言的超棒的ORM类库功能强大:全功能ORM(几乎)关联(包含一个,包含多个,属......
  • FastThreadLocal源码解析
    Netty为什么要用自己的FastThreadLocal?threadLocalHash冲突,检索时间长。Netty自己定义的fastThreadLocal用的是数组,直接数组下标检索快。下面以ftl作为FastThreadLocal的简称例子ftl只有在FastThreadLocalThread线程中运行才生效,不然会走SlowGet模式(jdkthreadLocal方式)publiccl......
  • RocketMQ NameServer启动流程解析
    具体分析可参考Gitee项目NameServer解析部分=》代码地址什么是NameServer简易Topic路由注册中心,用于支持Broker的服务注册与发现。类似Dubbo的zookeeper主要能力Broker集群管理:管理Broker集群注册信息,心跳检测broker存活路由信息管理:保存Broker集群路由信息,然后producer、consumer......
  • Eclipse中安装Velocity插件
    工具特性:   1)用户自定义模版   2)根据velocity的vtl和html的标签进行自动缩进   3)语法高亮显示   4)html标签和velocity语句的自动完成提示和内容帮助,   5)html预览   6)使用ctrl+alt+鼠标点击html的结束标签(如)或velocity......
  • 22-springboot应用监控-actuator
    可以做成页面监控(springboot-admin),而不是json的格式,看起来会更方便。在生产环境中,有时可能需要监控服务的可用性,spring-boot的actuator就是提供了对应用的配置查看、健康检查、相关功能统计等,可以通过HTTP,JMX来访问这些监控功能;(端点)如何使用该功能呢?1、在项目的Maven中添......
  • Chief Architect Premier X15(建筑和室内设计软件)
    ChiefArchitectPremierX15是一款高级的建筑设计软件,它可以帮助建筑师和设计师创建复杂的建筑和室内设计。该软件具有强大的三维渲染功能,可以帮助用户预览和编辑设计,以及快速创建高质量的建筑图纸和施工图。ChiefArchitectPremierX15还具有大量的库和工具,可以帮助用户快......
  • mysql总结
    MyiSAM和innodbMyiSAM:非聚集索引、B+树、叶子结点保存data地址;innodb:聚集索引、B+树、聚集索引中叶子结点保存完整data,innodb非聚集索引需要两遍索引,innoDB要求表必须有主键;innodb为什么要用自增id作为主键:自增主键:顺序添加,页写满开辟新的页;非自增主键(学号等):主键值随机,有碎片......
  • Wallys|Wi-Fi 7 SoC chip • Alder / BellsIPQ9574 / IPQ9554 / IPQ9514|IPQ9570 / IP
      Wi-Fi7explainedWiFi7istheupcomingWiFistandard,alsoknownasIEEE802.11beExtremelyHighThroughput(EHT).Itworksacrossallthreebands(2.4GHz,5GHz,and6GHz)tofullyutilizespectrumresources.WhileWiFi6wasbuiltinresponseto......
  • TypeScript 学习笔记 — 基于对象操作的内置类型的使用(十二)
    目录1.Partial转化可选属性(?)2.Required转化必填属性(-?)3.Readonly转化仅读属性(readonly)Mutate(非内置,与Readonly相对)(-readonly)4.Pick挑选所需的属性5.Omit忽略属性在前几章的笔记中,了解了以下几种内置类型:条件类型相关:Exclude排除类型(差集),Extract抽取......
  • 看我如何用定值 Cookie 实现反爬
    摘要:本次案例,用定值Cookie实现反爬。本文分享自华为云社区《我是怎么用一个特殊Cookie,限制住别人的爬虫的》,作者:梦想橡皮擦。Cookie生成由于本案例需要用到一个特定的Cookie,所以我们需要提前将其生成,你可以直接设置一个固定的字符串,也可以使用Python加密模块来加密一段......