Đăng ký và xử lý nhật ký MySQL trong Java có thể được thực hiện bằng nhiều cách khác nhau. Dưới đây là một số phương pháp phổ biến cùng với ví dụ mã nguồn.
- Sử dụng MySQL Binlog Connector để đăng ký nhật ký nhị phân (Binlog)
Đây là phương pháp phổ biến nhất, cho phép lấy thông tin thay đổi cơ sở dữ liệu theo thời gian thực.
Thêm phụ thuộc (Maven)
<dependency>
<groupId>com.github.shyiko</groupId>
<artifactId>mysql-binlog-connector-java</artifactId>
<version>0.25.3</version>
</dependency>
Ví dụ mã nguồn
import com.github.shyiko.mysql.binlog.BinaryLogClient;
import com.github.shyiko.mysql.binlog.event.Event;
import com.github.shyiko.mysql.binlog.event.EventType;
public class MySQLBinlogListener {
public static void main(String[] args) {
BinaryLogClient client = new BinaryLogClient(
"localhost", // Địa chỉ máy chủ MySQL
3306, // Cổng MySQL
"user", // Tên người dùng
"pass" // Mật khẩu
);
// Thiết lập ID máy chủ (phải duy nhất)
client.setServerId(987654);
// Đăng ký sự kiện
client.registerEventListener(event -> {
if (event.getEventType() == EventType.TABLE_MAP) {
System.out.println("Bảng được cập nhật.");
} else if (event.getEventType() == EventType.WRITE_ROWS) {
System.out.println("Dữ liệu mới đã được chèn.");
} else if (event.getEventType() == EventType.UPDATE_ROWS) {
System.out.println("Dữ liệu đã được cập nhật.");
} else if (event.getEventType() == EventType.DELETE_ROWS) {
System.out.println("Dữ liệu đã bị xóa.");
}
});
try {
client.connect();
} catch (Exception e) {
e.printStackTrace();
}
}
}
- Theo dõi nhật ký truy vấn bằng JDBC (Yêu cầu cấu hình MySQL)
Phương pháp này yêu cầu bật ghi lại các truy vấn chung trong MySQL.
Cấu hình MySQL (my.cnf/my.ini)
[mysqld]
general_log = 1
general_log_file = /var/log/mysql/general-query.log
Mã nguồn Java để lắng nghe thay đổi tệp nhật ký
import org.apache.commons.io.input.Tailer;
import org.apache.commons.io.input.TailerListenerAdapter;
public class MySQLQueryMonitor {
public static void main(String[] args) {
TailerListenerAdapter listener = new TailerListenerAdapter() {
@Override
public void handle(String line) {
System.out.println("Nhật ký mới: " + line);
}
};
File logFile = new File("/var/log/mysql/general-query.log");
Tailer tailer = new Tailer(logFile, listener, 1000, true);
Thread thread = new Thread(tailer);
thread.setDaemon(true);
thread.start();
try {
Thread.sleep(Long.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
- Sử dụng Canal để đăng ký MySQL Binlog (Giải pháp mã nguồn mở từ Alibaba)
Canal là một thành phần mã nguồn mở của Alibaba dựa trên việc phân tích nhật ký tăng dần của MySQL.
Thêm phụ thuộc
<dependency>
<groupId>com.alibaba.otter</groupId>
<artifactId>canal.client</artifactId>
<version>1.1.6</version>
</dependency>
Ví dụ mã nguồn
import com.alibaba.otter.canal.client.CanalConnector;
import com.alibaba.otter.canal.client.CanalConnectors;
import com.alibaba.otter.canal.protocol.Message;
import com.alibaba.otter.canal.protocol.CanalEntry.*;
public class CanalSubscriptionExample {
public static void main(String[] args) {
CanalConnector connector = CanalConnectors.newSingleConnector(
new InetSocketAddress("127.0.0.1", 11111),
"example", "", ""
);
try {
connector.connect();
connector.subscribe(".*\\..*");
connector.rollback();
while (true) {
Message message = connector.getWithoutAck(100);
long batchId = message.getId();
List<Entry> entries = message.getEntries();
if (batchId != -1 && !entries.isEmpty()) {
for (Entry entry : entries) {
if (entry.getEntryType() == EntryType.ROWDATA) {
RowChange rowChange = RowChange.parseFrom(entry.getStoreValue());
switch (rowChange.getEventType()) {
case INSERT:
System.out.println("Chèn: " + rowChange.getRowDatasList());
break;
case UPDATE:
System.out.println("Cập nhật: " + rowChange.getRowDatasList());
break;
case DELETE:
System.out.println("Xóa: " + rowChange.getRowDatasList());
break;
}
}
}
}
connector.ack(batchId);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
connector.disconnect();
}
}
}
Lưu ý quan trọng
- Yêu cầu quyền: Để đăng ký Binlog, tài khoản MySQL cần có quyền
REPLICATION SLAVEvàREPLICATION CLIENT.
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'user'@'%';
FLUSH PRIVILEGES;
- Cấu hình MySQL: Đảm bảo rằng Binlog được kích hoạt trong cấu hình MySQL.
[mysqld]
log-bin=mysql-bin
binlog-format=ROW
server_id=1
- Hiệu suất: Việc đăng ký nhật ký ở tần suất cao có thể ảnh hưởng đến hiệu suất cơ sở dữ liệu. Cần đánh giá kỹ lưỡng trong môi trường sản xuất.
- Xử lý mất kết nối: Trong ứng dụng thực tế, cần thêm cơ chế kết nối lại và xử lý lỗi.
Trong số các phương pháp trên, cách sử dụng MySQL Binlog Connector là phổ biến nhất và linh hoạt nhất, phù hợp với hầu hết các tình huống cần giám sát thay đổi MySQL theo thời gian thực.