How to Sync MySQL to Redis in Real-Time with Spring Boot 3 and mysql-binlog-connector-java
This article demonstrates how to achieve real‑time synchronization of MySQL data to Redis using Spring Boot 3, the open‑source mysql‑binlog‑connector‑java library, and optional JMX exposure, providing step‑by‑step setup, code examples for parsing binlog events, listening to changes, and configuring Maven dependencies.
Introduction
MySQL‑Redis real‑time synchronization reflects changes in a MySQL database instantly in a Redis cache. MySQL provides durable relational storage, while Redis offers high‑performance in‑memory caching. Combining them improves system performance and consistency, especially for high‑concurrency scenarios such as e‑commerce and social platforms.
Component Features
Automatic parsing of binlog file name/position and GTID
Connection‑loss recovery
Pluggable failover strategy
Supports binlog_checksum=CRC32 (MySQL 5.6.2+)
Secure communication via TLS
JMX management extension
Real‑time statistics
Available on Maven Central
No third‑party dependencies, tested across MySQL versions
Environment Preparation
Add the following Maven dependencies to your Spring Boot project:
<code><dependency>
<groupId>com.zendesk</groupId>
<artifactId>mysql-binlog-connector-java</artifactId>
<version>0.30.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency></code>Ensure MySQL binlog logging is enabled:
<code>SHOW VARIABLES LIKE '%log_bin%';</code>Run the command and verify the output. Example screenshot:
1. Programmatically Parse Binlog
The following Java program reads a binlog file, deserializes events, and prints their details:
<code>public static void main(String[] args) throws Exception {
File binlogFile = new File("C:\\ProgramData\\MySQL\\MySQL Server 5.7\\Data\\mysql-bin.000032");
EventDeserializer eventDeserializer = new EventDeserializer();
eventDeserializer.setCompatibilityMode(
EventDeserializer.CompatibilityMode.DATE_AND_TIME_AS_LONG,
EventDeserializer.CompatibilityMode.CHAR_AND_BINARY_AS_BYTE_ARRAY);
BinaryLogFileReader reader = new BinaryLogFileReader(binlogFile, eventDeserializer);
try {
for (Event event; (event = reader.readEvent()) != null;) {
EventData data = event.getData();
if (data instanceof WriteRowsEventData ed) {
List<Serializable[]> rows = ed.getRows();
rows.forEach(row -> {
for (Serializable s : row) {
if (s instanceof byte[] bs) {
System.err.print(new String(bs) + "\t");
} else {
System.err.print(s + "\t");
}
}
System.out.println();
});
} else if (data instanceof QueryEventData ed) {
System.out.printf("Query event: %s%n", ed.getSql());
} else if (data instanceof DeleteRowsEventData ed) {
System.err.println("Delete event");
} else if (data instanceof TableMapEventData ed) {
System.out.printf("Database: %s, Table: %s%n", ed.getDatabase(), ed.getTable());
}
}
} finally {
reader.close();
}
}</code>The program outputs events such as query start, table mapping, row inserts, updates, and deletions.
2. Real‑Time Binlog Listener
Implement a Spring component that connects to MySQL and registers an event listener to process changes as they occur:
<code>@Component
public class MySQLToRedisComponent implements CommandLineRunner {
public void listener() {
BinaryLogClient client = new BinaryLogClient("118.24.111.33", 3307, "test", "root", "123123");
EventDeserializer eventDeserializer = new EventDeserializer();
eventDeserializer.setCompatibilityMode(
EventDeserializer.CompatibilityMode.DATE_AND_TIME_AS_LONG,
EventDeserializer.CompatibilityMode.CHAR_AND_BINARY_AS_BYTE_ARRAY);
client.setEventDeserializer(eventDeserializer);
client.registerEventListener(event -> {
EventHeader header = event.getHeader();
switch (header.getEventType()) {
case EXT_WRITE_ROWS:
WriteRowsEventData writeData = event.getData();
for (Serializable[] row : writeData.getRows()) {
printRow(row);
}
break;
case EXT_UPDATE_ROWS:
UpdateRowsEventData updateData = event.getData();
System.err.printf("Updated columns: %s%n", updateData.getIncludedColumns());
for (Entry<Serializable[], Serializable[]> entry : updateData.getRows()) {
printRow(entry.getKey());
System.out.println(">>> before");
printRow(entry.getValue());
System.out.println(">>> after");
}
break;
case EXT_DELETE_ROWS:
DeleteRowsEventData deleteData = event.getData();
for (Serializable[] row : deleteData.getRows()) {
printRow(row);
}
break;
case TABLE_MAP:
TableMapEventData mapData = event.getData();
System.out.printf("Changed table: %s.%s%n", mapData.getDatabase(), mapData.getTable());
break;
default:
break;
}
});
client.connect();
}
private void printRow(Serializable[] row) {
for (Serializable s : row) {
if (s instanceof byte[] bs) {
System.out.print(new String(bs) + "\t");
} else {
System.out.print(s + "\t");
}
}
System.out.println();
}
@Override
public void run(String... args) throws Exception {
listener();
}
}</code>When data changes, the listener prints the affected table, columns, and row values.
3. Expose Binlog Client via JMX
Configure Spring beans to expose the client and its statistics through JMX:
<code>@Bean
BinaryLogClient client() {
return new BinaryLogClient("118.24.111.33", 3307, "test", "root", "123123");
}
@Bean
MBeanExporter exporterClient(BinaryLogClient client) {
MBeanExporter exporter = new MBeanExporter();
exporter.setBeans(Map.of("mysql.binlog:type=BinaryLogClient", client));
return exporter;
}
@Bean
MBeanExporter exporterClientStatistics(BinaryLogClient client) {
MBeanExporter exporter = new MBeanExporter();
BinaryLogClientStatistics stats = new BinaryLogClientStatistics(client);
exporter.setBeans(Map.of("mysql.binlog:type=BinaryLogClientStatistics", stats));
return exporter;
}</code>After starting the application, use JConsole to view the exposed MBeans.
The complete source code implements data‑change listening, conversion to objects, and writing to Redis. Feel free to leave a comment if you need the full implementation.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.