Canal监控Mysql同步到Redis(菜鸟也能搭建)
首先要Canal服务端下载:链接: https://pan.baidu.com/s/1FwEnqPC1mwNXKRwJuMiLdg 密码: r8xf
连接数据库的时候需要给予连接数据库权限:在my.ini配置文件里加上 log-bin=mysql-bin 这个就行了
连接数据库的账号需要授权
CREATE USER cqlpz IDENTIFIED BY 'cqlpz';
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'cqlpz'@'%';
FLUSH PRIVILEGES; 创建一个账号并给予权限
解压出来有4个目录
2.conf 里面canal.properties 配置canal自己的 比如多个服务连接,canal缓存名称
这是example里面的内容;
两个properties就是配置自己的数据库连接,meta.dat相当于启动canal服务过后的额缓存信息
3.lib 就是canal需要的jar
4.logs 日志文件
maven引入jar
1 <dependency> 2 <groupId>com.alibaba.otter</groupId> 3 <artifactId>canal.client</artifactId> 4 <version>1.0.25</version> 5 </dependency> 6 <dependency> 7 <groupId>redis.clients</groupId> 8 <artifactId>jedis</artifactId> 9 <version>2.9.0</version> 10 </dependency>
java代码
1.连接canal服务
// 创建链接
CanalConnector connector = CanalConnectors.newSingleConnector(
new InetSocketAddress(AddressUtils.getHostIp(), 端口),
"canal名称(虚拟数据名)",
"数据库账号",
"数据库密码");
2.连接某个数据库
connector.connect();
connector.subscribe("监控的数据库\\..*");
connector.rollback();
3.获取操作的事件
Message message = connector.getWithoutAck(数量); // 获取指定数量的数据
List<Entry> entrys=message.getEntries();
for (Entry entry : entrys) {
if (entry.getEntryType() == EntryType.TRANSACTIONBEGIN ||entry.getEntryType() == EntryType.TRANSACTIONEND) {
continue;
}
RowChange rowChage = null;
try {
rowChage = RowChange.parseFrom(entry.getStoreValue());
} catch (InvalidProtocolBufferException e) {
System.out.println("获取数据失败:"+e.getMessage());
}
EventType eventType = rowChage.getEventType();
for (RowData rowData : rowChage.getRowDatasList()) {
if (eventType.equals(EventType.DELETE)) {
rowData.getBeforeColumnsList();//删除的所有数据
} else if (eventType.equals(EventType.INSERT)) {
rowData.getAfterColumnsList();//添加的所有数据
}else if(eventType.equals(EventType.UPDATE)) {
rowData.getAfterColumnsList();//修改的所有数据
}
}
完整的java类
public class ClientSample { private static Logger logger = LoggerFactory.getLogger(ClientSample.class); public void startCanalThread(){ Thread thread = new StartCanalThread(); thread.start(); } /** * canal 线程 */ public class StartCanalThread extends Thread { @Override public void run() { // 创建链接 CanalConnector connector = CanalConnectors.newSingleConnector(new InetSocketAddress("localhost", 11111), "longpizi", "longpizi", "cqlongpizi"); connector.connect(); connector.subscribe("test\\..*"); connector.rollback(); try { while (true) { // 获取指定数量的数据 Message message = connector.getWithoutAck(1000); long batchId = message.getId(); if (batchId != -1 && message.getEntries().size() > 0) { printEntry(message.getEntries()); } connector.ack(batchId); // 提交确认 Thread.sleep(2000); } }catch (Exception e){ logger.error("Canal线程异常,已终止:"+e.getMessage()); } finally { //中断Canal连接 connector.disconnect(); } } } /** * 数据库执行的操作 * @param entrys */ private static void printEntry( List<Entry> entrys) { for (Entry entry : entrys) { //操作事物 忽略 if (entry.getEntryType() == EntryType.TRANSACTIONBEGIN || entry.getEntryType() == EntryType.TRANSACTIONEND) { continue; } RowChange rowChage = null;//执行事件信息 String database=null;//执行的数据库 String table=null;//执行的表 try { database=entry.getHeader().getSchemaName(); table=entry.getHeader().getTableName(); rowChage = RowChange.parseFrom(entry.getStoreValue()); } catch (InvalidProtocolBufferException e) { logger.error("获取数据失败:"+e.getMessage()); } //获取执行的事件 EventType eventType = rowChage.getEventType(); for (RowData rowData : rowChage.getRowDatasList()) { //删除操作 if (eventType.equals(EventType.DELETE)) { redisDelete(rowData.getBeforeColumnsList(),database,table); } //添加操作 else if (eventType.equals(EventType.INSERT)) { redisInsert(rowData.getAfterColumnsList(),database,table); } //修改操作 else if(eventType.equals(EventType.UPDATE)) { redisUpdate(rowData.getAfterColumnsList(),database,table); } //修改表结构 else if(eventType.equals(EventType.ALTER)){ logger.info("修改表结构"); } } } } /** * 数据库执行了添加操作 * @param columns * @param database * @param table */ private static void redisInsert( List<Column> columns,String database,String table){ JSONObject json=new JSONObject(); for (Column column : columns) { json.put(column.getName(), column.getValue()); } System.out.println("数据库:"+database+"==>表:"+table+"==>添加数据:"+JSON.toJSONString(json)); } /** * 数据库执行了修改操作 * @param columns * @param database * @param table */ private static void redisUpdate( List<Column> columns,String database,String table){ JSONObject json=new JSONObject(); for (Column column : columns) { json.put(column.getName(), column.getValue()); } System.out.println("数据库:"+database+"==>表:"+table+"==>修改数据:"+JSON.toJSONString(json)); } /** * 数据库执行了删除操作 * @param columns * @param database * @param table */ private static void redisDelete( List<Column> columns,String database,String table){ JSONObject json=new JSONObject(); for (Column column : columns) { json.put(column.getName(), column.getValue()); } System.out.println("数据库:"+database+"==>表:"+table+"==>删除数据:"+JSON.toJSONString(json)); } }
这样就可把操作的数据更新到redis里面了