文章目录
背景
1、内容
通过监听mysql的主库的写、删、更新操作产生的binlog日志,来做业务(eg:监控数据、同步数据等)
2、作用
- 无感知
服务A编辑数据库,服务B监听A的mysql内容,对于A而言,感知不到服务B的存在
3、缺点
- 主库压力大
如果写的并发很高,服务B监听binlog,同步信息,会对主库造成压力
- 必须写库成功后,才能监听到binlog同步的内容
假如B站用户点赞行为,A服务需要写库,写完库后,B服务需要同步财务结算up主收益
假如A写库失败了,B服务监听不到binlog,本次点赞行为就丢失了。这种场景不适合
这种场景可以使用MQ来解决
快速入门
1、pom
<!-- https://mvnrepository.com/artifact/com.gitee.Jmysy/binlog4j-spring-boot-starter -->
<dependency>
<groupId>com.gitee.Jmysy</groupId>
<artifactId>binlog4j-spring-boot-starter</artifactId>
<version>1.9.1</version>
</dependency>
- 支持集群模式
- 宕机续读(服务A写mysql,服务B监听,假如在服务B宕机期间,A写了新数据,则B重新启动后,仍可以获取到期间的binlog同步内容),实现:通过redis配置的serverId,去对应的binlogfileName + position获取
- 数据转换
2、yml配置
spring:
binlog4j:
redis-config:
host: 127.0.0.1
port: 6379
database: 1
client-configs:
master:
host: "127.0.0.1"
port: 3306
username: "root"
password: "941123"
mode: standalone
persistence: true
server-id: 1234
2、code实现
package com.mjp.binlog;
import com.gitee.Jmysy.binlog4j.core.BinlogEvent;
import com.gitee.Jmysy.binlog4j.core.IBinlogEventHandler;
import com.gitee.Jmysy.binlog4j.springboot.starter.annotation.BinlogSubscriber;
/**
* Author:majinpeng
* Date: 2024/08/23 10:47
*/
@BinlogSubscriber(clientName = "master")
public class Binlog4jServiceHandler implements IBinlogEventHandler<Object> {
// 这里的Object即你数据库中的实体类,比如Order、User
// 如果可以确定,则使用具体的User
// 如果是Object,则binlogEvent中的T data属性是map
@Override
public void onInsert(BinlogEvent<Object> binlogEvent) {
}
@Override
public void onUpdate(BinlogEvent<Object> binlogEvent) {
System.out.println(binlogEvent.toString());
}
@Override
public void onDelete(BinlogEvent<Object> binlogEvent) {
}
@Override
public boolean isHandle(String s, String s1) {
// 如果将<Object>使用具体的<User>接收,则一定需要在isHandle中,判断当前Binlog4jServiceHandler是否执行了
// 否则可能会因为映射的对象不符合,造成数据丢失
return false;
}
}
监听普通文件内容变动
1、实现CommandLineRunner接口 或 ApplicationRunner接口
2、使用hutool的WatchMonitor工具类(底层封装了JDK的WatchService)
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.31</version>
</dependency>
3、使用Tailer工具类
@Component
public class MonitorFile implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
File file = FileUtil.file("C:\\Users\\admin\\Desktop\\test.txt");
try (WatchMonitor watchMonitor = WatchMonitor.create(file, WatchMonitor.ENTRY_MODIFY)) {
watchMonitor.setWatcher(new Watcher() {
@Override
public void onCreate(WatchEvent<?> event, Path currentPath) {
}
@Override
public void onModify(WatchEvent<?> event, Path currentPath) {
Object context = event.context();
System.out.println("modify!!!" + context.toString());
}
@Override
public void onDelete(WatchEvent<?> event, Path currentPath) {
}
@Override
public void onOverflow(WatchEvent<?> event, Path currentPath) {
}
});
// 监听目录的足最大深度,
watchMonitor.setMaxDepth(3);
watchMonitor.start();
}
Tailer tailer = new Tailer(file, line -> System.out.println("变动的数据内容为:" + line));
tailer.start();
}
}