Spring Boot 与腾讯云 MySQL 监听 Binlog 数据变化,并使用 UI 展示页面效果

news2024/11/19 11:55:55

引言

在现代的分布式系统和微服务架构中,数据同步和变更监控是保证系统一致性和实时性的核心问题之一。MySQL 数据库的 binlog(二进制日志)功能能够记录所有对数据库的修改操作,如插入(INSERT)、更新(UPDATE)、删除(DELETE)等,是实现实时数据变更同步的有效工具。

结合 Spring Boot 框架与腾讯云 MySQL 服务,通过 mysql-binlog-connector-java 库监听 MySQL 的 binlog 变化,可以实时捕捉数据库中的数据变更,并通过合适的前端展示技术(如 Bootstrap UI)动态呈现这些变化,增强系统的可视化和互动性。

本文将详细介绍如何在 Spring Boot 项目中实现 MySQL binlog 监听、数据变更处理,并通过 Bootstrap UI 动态展示变化效果,提供一个完整的解决方案。

腾讯云MySQL,59块玩一年~

请在此添加图片描述

本文目标

本文将通过以下步骤展示如何实现数据变化监听和展示:

  1. 配置腾讯云 MySQL 数据库,启用 binlog 功能。
  2. 在 Spring Boot 项目中集成 mysql-binlog-connector-java 来监听 MySQL binlog。
  3. 通过 Spring Boot 的 Controller 处理监听到的数据变化。
  4. 使用 Thymeleaf 将后台数据动态渲染到前端页面。
  5. 使用 Bootstrap UI 组件展示 MySQL 数据变化。
  6. 通过 JavaScript 和 Bootstrap 的模态框实现动态展示数据变化详情。

1. 配置腾讯云 MySQL 数据库并启用 Binlog

1.1 腾讯云 MySQL 配置

在腾讯云上创建并配置 MySQL 数据库是实现数据监听的前提。首先登录腾讯云控制台并创建一个 MySQL 实例。在创建过程中,确保启用了 binlog(二进制日志)功能,并设置合适的日志格式(通常使用 ROW 格式以便捕获详细的行级变更信息)。

  • 登录腾讯云控制台

进入腾讯云控制台,选择 云数据库,并创建一个新的 MySQL 实例。

  • 启用 binlog 功能:(这里需要注意一下,腾讯云MySQL的Binlog是默认开启的!!!

在创建数据库实例时,在参数配置中启用 binlog,设置 binlog-format=rowrow 格式能够捕获更为详细的行级变更信息,适用于大多数变更监听场景。

[mysqld]
log-bin=mysql-bin
server-id=1
binlog-format=row
  • 创建 binlog 监听用户:创建一个具有读取 binlog 权限的用户:
CREATE USER 'binlog_user'@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'binlog_user'@'%';
FLUSH PRIVILEGES;

此用户将用于监听和读取 binlog 数据。

  • 验证 binlog 配置:执行以下命令来检查 binlog 是否启用:
SHOW VARIABLES LIKE 'log_bin';
SHOW VARIABLES LIKE 'binlog_format';

如果返回值为 ONROW,说明 binlog 配置已成功启用。

2. 在 Spring Boot 中集成 mysql-binlog-connector-java

2.1 创建 Spring Boot 项目

首先创建一个 Spring Boot 项目,并在 pom.xml 中添加 mysql-binlog-connector-java 依赖:

<dependency>
    <groupId>com.github.shyiko</groupId>
    <artifactId>mysql-binlog-connector-java</artifactId>
    <version>0.21.0</version>
</dependency>

这个依赖会帮助我们在 Spring Boot 项目中使用 mysql-binlog-connector-java 库来连接和监听 MySQL 的 binlog。

2.2 编写 Binlog 监听服务

接下来,编写一个服务类,用于连接 MySQL 并监听 binlog 数据变化。在这个 BinlogService 类中,BinaryLogClient 被用来连接到 MySQL 服务器并监听 binlog 数据变化。监听到的事件会被添加到一个 LinkedBlockingQueue 中,这样我们可以在 Controller 中将这些数据展示到前端页面。通过 TableMapEventData 来获取表的映射关系。TableMapEventData 事件通常在 binlog 中包含了表名映射信息,它是与 WriteRowsEventData 一起生成的事件之一。WriteRowsEventData 实际上是通过 TableMapEventData 事件获得表 ID,然后使用这个 ID 来查找表名。

  • TableMap 事件:每当 TableMapEventData 事件发生时,我们将表的 tableId 和表名(getTable())映射到 tableIdToNameMap 中。这是因为 TableMapEventData 包含了一个表 ID 和表名的映射,这使得我们能够将表的 ID 与表名关联起来。
  • WriteRowsEventData:在插入数据(INSERT)事件发生时,我们从 tableIdToNameMap 中获取表名(通过 getTableId() 获取表 ID),然后记录插入的行数和表名。
  • UpdateRowsEventData:对于更新(UPDATE)事件,同样通过 getTableId() 获取表 ID,并从 tableIdToNameMap 中获取表名,记录更新的行数。
  • DeleteRowsEventData:对于删除(DELETE)事件,操作与 UPDATE 和 INSERT 类似,通过 tableIdToNameMap 获取表名,并记录删除的行数。
package com.example.demo.service;

import com.github.shyiko.mysql.binlog.BinaryLogClient;
import com.github.shyiko.mysql.binlog.event.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.*;

@Service
public class BinlogService {

    @Value("${mysql.host}")
    private String host;
    
    @Value("${mysql.port}")
    private int port;
    
    @Value("${mysql.username}")
    private String username;
    
    @Value("${mysql.password}")
    private String password;

    private LinkedBlockingQueue<String> binlogChanges = new LinkedBlockingQueue<>();

    // 存储 tableId -> tableName 的映射关系
    private Map<Long, String> tableIdToNameMap = new HashMap<>();

    // 开始监听 binlog
    public void startListening() throws Exception {
        BinaryLogClient client = new BinaryLogClient(host, port, username, password);

//         设置 serverId,防止与其他连接冲突
        client.setServerId(12345);

        // 注册 binlog 事件监听器
        client.registerEventListener(new BinaryLogClient.EventListener() {
            @Override
            public void onEvent(Event event) {
                EventHeaderV4 header = event.getHeader();

                // 处理 TableMap 事件,用于记录表的映射关系
                if (event.getData() instanceof TableMapEventData) {
                    TableMapEventData tableMapData = (TableMapEventData) event.getData();
                    tableIdToNameMap.put(tableMapData.getTableId(), tableMapData.getTable());
                }
                // 判断事件类型,处理不同的 binlog 事件
                if (event.getData() instanceof WriteRowsEventData) {
                    WriteRowsEventData data = (WriteRowsEventData) event.getData();
                    String tableName = tableIdToNameMap.get(data.getTableId());
                    int rowsCount = data.getRows().size();
                    String message = String.format("INSERT事件:表 %s 插入了 %d 行数据", tableName, rowsCount);
                    binlogChanges.offer(message);
                } 
                else if (event.getData() instanceof UpdateRowsEventData) {
                    UpdateRowsEventData data = (UpdateRowsEventData) event.getData();
                    String tableName = tableIdToNameMap.get(data.getTableId());
                    int rowsCount = data.getRows().size();
                    String message = String.format("UPDATE事件:表 %s 更新了 %d 行数据", tableName, rowsCount);
                    binlogChanges.offer(message);
                }
                else if (event.getData() instanceof DeleteRowsEventData) {
                    DeleteRowsEventData data = (DeleteRowsEventData) event.getData();
                    String tableName = tableIdToNameMap.get(data.getTableId());
                    int rowsCount = data.getRows().size();
                    String message = String.format("DELETE事件:表 %s 删除了 %d 行数据", tableName, rowsCount);
                    binlogChanges.offer(message);
                }
            }
        });

        // 连接并开始监听 binlog
        client.connect();
    }

    // 获取最新的 binlog 数据变化
    public LinkedBlockingQueue<String> getBinlogChanges() {
        return binlogChanges;
    }
}

2.3 配置应用属性

application.properties 中配置 MySQL 的连接信息:

mysql.host=localhost
mysql.port=3306
mysql.username=binlog_user
mysql.password=password

2.4 创建 Controller 来处理 binlog 数据

在 Controller 中,我们将监听到的 binlog 变化通过模型传递给前端页面。在这个 Controller 中,index() 方法将 binlog 变化数据传递给前端页面。

package com.example.demo.controller;

import com.example.demo.service.BinlogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class BinlogController {

    @Autowired
    private BinlogService binlogService;

    @GetMapping("/")
    public String index(Model model) {
        model.addAttribute("binlogChanges", binlogService.getBinlogChanges());
        return "binlog";
    }
}

2.5 确保监听器在正确的位置启动

如果在启动时需要监听 binlog 数据变化,需要确保在合适的时机启动监听器。例如,可以在 @PostConstruct 方法中启动,也可以使用 Spring Boot 的 CommandLineRunnerApplicationRunner 来确保应用启动后执行相关任务。

package com.example.demo.config;

import com.example.demo.service.BinlogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Component
public class BinlogListenerRunner implements CommandLineRunner {

    @Autowired
    private BinlogService binlogService;

//    @PostConstruct
//    @Async  // 异步执行 binlog 监听
//    public void start() {
//    }

    @Override
    public void run(String... args) throws Exception {
        try {
            binlogService.startListening();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3. 使用 Bootstrap UI 展示数据变化

3.1 配置 Thymeleaf 模板

我们使用 Thymeleaf 模板引擎来动态渲染页面。首先,在 src/main/resources/templates 目录下创建一个 index.html 文件,并引入 Bootstrap UI 和 Thymeleaf 标签。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Binlog 数据变化展示</title>
    <!-- 引入 Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container">
    <h1 class="text-center my-4">Binlog 数据变化监控</h1>

    <!-- 动态展示数据变化 -->
    <div id="binlogChanges" class="row">
        <div class="col-md-4" th:each="change : ${binlogChanges}">
            <div class="card mb-3">
                <div class="card-body">
                    <h5 class="card-title">数据变化</h5>
                    <p class="card-text" th:text="${change}"></p>
                    <button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#changeDetailsModal"
                            th:attr="data-bs-whatever=${change}">查看详情</button>
                </div>
            </div>
        </div>
    </div>

    <!-- 模态框展示详细信息 -->
    <div class="modal fade" id="changeDetailsModal" tabindex="-1" aria-labelledby="changeDetailsModalLabel" aria-hidden="true">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="changeDetailsModalLabel">数据变化详情</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body">
                    <p id="changeDetails">详细信息加载中...</p>
                </div>
            </div>
        </div>
    </div>
</div>

<script>
    var changeDetailsModal = document.getElementById('changeDetailsModal');
    changeDetailsModal.addEventListener('show.bs.modal', function (event) {
        var button = event.relatedTarget;
        var changeDetails = button.getAttribute('data-bs-whatever');
        var modalBody = changeDetailsModal.querySelector('.modal-body #changeDetails');
        modalBody.textContent = changeDetails;
    });
</script>
</body>
</html>

3.2 动态更新 binlog 数据

在页面加载时,通过 th:each 将后台的 binlog 变化数据动态展示在卡片中。每当新的数据变化被监听到,前端页面会自动更新并显示最新的变化。

3.3 效果展示

通过以上方法,您可以创建一个高效、可靠的实时数据监听与展示系统。

请在此添加图片描述


4. 总结与优化

4.1 总结

通过结合 Spring Boot 框架和腾讯云 MySQL 服务,利用 binlog 监听 MySQL 数据变化并在前端展示,我们能够实时捕捉并展示数据库的变化,极大地提升了系统的响应性和实时性。在前端,我们使用了 Bootstrap UI 组件,如卡片、按钮和模态框,创建了一个用户友好的界面。

4.2 优化与扩展

  • 实时推送:目前的实现通过轮询获取数据,可以考虑使用 WebSocket 来实现实时推送,减少轮询带来的性能开销。
  • 数据过滤与精确化:根据业务需求,可以对监听到的 binlog 数据进行精确过滤,仅处理特定的表或操作。
  • 日志与监控:在生产环境中,记录日志并进行健康监控对于高可用系统至关重要,可以考虑集成 Spring Boot Actuator 进行系统健康检查。

5. 使用MySQL减轻轻量应用服务器功能压力

通过将数据存储和处理卸载到腾讯云MySQL,CVM可以专注于处理应用逻辑和业务需求,减轻数据库管理、查询优化、存储管理等方面的负担。腾讯云MySQL提供的高性能、自动化运维、分布式架构、数据安全等功能,有助于提升系统的稳定性、可扩展性和性能,进而减少CVM服务器的功能压力,使得整体系统更加高效、可靠。

请在此添加图片描述

5.1 集中式数据库管理

腾讯云MySQL是一个完全托管的数据库服务,用户无需担心数据库的硬件资源、备份、维护和高可用性配置等问题。通过使用腾讯云MySQL,CVM可以将业务逻辑的复杂性转移到数据库层,减轻服务器的处理负担。

5.2 优化数据库查询性能

腾讯云MySQL拥有丰富的查询优化工具和调优功能(如查询缓存、索引优化、SQL调优等),通过合理的设计和配置,可以显著提高数据库的查询性能,减轻CVM服务器的负担。

5.3 分布式数据库架构

腾讯云MySQL支持分布式数据库架构(如读写分离、分表分库、Sharding等)。通过合理配置,可以将数据库负载分散到多个节点上,避免单一CVM服务器的过载。

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

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

相关文章

Spring Boot汽车资讯:科技与速度的新纪元

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了汽车资讯网站的开发全过程。通过分析汽车资讯网站管理的不足&#xff0c;创建了一个计算机管理汽车资讯网站的方案。文章介绍了汽车资讯网站的系统分析部分&…

thinkphp6模板调用URL方法生成的链接异常

var uul params.url ;console.log(params.url);console.log("{:Url(UserLog/index)}");console.log("{:Url("uul")}"); 生成的链接地址 UserLog/index /jjg/index.php/Home/UserLog/index.html /jjg/index.php/Home/Index/UserLog/index.html…

NodeJS 百度智能云文本转语音(实测)

现在文本转语音的技术已经非常完善了&#xff0c;尽管网络上有许多免费的工具&#xff0c;还是测试了专业的服务&#xff0c;选择了百度的TTS服务。 于是&#xff0c;在百度智能云注册和开通了文本转语音的服务&#xff0c;尝试使用NodeJS 实现文本转语音服务。但是百度的文档实…

UML 类图讲解

UML 类图符号含义 在 UML 类图中&#xff0c;每个符号都有其特定的含义。以下是常见符号的解释&#xff1a; : Public&#xff08;公共访问权限&#xff09;-: Private&#xff08;私有访问权限&#xff09;#: Protected&#xff08;受保护访问权限&#xff09;~: Package&…

【GAT】 代码详解 (1) 运行方法【pytorch】可运行版本

GRAPH ATTENTION NETWORKS 代码详解 前言0.引言1. 环境配置2. 代码的运行2.1 报错处理2.2 运行结果展示 3.总结 前言 在前文中&#xff0c;我们已经深入探讨了图卷积神经网络和图注意力网络的理论基础。还没看的同学点这里补习下。接下来&#xff0c;将开启一个新的阶段&#…

远程控制步骤

当远在千里之外的朋友想求助你帮他找到他电脑上的文件、或者是给他安装软件时。但是你给他说了他又找不到&#xff0c;那么这时你就可以通过控制对方的电脑去做一系列的操作。 如何远程控制对方的电脑非常关键。 方法一&#xff08;Windows自带远程桌面功能&#xff09;&#…

C指针之舞——指针探秘之旅

❤博客主页&#xff1a;折枝寄北-CSDN博客 ❤专栏内容&#xff1a;C语言学习专栏https://blog.csdn.net/2303_80170533/category_12794764.html?spm1001.2014.3001.5482 指针基础学习 在之前的博客文章中&#xff0c;简单总结了指针的基础概念 我们知道了指针的概念&#xf…

前端 JS 浅拷贝与深拷贝

目录 一、问题引出 二、浅拷贝 1、通过解构重构实现浅拷贝 三、深拷贝 1、自定义实现深拷贝 2、JSON实现深拷贝 四、总结 一、问题引出 基础类型的数据存放&#xff1a; let a 100let b aconsole.log("a:" a, "b:" b)a 50console.log("a…

72项!湖北省2024年度第二批省级科技计划项目拟立项项目公示!

本期精选 SCI&EI ●IEEE 1区TOP 计算机类&#xff08;含CCF&#xff09;&#xff1b; ●EI快刊&#xff1a;最快1周录用&#xff01; 知网(CNKI)、谷歌学术期刊 ●7天录用-检索&#xff08;100%录用&#xff09;&#xff0c;1周上线&#xff1b; 免费稿件评估 免费匹配…

uniapp微信小程序转发跳转指定页面

onShareAppMessage 是微信小程序中的一个重要函数&#xff0c;用于自定义转发内容。当用户点击右上角的菜单按钮&#xff0c;并选择“转发”时&#xff0c;会触发这个函数。开发者可以在这个函数中返回一个对象&#xff0c;用于定义分享卡片的标题、图片、路径等信息。 使用场…

[N1CTF 2018]eating_cms

打开题目 只有个登录框&#xff0c;其他什么都没有&#xff0c;尝试了一下弱口令&#xff0c;没能成功 尝试访问一下register.php&#xff0c;看看能不能注册个账号 注册页面&#xff0c;随便注册个账号登陆一下 url中感觉是个注入点&#xff0c;尝试使用file伪协议读取一下us…

PMP–一、二、三模、冲刺–分类–5.范围管理–技巧–引导

文章目录 技巧一模5.范围管理--3.定义范围--工具与技术--引导--在研讨会和座谈会中使用引导技能来协调具有不同期望或不同专业知识的关键干系人&#xff0c;使他们就项目可交付成果以及项目和产品边界达成跨职能的共识。引导&#xff1a;题干关键词 “需求不同、需求差异、需求…

C语言-字符串指针及多变的访问方式

1、字符串指针 示例;输出字符串数组 1. #include <stdio.h> 2. #include <string.h> 3. 4. int main(){ 5. char str[] "<http://baidu.com>"; 6. int len strlen(str), i; 7. //直接输出字符串 8. printf("%s\\n", str); 9. //每次…

Linux之vim模式下全选命令

在Linux系统中&#xff0c;使用Vim编辑器进行全选操作可以通过以下几种方式实现&#xff1a; 1.使用键盘快捷键 按下 ”ggVG”&#xff08;先按下”g”&#xff0c;再按下”g”&#xff0c;再按下”V”&#xff0c;最后按下”G”&#xff09;可以全选当前文件内容。其中 ”g…

解决虚拟机未被自动分配ip

文章目录 1. 背景2. 解决步骤 1. 背景 从vulnhub下载的靶场文件&#xff0c;网络适配器模式设置为nat模式之后&#xff0c;启动虚拟机之后发现没有成功分配动态ip。推测是虚拟机分配的网卡名称和原先靶机作者设置网络配置文件 网络接口名称不一致导致。 2. 解决步骤 解决办法就…

【数据结构与算法】排序

文章目录 排序1.基本概念2.分类2.存储结构 一.插入排序1.1直接插入排序1.2折半插入排序1.3希尔排序 二.选择排序2.1简单选择排序2.2堆排序 三.交换排序3.1冒泡排序3.2快速排序 四.归并排序五.基数排序**总结** 排序 1.基本概念 排序&#xff08;sorting&#xff09;又称分类&…

5. ARM_指令集

概述 分类 汇编中的符号&#xff1a; 指令&#xff1a;能够编译生成一条32位机器码&#xff0c;并且能被处理器识别和执行伪指令&#xff1a;本身不是指令&#xff0c;编译器可以将其替换成若干条指令伪操作&#xff1a;不会生成指令&#xff0c;只是在编译阶段告诉编译器怎…

WPF MVVM框架

一、MVVM简介 MVC Model View Control MVP MVVM即Model-View-ViewModel&#xff0c;MVVM模式与MVP&#xff08;Model-View-Presenter&#xff09;模式相似&#xff0c;主要目的是分离视图&#xff08;View&#xff09;和模型&#xff08;Model&#xff09;&#xff0c;具有低…

Java-03 深入浅出 MyBatis - 快速入门(无 Spring) 增删改查 核心配置讲解 XML 与 注解映射

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 大数据篇正在更新&#xff01;https://blog.csdn.net/w776341482/category_12713819.html 目前已经更新到了&#xff1a; MyBatis&#xff…

Spring Cloud Alibaba [Gateway]网关。

1 简介 网关作为流量的入口&#xff0c;常用功能包括路由转发、权限校验、限流控制等。而springcloudgateway 作为SpringCloud 官方推出的第二代网关框架&#xff0c;取代了Zuul网关。 1.1 SpringCloudGateway特点: &#xff08;1&#xff09;基于Spring5&#xff0c;支持响应…