数据库数据定期同步实现
来源:互联网 发布:数据库开发暑期班 编辑:程序博客网 时间:2024/06/04 19:31
需求背景:有一个业务方需要定期跟数据库进行数据同步,就是需要定期往数据库中同步部分数据,而这些数据并不能被当前系统直接使用,需要做一些处理同步到系统所使用的数据库中,处理比较复杂,没办法进行实时的同步,所以需要写个定时任务,将处理后的数据进行同步,说白了就是数据库中两个表的数据同步。
实现这个需求,首先想到的是直接通过sql
进行同步,表之间数据同步无非是三种操作:更新,删除,插入,假设两个表 dst
,src
,dst
中有id,name,auth
三个字段,src
中有id,name,dsc
三个字段,需要将src
中的id,name
同步到dst
中去,如图所示:
在dst
和src
中都存在的数据,只需要按照src
中的数据,批量更新dst
中的数据即可,sql
语句可能是这样:
update dst, src set dst.id=src.id,dst.name=src.name where src.id=dst.id;
更新完成之后,需要向dst
表中插入在src
存在,而dst
中不存在的数据,简单的sql
可能是这样:
insert dst (id,name,auth) select src.id,src.name,'1' from src where not exists(select dst.id from dst where src.id=dst.id);
再接着是删除,将dst
中存在src
中不存在的数据称从dst
中删除,sql
如下:
delete from dst where not exists(select src.id from src where src.id=dst.id );
注意:如果是用的
mysql
上述同步删除语句中的dst
表明不能简写
有了这三条语句,写个定时任务,依次执行即可,如果是用的spring
,通常会用@Scheduled
具体使用可以google
一下,非常方便。如果需要事务可以使用@Transactional
,这些是spring
通过aop
集成好的,可以声明式使用,但是提供的粒度不够灵活,使用也会有些限制,如果想更灵活点话,可以使用编程式事务。而如果数据库开启了autocommit
功能,其本身就会有事务,不需要逻辑代码中再加事务(不是绝对的,当然要看自己需要,要记住autocommit
只保证每一条sql
是一个事务)。如果要看看自己的数据库是否开启了autocommit
,可以用下面的sql
:
show variables like 'autocommit'
这种方式的特点就是思路很简单。不需要写太多的java
代码(定时任务都可以直接用spring
封装好的注解,只需要写个类,写个函数,如果使用orm的话,然后实现mybatis
或hibernate
相关的dao
和service
)。而这种实现的问题也很明显,就是你对整个同步过程可控的东西很有限,最多通过事务保证如果同步失败了,整体回滚。而且当同步逻辑比较复杂的时候,比如说表中字段比较多,而且同步部分字段,同步的字段需要join
其他表才能决定需不需要同步,这些逻辑全部写在sql
中会导致sql
很臃肿,而且更容易出错,更严重的是出错了你却什么都做不了,也不知道具体哪里同步出错了。肿么办?那就一条一条的来呗。
要想对同步过程拥有足够的控制,就只能将需要同步的数据全部load
到内存,然后通过写程序进行遍历。具体过程应该是这样的:
1. 将src
中的数据全部load
到内存中,如果数据量比较大(通常都是这样,内存一次性放不下),就进行分页load
,sql
语句如下:
select * from src limit 'pageSize' offset 'offset'
其中
'pageSize'
通过程序设定,而'offset'
就是pageSize*pageNo
,比如说每页100条数据,取第一页的数据就是select * from src limit 100 offset 100*1
对取出来的数据进行循环遍历,java
程序简写如下:
private void syncData(){ Date curTime = new Date(); List<MyData> datas = myDataDao.getDatas(pageNo,pageSize);//访问的是src表 for(MyData data : datas){ if(needToUpdate(data))//src表中的数据在dst中已经存在就update,否则就insert update(data); else insert(data); } deleteDatasFromNow(curTime); //删除当前同步时间之前的数据}
那么needToUpdate
做的就是判断一下data
是否在dst
中存在,这里需要一个唯一标识来确定当前data
,通常是一个字段或几个联合确定唯一的data
。所以needToUpdate
可能如下:
private boolean needToUpdate(MyData data){ Optional<MyData> myData = myDataDao.findByName(data.getName);//这里访问的是dst表 if(myData.isPresent()){ return true; } else return false;}
update
和insert
都会改变dst
中的updateTime
,所以在删除的时候就可以通过updateTime
是否晚于curTime
来判断当前数据是否更新过或新插入的,如果不是,那就是需要删除的数据,所以deleteDatasFromNow()
如下:
private void deleteDatasFromNow(Date curTime){ List<MyData> datasNeedToDel = myDataDao.getDatasNeedToDel(curTime); for(MyData data : datasNeedToDel){ delete(data); }}
这样整个同步过程就完成了,如果想要打印同步日志或将同步过程记录下来,就可以在update(),insert(),delete()
中插入日志操作就行了,就拿update()
来说的话,可能像下面的情况:
private void update(MyData data){ try{ myDataDao.update(data); } catch(Exception e){ logger.error("数据"+data.getName()+"同步出错");//这里是打印日志,如果需要也可以保存到数据库 return; } logger.info("数据"+data.getName()+"同步成功");}
通过日志文件分析(如果将操作保存到数据库的话也可以直接查询数据库),可以清晰的知道哪些数据进行了更新,哪些数据是新插入的,哪些是删除了的,然后还可以进行统计,共更新了多少数据,多少成功了,多少失败了。业务层面就可以了解更多有关数据同步的信息。而且这种操作使sql
非常简单,也不太容易出错。但是一个很明显的问题也暴露出来了,那就是效率问题,如果通过这种方式,势必要遍历每一条数据,对需要update,insert,delete
的数据需要一个一个地进行访问数据库,而且对于needToUpdate(MyData data)
中也额外访问了一次数据库,亲测这个效率真是低惊人。而且这种实现中会导致,即便什么数据都不更新,也会完全遍历一遍数据,访问同样多的数据库,所需的时间还是那么久,这是在业务层面无法容忍的。于是就有了思路三。
既然上述方法的主要问题就是访问数据库过多导致效率底下,那么就必须尽可能减少数据库的访问和遍历的次数。那就需要紧贴业务需求,针对具体的需求进行改善。我遇到的需求就是每次数据同步的过程中,大部分数据都是不变的,只有少部分新增和删除,针对这个需求进行了下面的优化:
* 不再每次将所有的src
中的数据取出来,而是将需要删除的和需要更新的,以及需要新插入的分别取出来,这样数据取来之后就可以直接进行update,insert,delete
了,不需要再进行额外的比较判断的了
* 大部分数据不变,因此进行update
的时候不再单条进行更新,直接进行分页批量更新,比如说每次更新100条或者更多,以提高更新的效率。
通过这些优化大副提高了同步的效率,其中需要注意的是当写稍微复杂点的sql
的时候一定要注意,虽然都能得到相同的查询结果,可能效率相差十万八千里,在实现这个数据同步是,就因为join
位置放的不对,导致查询需要插入的数据时灰常慢,所以好好学学sql
优化还是很有必要的,网上有很多大牛介绍,可以多看看,或者用的时候再学(我通常是这样。。。)
- 数据库数据定期同步实现
- 两个一样的oracle 数据库怎么实现数据定期同步?
- 两个一样的oracle 数据库怎么实现数据定期同步?
- SQL 实现定期备份数据库
- SQL 实现定期备份数据库
- [数据库] Navicat for MySQL事件Event实现数据每日定期操作
- 两台Mysql数据库数据同步实现
- 两台Mysql数据库数据同步实现
- 两台Mysql数据库数据同步实现
- 实现不同数据库同步更新数据
- 两台Mysql数据库数据同步实现
- 在oracle数据库中实现数据同步
- 实现两个数据库之间的数据同步
- 两台Mysql数据库数据同步实现
- mongodb实现两台数据库数据同步
- sql server数据库实现定期自动备份
- Oracle-流复制-实现数据同步-数据库同步
- 文件数据如何实现定期自动备份
- QT对象序列化详解
- 朋友从乡下带回一堆破石头以后... 还有这种操作?
- 关于中高级java工程师所需要知道的东西
- Oracle数据库审计
- python常用排序算法
- 数据库数据定期同步实现
- apache+ svn 搭建教程
- Decode error
- 416. Partition Equal Subset Sum
- 自言自语
- 古典密码
- linux下安裝NNPACK
- 线程的生命周期
- 继承