并发事务对数据同步的影响
创始人
2024-06-03 11:23:23
0

事故背景:

1.由于历史原因和业务需要,我们需要把A库的test表数据,同步到B库的test表中

2.因为A库是sqlserver,旧同步使用的timestamp版本字段,进行的新增、更新检测;后期我们都会迁移到mysql中,所以这部分改用updateTime字段进行新增、更新检测

3.又因为,updateTime字段的更新并没有被所有业务覆盖,即有的业务更新test表,但没有更新updateTime;且手动更新表的情况也不会总更新updateTime;且sqlserver并没有mysql的DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 的功能

4.使用sqlserver的触发器功能为updateTime赋值,触发器代码如下

<-- 触发器 -->
CREATE TRIGGER [dbo].[tgr_test_updtim]
ON [dbo].[test]
WITH EXECUTE AS CALLER
FOR UPDATE
AS
BEGINSET NOCOUNT ON;UPDATE dbo.[test]SET updateTime=SYSDATETIME()WHERE id IN (SELECT DISTINCT id FROM inserted)
END

事故描述:

1.updateTime = '2023-03-02 15:11:59.995' 的数据记录没有同步过去,我们称为记录a

2.updateTime = '2023-03-02 15:12:00.006' 的数据记录同步过去了,我们称为记录b

3.且记录已经同步过去的数据的最大updateTime为 '2023-03-02 15:38:59.725',这意味着a记录在同步过程中丢失了

4.同步的过程为,我们根据当前同步的最大updateTime,去A库的拍品表中查询大于等于的数据,同步到B库,并记录这部分数据中最大的updateTime,更新当前同步的最大updateTime

原因猜测:

1.A库主从延迟,导致同步查询从库时,没有查询到记录a;

          -- 但是记录b同步过来了,主从同步是根据binlog过来的,是严格的顺序执行,且在a记录之后的b记录已经同步过来了。==》否定

2.记录a的updateTime字段生成后并没有立即持久化到A库中,且在这个过程中记录b生成了updateTime且持久化了;这时候同步代码查询,并使用记录b的(或更大的)updateTime作为当前同步的最大updateTime;而在同步代码查询之后,记录a持久化成功了,导致记录a被同步代码遗漏

          -- 听起来合理,但是还要想办法验证;且如果该原因成立,旧代码中根据timestamp字段进行同步的代码也有一样的问题

验证思路:

1.当前表中有触发器、CDC;所以涉及到三个时间:触发器生成的updateTime,实际落库提交时间、CDC记录的时间

       1.1 触发器生成的updateTime:SET updateTime=SYSDATETIME()在编译期就会调用,即commit之前

        1.2 实际落库时间

        1.3 CDC记录时间

手动开启两个事务,并进行更新如下:

-- mysql的默认全局事务隔离级别是可重复度 - Repeatable read查询方式1(8以下):SELECT @@GLOBAL.tx_isolation, @@tx_isolation;    查询方式2(8以上):SELECT @@GLOBAL.transaction_isolation, @@transaction_isolation;
-- sqlserver的连接默认是读已提交-Read committed-- 事务一  id = 123的sp=3.55,updateTime='2023-03-14 15:30:35.256'
BEGIN TRANSACTION
SELECT id,sp FROM test WHERE id = 123;
UPDATE test SET sp = 3.56 WHERE id = 123;
SELECT id,sp FROM test WHERE id = 123;
COMMIT;-- 事务二  id = 234的sp=3.95,updateTime = '2023-01-05 19:03:33.266'
BEGIN TRANSACTION
SELECT id,sp FROM test WHERE id = 234
UPDATE test SET sp = 3.55 WHERE id = 234;
SELECT id,sp FROM test WHERE id = 234;
COMMIT;

执行顺序为:

1.开启事务一

2.事务一更新前查询

3.事务一更新 id为123的记录

4.事务一查询(隔离级别是读已提交,但事务内可读,是更新后的值)

5.事务二开启、更新前查询

6.更新(id为234的记录)、查询

7.事务二提交

6.事务一提交

查询CDC,id=123的记录如下

 select createTime,UpdateTime, sp,
 sys.fn_cdc_map_lsn_to_time(__$start_lsn) cdc_createTime,
 __$operation from cdc.test_CT where id = 123

 查询CDC,id=234的记录如下

 select createTime,UpdateTime, sp,
 sys.fn_cdc_map_lsn_to_time(__$start_lsn) cdc_createTime,
 __$operation from cdc.test_CT where id = 234

 我们的第二个猜想得到了验证!!!

我们来具体分析:

1.CDC表子段查询含义

         UpdateTime、sp 是 test表中字段的值

         cdc_createTime 是test_CT表中记录生成时间

        __$operation 是test_CT表中记录类型,1-删除,2新增,3更新前,4更新后

2.触发器在更新操作时触发,且和更新操作属于同一个事务

再次看执行顺序和对应结果

执行顺序为:

1.开启事务一

2.事务一更新前查询  ==》   

       (old) id = 123的sp=3.56,updateTime = '2023-03-14 15:30:35.256' 

3.事务一更新 id为123的记录  ==》

        3.1 id=123,sp=3.56,updateTime = '2023-03-14 15:30:35.256' (未提交/未持久化) ==》

        3.2 sp更新触发记录CDC记录(但是没有持久化)==》

                更新前:id=123,sp=3.55,updateTime = '2023-03-14 15:30:35.256'

                更新后:id=123,sp=3.56,updateTime = '2023-03-14 15:30:35.256'

        3.3 触发器触发,更新updateTime字段(和3.2的执行顺序没有先后)==》

                id=123,sp=3.56,updateTime = '2023-03-14 16:24:02.010'(未提交/未持久化)

        3.4 触发器更新updateTime字段触发CDC记录(没有持久化)

                更新前:id=123,sp=3.56,updateTime = '2023-03-14 15:30:35.256'

                更新后:id=123,sp=3.56,updateTime = '2023-03-14 16:24:02.010'

4.事务一查询(隔离级别是读已提交,但事务内可读,是更新后的值)

      (new)id=123,sp=3.56,updateTime = '2023-03-14 16:24:02.010'(未提交/未持久化)

5.事务二开启、更新前查询

        (old) id = 234的sp=3.95,updateTime = '2023-01-05 19:03:33.266' 

6.更新(id为234的记录)、查询

        6.1 id=234,sp=3.55,updateTime = '2023-01-05 19:03:33.266' (未提交/未持久化) ==》

        6.2 sp更新触发记录CDC记录(但是没有持久化)==》

                更新前:id=234,sp=3.95,updateTime = '2023-01-05 19:03:33.266'

                更新后:id=234,sp=3.55,updateTime = '2023-01-05 19:03:33.266'

        6.3 触发器触发,更新updateTime字段(和3.2的执行顺序没有先后)==》

                id=234,sp=3.55,updateTime = '2023-03-14 16:24:02.010'(未提交/未持久化)

        6.4 触发器更新updateTime字段触发CDC记录(没有持久化)

                更新前:id=234,sp=3.55,updateTime = '2023-01-05 19:03:33.266'

                更新后:id=234,sp=3.55,updateTime = '2023-03-14 16:24:41.893'

7.事务二提交 (提交时间:2023-03-14 16:24:32.758)

        CDC记录的创建时间为实际提交时间

6.事务一提交(提交时间:2023-03-14 16:25:01.346)

        CDC记录的创建时间为实际提交时间

时间顺序行为如下:

1.id=123的记录,《2023-03-14 16:24:02.010》更新sp, 3.55->3.56;

触发器触发更新updateTime,生成updateTime为《2023-03-14 16:24:02.010》

2.id=234的记录,《2023-03-14 16:24:41.893》更新sp, 3.55->3.56;

触发器触发更新updateTime,生成updateTime为《2023-03-14 16:24:41.893》

3.《2023-03-14 16:24:45.758》提交id=234的事务 ==>CDC这个时间生成四条记录,分别是是id = 234更新sp前、后的记录+更新updateTime字段前、后的记录

4.《2023-03-14 16:25:01.346》提交id=123的事务 ==>CDC这个时间生成四条记录,分别是id = 123的更新sp前、后的记录+更新updateTime字段前、后的记录

总结:

1.触发器和更新操作时同一个事务中执行的,触发器中SYSDATETIME()方法在编译执行时就获得了时间结果

2.先触发更新的提交时间可能晚于后触发更新的提交

3.CDC记录的sys.fn_cdc_map_lsn_to_time(__$start_lsn) cdc_createTime 是提交时的时间

问题分析、确认完成,解决方案就不再话下

同样的,sqlserver的timestamp作为同步数据条件也会有一样的问题

解决方案:同步时间查询时往前推30秒 + 手动补偿(快速解决问题)

不足:预警确实,问题感知被动

相关内容

热门资讯

虞书欣谈成名的代价令人心疼,如... 虞书欣谈成名的代价令人心疼,如今她在圈内的前景如何?虞书欣在圈内前景是很不错的,大家都很喜欢她,也有...
最有效的减肥食谱 最有效的减肥食谱谁有最有效的减肥食谱呢?麻烦给一个吧?急求最有效的减肥食谱,听说有一个什么汤的可以很...
关晓彤鹿晗被曝月底会分手,你对... 关晓彤鹿晗被曝月底会分手,你对于他们两个的爱情有什么看法?当初我也觉得他们俩的感情肯定不会长久的,但...
她曾在家中喂猪,却被张艺谋相中... 她曾在家中喂猪,却被张艺谋相中一夜成名,魏敏芝如今过得怎样?魏敏芝过得非常不错啊,而且当地的头衔也是...
电影《中邪》主要讲了什么? 电影《中邪》主要讲了什么?中邪的剧情简介 · · · · · ·大学生丁鑫和刘梦为拍摄农村风俗纪录片...
可以在营业厅查到短信的内容吗? 可以在营业厅查到短信的内容吗?查自己的短信==如果你是本人应该可以…不是本人是不可以的那是别人的隐私...
春日时雨时晴,杏花开时,小雨落... 春日时雨时晴,杏花开时,小雨落在身上,衣服欲湿未湿;杨柳风最柔,吹到脸上也下觉其寒。是什么诗句沾衣欲...
低学历的女人真的不能娶吗? 低学历的女人真的不能娶吗?我觉得不是的,娶妻子还是主要看对方的品性如何,而不是在意对方的学历。不一定...
电影配音问题 懂的进来 不是很... 电影配音问题 懂的进来 不是很难我想知道一个问题 比如说 一个电影 演员是 X 那他的说...可以是...
关于大蒜的谜语有哪些 关于大蒜的谜语有哪些有关蒜的谜语有:两二小,头长草 (打字一)谜底:蒜弟兄七八个,围着柱子坐,只要一...
怎么夸老师漂亮 怎么夸老师漂亮老师您长得太有气质了,非常出众,我身为一个女孩子都快要把持不住了。就直接一点说:老师你...
一般怎么钢琴即兴伴奏,一拿到简... 一般怎么钢琴即兴伴奏,一拿到简谱就能伴奏的和弦 天空之城简易般的可一参考 摸摸就出来的 弹一个音 ...
我对异地女友说,异地太苦了我真... 我对异地女友说,异地太苦了我真心问你,你和我一起内心快乐吗?她说,不管日子再苦,有你就是甜的?你一个...
为什么叫镇江 为什么叫镇江为什么叫镇江意义为"Garrison of the Yangtze River"
在足球历史上,阿贾克斯都获得过... 在足球历史上,阿贾克斯都获得过多少次欧冠?一共应该是获得过4次冠军,而且他真的是特别厉害,很少有人可...
时间简史是谁写的? 时间简史是谁写的?史蒂芬·威廉·霍金
我爱她,但她爱他。 我爱她,但她爱他。如果换了我是你!我会一直的爱着她!她爱着他,你又爱着他!她知道爱一个不爱自己人的资...
歌词:我是你的月亮,是你夜里的... 歌词:我是你的月亮,是你夜里的光芒。叫月光曲,嘿嘿
枪神纪里面的英文歌曲叫什么? 枪神纪里面的英文歌曲叫什么?枪神纪里面的英文歌曲叫什么?一首是男的一首是女的,女的那首好像有一句是,...
中外小朋友 大家手拉手 来自五... 中外小朋友 大家手拉手 来自五大洲 是什么歌名?中外小朋友 大家手拉手 来自五大洲 是什么歌名?《庆...