基于binlog实现一些业务(Binlog4j)

前言

       今天要跟大家分享的是监控数据变化,实现自己的业务的另一个思路,基于数据库的binglog。我这里是用的Binlog4j实现,希望看总结的,直接看最后。


一、Binlog4j是什么?

       Binlog4j是轻量级 Mysql Binlog 客户端, 提供宕机续读, 高可用集群等特性等等。具体看一看它的官网,目前已经出到1.9.0版本,项目加入了Dromara 社区。

二、使用步骤

先说下我这里用上这个的原因:

  • 多个数据增删改触发重新计算
  • 不想在每个业务操作方法后调用重新计算
  • 不想aop切面处理,实现重新计算
  • 不想用springboot的事件、监听实现重新计算
  • 骨子里想创新,接受新事物、新思路
    所以我选择了它,下面我简单介绍下使用。

官网其实有demo,我这里是与springboot集成。

1.引入库

<!-- binlog支持 --><dependency><groupId>com.gitee.Jmysy</groupId><artifactId>binlog4j-spring-boot-starter</artifactId><version>1.9.0</version></dependency>

       mysql的依赖、redis的依赖自行补充。

2.配置文件

spring:  binlog4j:database: 要监听的数据库(一个实例上有多个库)redis-config: #redis配置host: ipport: 端口password: 密码client-configs:master:username: 数据库用户password: 密码host: 数据库ipport: 端口serverId: 1990

配置说明

  • timeOffset 时间偏移量, 单位:毫秒
  • serverId 编号
  • redisConfig Redis 配置信息, 详见 RedisConfig
  • inaugural 首次启动, 如果为 true 在启动时不再读取 Redis 记录
  • persistence 是否启用持久化, 默认为 false
  • strict 严格模式, 默认为 true
  • mode 模式, 详见: BinlogClientMode
  • username 数据库账户
  • password 数据库密码
  • host 数据库所在服务器 IP 地址
  • port 数据库占用端口, 默认 3306
  • hikariConfig 数据库连接池配置

3.统一监听处理

MyBinlogEventHandler


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.date.StopWatch;
import cn.hutool.json.JSONUtil;
import com.gitee.Jmysy.binlog4j.core.BinlogEvent;
import com.gitee.Jmysy.binlog4j.core.IBinlogEventHandler;
import com.gitee.Jmysy.binlog4j.springboot.starter.annotation.BinlogSubscriber;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import site.morn.rest.RestBuilders;
import site.morn.rest.RestMessage;import javax.annotation.Resource;/*** binlog事件处理器* 连接数据的用户需要有binlog读权限** @author zwmac*/
@Slf4j
@BinlogSubscriber(clientName = "master")
public class MyBinlogEventHandler implements IBinlogEventHandler {@Value("${spring.binlog4j.database:linkappdb}")public String monitorDatabase;@Resourceprivate ProgressWarnService progressWarnService;@Overridepublic void onInsert(BinlogEvent binlogEvent) {//log.info("数据库:" + binlogEvent.getDatabase());//log.info("数据表:" + binlogEvent.getTable());//log.info("插入数据:" + binlogEvent.getData());//需要重新计算场景//1、插入设置 app_progress_warn_config//2、新增实际进度详情 app_progress_real_detail//3、新增进度计划任务(子节点)app_progress_infoRestMessage restMessage = RestBuilders.successMessage();CalProgressWarnVo calVo = new CalProgressWarnVo();calVo.setType(1);String tableName = binlogEvent.getTable();if ("app_progress_warn_config".equals(tableName)) {StopWatch sw = new StopWatch();sw.start();calVo.setDataType(1);ProgressWarnConfig progressWarnConfig = BeanUtil.mapToBean(JSONUtil.parseObj(binlogEvent.getData()), ProgressWarnConfig.class, true, CopyOptions.create().ignoreNullValue());calVo.setNewData(progressWarnConfig);restMessage = progressWarnService.calProgressWarn(calVo);sw.stop();log.info("新增[进度预警配置]数据触发binlog事件执行结果:{}-耗时:{}ms", restMessage.getCode(), sw.getTotalTimeMillis());}if ("app_progress_real_detail".equals(tableName)) {StopWatch sw = new StopWatch();sw.start();calVo.setDataType(2);ProgressRealDetail realDetail = BeanUtil.mapToBean(JSONUtil.parseObj(binlogEvent.getData()), ProgressRealDetail.class, true, CopyOptions.create().ignoreNullValue());calVo.setNewData(realDetail);restMessage = progressWarnService.calProgressWarn(calVo);sw.stop();log.info("新增[实际进度详情]数据触发binlog事件执行结果:{}-耗时{}ms", restMessage.getCode(), sw.getTotalTimeMillis());}if ("app_progress_info".equals(tableName)) {StopWatch sw = new StopWatch();sw.start();Object progressInfoObj = binlogEvent.getData();ProgressInfo progressInfo = BeanUtil.mapToBean(JSONUtil.parseObj(binlogEvent.getData()), ProgressInfo.class, true, CopyOptions.create().ignoreNullValue());if (progressInfo.getType() == 2) {//计划任务才需要重新计算calVo.setDataType(3);calVo.setNewData(progressInfo);restMessage = progressWarnService.calProgressWarn(calVo);}sw.stop();log.info("新增[进度任务]数据触发binlog事件执行结果:{}-耗时{}ms", restMessage.getCode(), sw.getTotalTimeMillis());}}@Overridepublic void onUpdate(BinlogEvent binlogEvent) {//log.info("数据库:" + binlogEvent.getDatabase());//log.info("数据表:" + binlogEvent.getTable());//log.info("原数据:" + binlogEvent.getOriginalData());//log.info("新数据:" + binlogEvent.getData());//需要重新计算场景//1、设置表变更 app_progress_warn_config//2、进度详情记录变更 app_progress_real_detail//3、进度计划任务变更(计划开始时间、计划结束时间、工期)app_progress_infoRestMessage restMessage = null;CalProgressWarnVo calVo = new CalProgressWarnVo();calVo.setType(2);String tableName = binlogEvent.getTable();if ("app_progress_warn_config".equals(tableName)) {StopWatch sw = new StopWatch();sw.start();calVo.setDataType(1);ProgressWarnConfig oldConfig = BeanUtil.mapToBean(JSONUtil.parseObj(binlogEvent.getOriginalData()), ProgressWarnConfig.class, true, CopyOptions.create().ignoreNullValue());ProgressWarnConfig newConfig = BeanUtil.mapToBean(JSONUtil.parseObj(binlogEvent.getData()), ProgressWarnConfig.class, true, CopyOptions.create().ignoreNullValue());calVo.setNewData(newConfig);calVo.setOldData(oldConfig);restMessage = progressWarnService.calProgressWarn(calVo);sw.stop();log.info("修改[进度预警配置]数据触发binlog事件执行结果:{}-耗时{}ms", restMessage.getCode(), sw.getTotalTimeMillis());}if ("app_progress_real_detail".equals(tableName)) {StopWatch sw = new StopWatch();sw.start();calVo.setDataType(2);ProgressRealDetail oldDetail = BeanUtil.mapToBean(JSONUtil.parseObj(binlogEvent.getOriginalData()), ProgressRealDetail.class, true, CopyOptions.create().ignoreNullValue());ProgressRealDetail newDetail = BeanUtil.mapToBean(JSONUtil.parseObj(binlogEvent.getData()), ProgressRealDetail.class, true, CopyOptions.create().ignoreNullValue());calVo.setNewData(newDetail);calVo.setOldData(oldDetail);restMessage = progressWarnService.calProgressWarn(calVo);sw.stop();log.info("修改[进度详情]数据触发binlog事件执行结果:{}-耗时{}ms", restMessage.getCode(), sw.getTotalTimeMillis());}if ("app_progress_info".equals(tableName)) {StopWatch sw = new StopWatch();sw.start();calVo.setDataType(3);ProgressInfo oldInfo = BeanUtil.mapToBean(JSONUtil.parseObj(binlogEvent.getOriginalData()), ProgressInfo.class, true, CopyOptions.create().ignoreNullValue());ProgressInfo newInfo = BeanUtil.mapToBean(JSONUtil.parseObj(binlogEvent.getData()), ProgressInfo.class, true, CopyOptions.create().ignoreNullValue());calVo.setNewData(newInfo);calVo.setOldData(oldInfo);restMessage = progressWarnService.calProgressWarn(calVo);sw.stop();log.info("修改[进度计划任务]数据触发binlog事件执行结果:{}-耗时{}ms", restMessage.getCode(), sw.getTotalTimeMillis());}}@Overridepublic void onDelete(BinlogEvent binlogEvent) {//log.info("数据库:" + binlogEvent.getDatabase());//log.info("数据表:" + binlogEvent.getTable());//log.info("删除数据:" + binlogEvent.getData());//需要重新计算场景//1、删除进度详情记录 app_progress_real_detail//2、删除进度任务(子节点)app_progress_infoRestMessage restMessage = null;CalProgressWarnVo calVo = new CalProgressWarnVo();calVo.setType(3);String tableName = binlogEvent.getTable();if ("app_progress_real_detail".equals(tableName)) {StopWatch sw = new StopWatch();sw.start();calVo.setDataType(2);ProgressRealDetail oldDetail = BeanUtil.mapToBean(JSONUtil.parseObj(binlogEvent.getOriginalData()), ProgressRealDetail.class, true, CopyOptions.create().ignoreNullValue());calVo.setOldData(oldDetail);restMessage = progressWarnService.calProgressWarn(calVo);sw.stop();log.info("删除[进度详情]数据触发binlog事件执行结果:{}-耗时{}ms", restMessage.getCode(), sw.getTotalTimeMillis());}if ("app_progress_info".equals(tableName)) {StopWatch sw = new StopWatch();sw.start();calVo.setDataType(3);ProgressInfo oldInfo = BeanUtil.mapToBean(JSONUtil.parseObj(binlogEvent.getOriginalData()), ProgressInfo.class, true, CopyOptions.create().ignoreNullValue());calVo.setOldData(oldInfo);restMessage = progressWarnService.calProgressWarn(calVo);sw.stop();log.info("删除[进度计划任务]数据触发binlog事件执行结果:{}-耗时{}ms", restMessage.getCode(), sw.getTotalTimeMillis());}}@Overridepublic boolean isHandle(String database, String table) {//log.info("database:{},table:{}", database, table);//只监控aep数据库if (monitorDatabase.equals(database)) {return true;}return false;}}

CalProgressWarnVo

import lombok.Data;/*** 计算进度预警参数Vo** @author zwmac*/
@Data
public class CalProgressWarnVo {/*** 类型:1新增,2变更,3删除*/private Integer type;/*** 数据类型:1进度预警配置,2进度详情,3进度计划任务*/private Integer dataType;/*** 旧数据*/private Object oldData;/*** 新数据*/private Object newData;}

       从入参可以看出3类数据增删改都触发重新计算,这里的oldData、newData可以直接用于修改的时候传参,不用在查一次数据库。


progressWarnService.calProgressWarn(calVo);就是重新计算的具体实现了,这就涉及到业务了,各位自己实现。

总结

  • 配置的账号要有binlog的读权限
  • 项目在跑,直接用其他工具操作数据库,也可以触发(这就是监听binlog的美妙)
  • 其他项目操作本项目的表,也可以监听到(原理同上)
  • 统一入口,不用有aop、事件、业务调用那么多入口需要考虑
           好了,就写到这里,希望可以帮到大家,拥抱新事物,uping!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/189834.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2022年03月22日 Go生态洞察:泛型介绍

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

HT71778 实时音频信号跟踪同步升压转换器的特性

HT71778是一款高功率、全集成升压转换器&#xff0c;集成16mΩ功率开关管和18mΩ同步整流管&#xff0c;为便携式系统提供G效的小尺寸处理方案。 HT71778 实时音频信号跟踪同步升压转换器的特性&#xff1a; ・实时音频信号跟踪的电源供电 SN 短接地, VIN 2.7~4.5V, VOUT 5…

Hdoop学习笔记(HDP)-Part.02 核心组件原理

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

Redis - 多数据源切换

问题描述 最近遇到一个 Redis 多数据源切换问题&#xff0c;不过我这个没有那么动态切换需求&#xff0c;所以就写了一种比较硬编码的方式来做『切换』 其实大概的场景是这样的&#xff1a;不同的开发环境调用 db0、生产环境调用 db1&#xff0c;但是因为业务原因&#xff0c…

python绘制皮卡丘

1.源代码 import turtle as t import time # 皮卡丘 # 基础设置 t.screensize(800, 600) t.pensize(2) # 设置画笔的大小 t.speed(10) # 设置画笔速度为10 # 画左偏曲线函数 def radian_left(ang, dis, step, n):for i in range(n):dis step # dis增大stept.lt(ang) # 向左…

二、ZooKeeper集群搭建

目录 1、概述 2、安装 2.1 第一步&#xff1a;下载zookeeeper压缩包 2.2 第二步&#xff1a;解压 ​​​​​​​2.3 第三步&#xff1a;修改配置文件 ​​​​​​​2.4 第四步&#xff1a;添加myid配置 ​​​​​​​2.5 第五步&#xff1a;安装包分发并修改myid的值…

《微信小程序开发从入门到实战》学习三十八

4.2 云开发JSON数据库 4.2.9 条件查询与查询指令 在查询数据时&#xff0c;有时需要对查找的数据添加一些限定条件&#xff0c;只获取满足给定条件的数据&#xff0c;这样的查询称为条件查询。 可以在集合引用上使用where方法指定查询条件&#xff0c;再用get方法&#xff0…

IBL环境贴图原理及着色器实现【基于图像的照明】

IBL - Image Based Lighting - 也就是基于图像的照明&#xff0c;是一组照亮物体的技术&#xff0c;不是像上一章那样通过直接分析光&#xff0c;而是将周围环境视为一个大光源。 这通常是通过操作立方体贴图环境贴图&#xff08;取自现实世界或从 3D 场景生成&#xff09;来完…

基于hadoop下的hbase安装

简介 HBase是一个分布式的、面向列的开源数据库&#xff0c;该技术来源于Fay Chang所撰写的Google论文“Bigtable&#xff1a;一个结构化数据的分布式存储系统”。就像Bigtable利用了Google文件系统&#xff08;File System&#xff09;所提供的分布式数据存储一样&#xff0c;…

php 使用多线程

fpm cli socket redis PHP多线程-阿里云开发者社区 常驻内存&#xff1a;op cli EasyTask: PHP常驻内存多进程任务管理器&#xff0c;支持定时任务(PHP resident memory multi-process task manager, supports timing tasks) 协程&#xff1a;swoole Swoole - PHP 协…

YOLOv8创新魔改教程(一)如何进行模块创新

YOLOv8创新魔改教程&#xff08;一&#xff09;如何进行模块创新 YOLOv8创新魔改教程 本人研一&#xff0c;最近好多朋友问我要如何修改模型创新模块&#xff0c;就想着不如直接开个专栏歇一歇文章&#xff0c;也算是对自己学习的总结&#xff0c;本专栏以YOLOv8为例&#xf…

「C++」类和对象2

&#x1f387;个人主页&#xff1a;Ice_Sugar_7 &#x1f387;所属专栏&#xff1a;C启航 &#x1f387;欢迎点赞收藏加关注哦&#xff01; 文章目录 &#x1f349;前言&#x1f349;构造函数&#x1f34c;参数&#x1f34c;默认构造函数&#x1f95d;两种类型&#x1f95d;编译…

CentOS系统环境搭建(二十四)——借助Git实现一键部署

centos系统环境搭建专栏&#x1f517;点击跳转 文章目录 如何一键部署1.后端1.1 拉取代码1.2 打包1.2.1 如果打包没问题&#xff0c;只看这部分即可1.2.2 maven有问题看这一部分1.2.2.1 安装jdk1.2.2.2 Jdk路径寻找&#xff0c;使用命令1.2.2.3 由此可知&#xff0c;jdk路径为…

优化问题,详解静态优化

优化问题&#xff0c;尤其静态优化问题&#xff0c;在控制系统设计中随处可见&#xff0c;例如基于燃油经济性和驾驶体验的多目标优化的汽车发动机 MAP 标定&#xff0c;基于性能指标优化的飞行器结构设计参数优化&#xff0c;以实验数据与模型输出匹配为目标的电池 RC 等效电路…

K8S集群搭建redis集群的步骤

在Kubernetes&#xff08;K8s&#xff09;集群上搭建Redis集群涉及多个步骤&#xff0c;包括创建配置文件、部署StatefulSets和设置网络。以下是一个基本指南&#xff1a; 1. 准备Redis配置文件 首先&#xff0c;创建一个Redis配置文件&#xff08;redis.conf&#xff09;&am…

Python基础学习快速入门

文章目录 Number变量String字符串Def函数Class类List列表Tuple元组Dictionary字典Set集合值与引用类型if条件控制Loop循环 Number变量 python直接赋值&#xff0c;不需要定义变量类型。不需要**,逗号结尾符 使用print**直接进行输出 #赋值 a 1.0 print(a)a 7 print(a)p…

带删除的并查集

Almost Union-Find 支持三种操作 合并 x x x和 y y y所在的集合把 x x x移到 y y y所在的集合求 x x x所在的集合的元素个数和元素之和 操作1和3是基本的并查集的操作. 关键在于操作 2 2 2: 若使用朴素的并查集&#xff0c;把节点 1 1 1合并到 3 3 3所在的集合&#xff0c;会…

华为OD机试 - 最多购买宝石数目(Java JS Python C)

题目描述 橱窗里有一排宝石,不同的宝石对应不同的价格,宝石的价格标记为 gems[i] 0 ≤ i < nn = gems.length宝石可同时出售0个或多个,如果同时出售多个,则要求出售的宝石编号连续; 例如客户最大购买宝石个数为m,购买的宝石编号必须为:gems[i],gems[i+1],...,ge…

ES-ELSER 如何在内网中离线导入ES官方的稀疏向量模型(国内网络环境下操作方法)

ES官方训练了稀疏向量模型&#xff0c;用来支持语义检索。&#xff08;目前该模型只支持英文&#xff09; 最好是以离线的方式安装。在线的方式&#xff0c;在国内下载也麻烦&#xff0c;下载速度也慢。还不如用离线的方式。对于一般的生产环境&#xff0c;基本上也是网络隔离的…

SQL注入漏洞的检测及防御方法

SQL注入&#xff08;SQL Injection&#xff09;是一种广泛存在于Web应用程序中的严重安全漏洞&#xff0c;它允许攻击者在不得到授权的情况下访问、修改或删除数据库中的数据。这是一种常见的攻击方式&#xff0c;因此数据库开发者、Web开发者和安全专业人员需要了解它&#xf…