组织结构同步(数据源为webService接口,数据终点为本地数据库)

前言:看了看博客,发现自己已经很长时间没有写了,这是因为最近都在弄组织结构同步的开发,遇到了不少的问题。
众所周知,增量的前提是全量,那么全量同步是简单的,一股脑地把接口传递过来的数据,做一个转换适配到我们的数据库,然后在这期间,去做到SQL语句插入的优化,我都优化主要在减少循环、进行SQL动态拼接批处理插入以及SQL语句的语法层面的优化,能够让数据库对数据进行处理的情况,那就交给数据库,毕竟sqlServer自己的插入更新效率还是挺高的。
讲讲增量,由于接口的格式是类似:getData(日期,起始时间,结束时间),日期的格式为"yyyy-MM-dd",起始时间和结束时间的格式都为"HHmmss",咋一看没什么,其实在实现的时候会出现多种场景:全量结束切换成增量的场景(是否跨天了,是否跨整点了)等。
这时候考虑实现就会有许多的膈应。

全量同步开始前,暂停正在进行的增量任务,记录下全量开始时间,准备开始进行全量同步,全量完成后,记录下全量结束的时间。以下有几种极限情况:

1、跨日的情况
23————————24——T4————T4'——下一个调用时间点P
                  A --------全量进行中------B   				
接口是根据日期取参数。
时间A开始执行全量,时间B结束。那么这次全量同步获取的有效数据是A之前的。A-24小时的增量没有执行,22至24小时的增量需要执行,准确的应该是说上一次增量结束时间到下一次增量开始时间T4(这个T4不是凌晨两点)的这两个小时间隔的同步数据被中断了。
但是A开始全量,那么A之前的数据都有。需要根据上一次增量结束时间取推测T4
这里有两种情况,B的时间大于T4,应该特殊处理,调用接口(day1,A,24),(day2,0,T4),然后回归正常,恢复任务调度,(day2,T4,T4+2),(day2,T4+2,(T4+2)+2),到每次预判断日期的时候:如果不相等,那么就拆成两个接口来调用(day2,EndTime2,0),(day3,0,EndTime3),恢复任务调度,(day3,EndTime3,EndTime3+2),(day3,EndTime3=2,(EndTime3+2)+2);
另外,B的时间小于T4‘,调用接口(day1,A,24),(day2,0,T4‘)

2、非跨日
0—B1—B2———B2'———————————B2''—————24
     A--------全量进行中-------B
首先暂时不考虑,上一次增量同步结束时间是上一天。
假设B1,是上一次增量开始时间,B2是上一次增量结束时间。
一、B1-B2(上一次增量同步结束时间有了)
A之前的数据都有,那么下一次增量同步开始时间就是,(day,A,A+2),(day,A+2,(A+2)+2)
二、B1-B2'
本应该是B2'时间时,需要进行增量,可是A开始后,任务就暂停调度了,那么全量结束后,(day,A,A+2)
三、B1-B2''
(day,A,A+2)

可以看出来这种非跨日的就直接(day,A,A+2)就可以了。

*****情景模拟:
*****第一次全量先什么都不考虑,先让数据库有东西,但是要记录下来这个全量开始的时间T1
然后运行部署的程序,运行定时任务。
这时候有一个增量开始时间,时间为T1

lastIncSyncTime = T1 上一次增量同步时间
predictNextIncSyncTime = T1+2 计划的下一次增量同步时间
FullSyncStartTime = null 全量同步开始时间

//  突然我要使用全量了,这个时候增量正在运行
     pauseJob();
     FullSyncStartTime = now;
     fullSync();
     FullSyncEndTime = end;
//  tell admin, 'i need SyncInc'
boolean isAcrossDay(FullSyncStartTime, FullSyncEndTime);
if(isAcrossDay){
syncInc(day1,FullSyncStartTime,24);
syncInc(day2,0,predictNextIncSyncTime)

syncInc(day2,predictNextIncSyncTime,predictNextIncSyncTime+2);
...
}

syncInc(day,beginTime,endTime){
每次增量同步,都要预判断结束日期和开始日期是不是同一天。
不是同一天,就调用两次接口;是同一天就直接恢复
}

不知道你没看懂我上面在纠结什么问题。没看懂没关系,最后我和同事大佬想到了使用固定时间片轮询的策略来实现数据的生产(我把获取数据的这个过程叫做数据生产,把“将获得的增量数据有则更新、无则插入”的这个过程叫做数据消费,这里有点生产者-消费者的意思,有点消息队列MQ的思想,为的就是让这两个过程解除耦合),通过固定的时间片轮询,我就不需要关心是否跨天、跨整时的情况了,不过也有弊端,就是时间片可能会因为异常启动等原因不能够实时,会有滞后性,这是开发者需要评估的一个问题了。

固定时间片轮询,固定两个小时调用接口拿数据(这里使用Quartz框架来实现定时效果),每次拿数据都是整点(00:00、02:00、04:00等),这通过Quartz去设置,拿到了就存进一个缓存里,消费者一个小时轮询一次缓存表内有没有可以消费的数据,如果有就进行消费者自己的操作,如果没有就等待下一次的轮询。这里主要会考验你对于LocalDateTime、Date以及Quartz的熟悉程度了,这个可以很快就现学现用了。

当然也有特殊情况存在:
1、全量同步结束后,需要触发增量,那我们怎么去判断这个时间片的起始时间和开始时间呢?这个就仁者见仁智者见智,反正我是实现了的。
2、增量同步暂停,然后杀死正在运行的服务,重新启动增量服务时,那这一次的增量同步的时间片的取值又是如何处理呢?需要人工干预吗?

这算是一次记录,对自己做过的事情的记录。
记录一下使用到的技术:
SpringBoot、CXF接口调用框架、Quartz框架、Jenkins、GitLab、Maven、多线程调度、(单例、消费者生产者、建造者、工厂)设计模式思想等。

你可能感兴趣的:(Oracle,java)