博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SQL Server 多表数据增量获取和发布 4
阅读量:5832 次
发布时间:2019-06-18

本文共 5150 字,大约阅读时间需要 17 分钟。

核心代码分析

最关键的在于获取捕获表信息(系统表中间_CT结尾的数据)。

根据网上资料查取,找到了获取当前捕获表时间区间范围内数据的方式。
见[SQL Server 多表数据增量获取和发布 2.3()

--10.按照时间范围查询CDC结果DECLARE @from_lsn BINARY(10),@end_lsn BINARY(10)DECLARE @start_time DATETIME = '2018-08-01'DECLARE @end_time DATETIME ='2018-08-30'SELECT @from_lsn=sys.fn_cdc_map_time_to_lsn('smallest greater than or equal',@start_time)SELECT @end_lsn=sys.fn_cdc_map_time_to_lsn(' largest less than or equal',@end_time)SELECT * FROM cdc.fn_cdc_get_all_changes_dbo_Department(@from_lsn,@end_lsn,'all')

数据既然能够通过sql语句获取到,那么逻辑判断就会变得简单,通过分析我们可以发现select * from XXX ,XXX就是上文中讲到的CDC生成的表值函数,表值函数前面相等,可变化的就是架构名_表名称(dbo_Person)

img_3d82cc144eef60515a92ed7e3c56880e.png
image.png

所以我们完全可以通过拼接sql语句得到我们需要的内容,可以默认返回给我们的数据是不友好的,我们还需要自己在做一步设置,将某些字段变成我们好理解的内容

如对下文内容不理解,可翻阅LZ之前的文章

  • sys.fn_cdc_map_lsn_to_time(__$start_lsn) AS UpdateTime
  • [__$operation] AS Operation

通过查看CDC生成的捕获表我们发现,其实他是在原来的数据表结构上新增了几个字段给我们,其他的表也相同。

img_26cad58ed602a7b2143e34bc96613086.png
image.png
img_f34a72265c6d80915e1958ed34cc4782.png
image.png

那我们在代码中对实体的设计就可以基于继承相同父类的方式,定义一个父类,拥有共同属性

public partial class ExtBase    {        ///         /// 更新时间        ///         public DateTime UpdateTime { get; set; }        ///         /// 操作方式 1 = 删除,2 = 插入,3 = 更新(旧值),4 = 更新(新值)        ///         public int Operation { get; set; }    }

其他表都是在自己原来字段的基础上继承当前父类

public class Department : ExtBase    {        public int Id { get; set; }        public string Name { get; set; }    }    public class Person : ExtBase    {        public int Id { get; set; }        public string Name { get; set; }        public int? Age { get; set; }    }

实体类结构完毕后我们开始考虑获取数据的业务逻辑,根据业务我们可以假设获取数据的方法几乎相同,不同的地方就是返回的数据实体集合不同,那我们通过何种方法来完成逻辑的有效封装,这是需要考虑的问题。

经过思考,我构想出了一种方法

1、定义一个抽象基类,在其中定义公共业务逻辑(GetDate)方法,然后定义一个抽象方法,抽象方法需要被子类继承,而子类需要做的就是覆写父类的GetData方法,唯一需要修改的就是传递的实体——可以采用泛型变量的形式去实现

2、等所有的子类构建完成以后,创建一个简单工厂,传递需要的参数,然后根据参数中的唯一标识符,实例化对应的操作类去执行公共方法。

首先是基类抽象类

///     /// Cdc 数据捕获服务类    ///     /// 
public abstract class CTBaseService{ /// /// 获取CDC捕获表的数据 /// ///
/// /// ///
private List
GetRangeList
(string schema_table, DateTime startDateTime) where T : class, new() { //获取当前需要更新的日期集合列表 var conn = new SqlConnection(StaticConst.Conn); string query = @"SELECT * ,sys.fn_cdc_map_lsn_to_time(__$start_lsn) AS UpdateTime,[__$operation] AS Operation FROM [cdc].[{2}_CT] WHERE[__$operation] IN(1, 2, 4) AND sys.fn_cdc_map_lsn_to_time(__$start_lsn) > '{0}' AND sys.fn_cdc_map_lsn_to_time(__$start_lsn) <= '{1}';"; string nowDate = DateTime.Now.ToString(); query = string.Format(query, startDateTime.ToString(), nowDate, schema_table); var queryList = conn.Query
(query).ToList(); return queryList; } ///
/// 抽象方法,由父类实现 /// ///
///
///
public abstract void Work(int id, string schema_table, DateTime startDateTime); ///
/// 得到CDC捕获数据并插入队列 /// ///
///
///
///
protected void GetRangeListAndInsertQueue
(int id, string schema_table, DateTime startDateTime) where T : ExtBase, new() { //获取当前需要更新的日期集合列表 List
queryList = GetRangeList
(schema_table, startDateTime); if (queryList.Count > 0) { //对集合进行操作 【集合序列化,注意集合反序列化】 string jsonItem = JsonConvert.SerializeObject(queryList); QueueWorker.Instance.EnqueueItem(jsonItem); int iret = UpdateServiceLog(id, queryList); string nowDate = DateTime.Now.ToString(); if (iret > 0) { Log4NetHelper.Info(string.Format("表名:{0}\r\n 队列数据:{1} \r\n 插入时间:{2}", schema_table, jsonItem, nowDate)); } } }}

子类实现

我们可以发现子类实现非常好理解,正如上文所说,基类提供了一个抽象接口供子类实现,而子类也真的只需要修改一个实体就可以。如果大家不懂,可以多看几遍来裂解其中的设计方式。

public class DepartmentCT : CTBaseService    {        public override void Work(int id, string schema_table, DateTime startDateTime)        {            base.GetRangeListAndInsertQueue
(id, schema_table, startDateTime); } }
public class PersonCT : CTBaseService    {        public override void Work(int id, string schema_table, DateTime startDateTime)        {          base.GetRangeListAndInsertQueue
(id, schema_table, startDateTime); } }

最后我们建立一个工厂类,工厂类主要负责接受参数并创建对应的CT帮助类,代码结构如下。根据表名作为唯一标识符字段,创建***CT服务类,然后因为他们继承并覆写了父类抽象方法Work,所以调用.Work方法即可实现获取数据并插入队列的功能。

public class CTCExecuteFactory    {        ///         /// 执行服务        ///         ///         ///         ///         public static void ExecuteService(int id, string schemaName, string tableName, DateTime updateTime)        {            CTBaseService service = null;            switch (tableName.ToLower())            {                case ServiceTables.person: service = new PersonCT(); break;                case ServiceTables.department: service = new DepartmentCT(); break;                default: break;            }            if (service != null) service.Work(id, string.Format("{0}_{1}", schemaName, tableName), updateTime);        }    }

其他模块的代码我觉得属于正常理解范围内的东西,不予说明,有兴趣的可自行下载代码查看具体功能。

转载地址:http://ptrdx.baihongyu.com/

你可能感兴趣的文章
新开的博客,为自己祝贺一下
查看>>
【CQOI2011】放棋子
查看>>
采用JXL包进行EXCEL数据写入操作
查看>>
将txt文件转化为json进行操作
查看>>
线性表4 - 数据结构和算法09
查看>>
我的2014-相对奢侈的生活
查看>>
Java设计模式
查看>>
Spring Cloud 微服务分布式链路跟踪 Sleuth 与 Zipkin
查看>>
ORM数据库框架 SQLite 常用数据库框架比较 MD
查看>>
华为OJ 名字美丽度
查看>>
微信公众号与APP微信第三方登录账号打通
查看>>
onchange()事件的应用
查看>>
Windows 下最佳的 C++ 开发的 IDE 是什么?
查看>>
软件工程师成长为架构师必备的十项技能
查看>>
python 异常
查看>>
百度账号注销
查看>>
mysql-This version of MySQL doesn’t yet support ‘LIMIT & IN/ALL/ANY/SOME 错误解决
查看>>
BIEE Demo(RPD创建 + 分析 +仪表盘 )
查看>>
Cocos2dx 3.0开发环境的搭建--Eclipse建立在Android工程
查看>>
基本概念复习
查看>>