数据接口同步
| 1、业务场景:一般系统,多数会与第三方系统的数据打交道,而第三方的生产库,并不允许我们直接操作。在企业里面,一般都是通过中间表进行同步,即第三方系统将生产数据放入一张与其生产环境隔离的另一个独立的库中的独立的表,再根据接口协议,增加相应的字段。而我方需要读取该中间表中的数据,并对数据进行同步操作。此时就需要编写相应的程序进行数据同步。 |
| 2、数据同步一般分两种情况: |
| 全量同步:每天定时将当天的生产数据全部同步过来(优点:实现简单 缺点:数据同步不及时) |
| 增量同步:每新增一条,便将该数据同步过来(优点:数据近实时同步 缺点:实现相对困难) |
| 3、我方需要做的事情:读取中间表的数据,并同步到业务系统中(可能需要调用我方相应的业务逻辑) |
| 4、模型抽离 |
| 生产者消费者模型 |
| 生产者:读取中间表的数据 |
| 消费者:消费生产者生产的数据 |
| 5、接口协议的制定 |
| 1.取我方业务所需要的字段 |
| 2.需要有字段记录数据什么时候进入中间表 |
| 3.增加相应的数据标志位,用于标志数据的同步状态 |
| 4.记录数据的同步时间 |
| 6、技术选型:mybatis、单一生产者多消费者、多线程并发操作 |
| |
中间表设计
| DROP TABLE IF EXISTS `student`; |
| CREATE TABLE `student` ( |
| `id` int(11) NOT NULL, |
| `name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, |
| `sex` varchar(4) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, |
| `birth` datetime(0) NULL DEFAULT NULL, |
| `department` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, |
| `add_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0), |
| `data_status` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '10I' COMMENT '10I 第三方系统把数据入库 10D 处理中 10F 处理完成 10E处理失败', |
| `deal_time` datetime(0) NULL DEFAULT NULL COMMENT '处理时间', |
| PRIMARY KEY (`id`) USING BTREE |
| ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; |
| |
| SET FOREIGN_KEY_CHECKS = 1; |
| CREATE TABLE `student` ( |
| `id` int(11) NOT NULL, |
| `name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, |
| `sex` varchar(4) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, |
| `birth` datetime(0) NULL DEFAULT NULL, |
| `department` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, |
| `address` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, |
| PRIMARY KEY (`id`) USING BTREE |
| ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; |
| |
| SET FOREIGN_KEY_CHECKS = 1; |
基础环境搭建
| <dependencies> |
| |
| <dependency> |
| <groupId>mysql</groupId> |
| <artifactId>mysql-connector-java</artifactId> |
| <version>6.0.6</version> |
| </dependency> |
| |
| <dependency> |
| <groupId>org.mybatis</groupId> |
| <artifactId>mybatis</artifactId> |
| <version>3.4.6</version> |
| </dependency> |
| |
| <dependency> |
| <groupId>org.slf4j</groupId> |
| <artifactId>slf4j-log4j12</artifactId> |
| <version>1.7.25</version> |
| </dependency> |
| |
| <dependency> |
| <groupId>com.zaxxer</groupId> |
| <artifactId>HikariCP</artifactId> |
| <version>3.2.0</version> |
| </dependency> |
| |
| <dependency> |
| <groupId>junit</groupId> |
| <artifactId>junit</artifactId> |
| <version>4.12</version> |
| <scope>test</scope> |
| </dependency> |
| </dependencies> |
生产者代码实现
| 1、分批读取中间表(10I),并将读取到的数据状态修改为10D(处理中) |
| 2、将相应的数据交付给消费者进行消费 |
| 方式1:把生产完的数据,直接放到队列里,由消费者去进行消费 |
| 方式2:把消费者放到队列里面,生产完数据,直接从队列里拿出消费者进行消费 |
| 3、第2步使用方式2,将(第三方系统)中间表同步到(业务端)学生表 |
| |
| # 生产者 |
| public class Producer implements Runnable { |
| |
| private static final Logger LOGGER = LoggerFactory.getLogger(Producer.class); |
| |
| |
| private QryBusi qryBusi; |
| |
| |
| private LinkedBlockingQueue<Runnable> consumers; |
| |
| |
| private ThreadPoolExecutor executor; |
| |
| |
| public Producer(QryBusi qryBusi,LinkedBlockingQueue<Runnable> consumers,ThreadPoolExecutor executor) { |
| this.qryBusi = qryBusi; |
| this.consumers = consumers; |
| this.executor = executor; |
| } |
| |
| @Override |
| public void run() { |
| while (true) { |
| |
| List list = qryBusi.queryList(10); |
| try { |
| if (list != null && list.size() > 0) { |
| |
| qryBusi.modifyListStatus(list,DataStutusConst.DEALING); |
| Consumer consumer = (Consumer) consumers.take(); |
| consumer.setData(list); |
| executor.execute(consumer); |
| } else { |
| try { |
| Thread.sleep(5000L); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| } |
| } catch (Exception e) { |
| LOGGER.error("生产者发生异常=======》",e); |
| qryBusi.modifyListStatus(list, DataStutusConst.ERROR); |
| } |
| } |
| } |
| |
| } |
| |
| # 消费者 |
| public class Consumer implements Runnable { |
| |
| |
| private List data; |
| |
| |
| private DealBusi dealBusi; |
| |
| |
| private LinkedBlockingQueue<Runnable> consumers; |
| |
| |
| public void setData(List data) { |
| this.data = data; |
| } |
| |
| |
| public Consumer(DealBusi dealBusi, LinkedBlockingQueue<Runnable> consumers) { |
| this.dealBusi = dealBusi; |
| this.consumers = consumers; |
| } |
| |
| @Override |
| public void run() { |
| try { |
| dealBusi.deal(data); |
| } finally { |
| try { |
| consumers.put(this); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| } |
| } |
| |
| } |
| |
| # 测试类 |
| public class Main { |
| |
| public static void main(String[] args) { |
| QryBusi qryBusi = new QryBusiImpl(); |
| DealBusi dealBusi = new DealBusiImpl(); |
| |
| ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 20, 5L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(20)); |
| |
| LinkedBlockingQueue<Runnable> runnables = new LinkedBlockingQueue<>(10); |
| for (int i = 0; i < 10; i++) { |
| try { |
| runnables.put(new Consumer(dealBusi,runnables)); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| Producer producer = new Producer(qryBusi,runnables,threadPoolExecutor); |
| |
| new Thread(producer).start(); |
| } |
| |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术
2021-05-18 Linux常用命令