安装
1、新建.net core 6.0 控制台项目
2、引入CanalSharp包
3、开始编写代码
- 初始化日志,引入包Microsoft.Extensions.Logging.Console
var loggerFactory = LoggerFactory.Create(builder =>
{
builder
.AddFilter("Microsoft", LogLevel.Debug)
.AddFilter("System", LogLevel.Information)
.AddConsole();
});
var logger = loggerFactory.CreateLogger<SimpleCanalConnection>();
- 创建连接
var conn=new SimpleCanalConnection(new SimpleCanalOptions("127.0.0.1",11111,"1234"),logger);
//连接到 Canal Server
await conn.ConnectAsync();
//订阅
await conn.SubscribeAsync();
- 获取数据
var msg = await conn.GetAsync(1024);
- 解析数据
- Entry
conn.GetAsync()
返回的是一个 Entry 集合,Entry 对应 binlog 记录,它可能是事务标记也有可能是行数据变化,通过 Entry.EntryType 来区分,一般事务的标记在业务消费处理时不需要处理。
示例:
var entries = await conn.GetAsync(1024);
foreach (var entry in entries)
{
//不处理事务标记
if (entry.EntryType == EntryType.Transactionbegin || entry.EntryType == EntryType.Transactionend)
{
continue;
}
}
Entry.Header 包含了一些binlog以及数据库信息
属性 | 说明 |
---|---|
Entry.Header.LogfileName | binlog 文件名 |
Entry.Header.LogfileOffset | binlog 偏移 |
Entry.Header.SchemaName | mysql schema 名称 |
Entry.Header.TableName | 表名 |
- RowChange
一般在业务处理中,都会需要行数据的变更,将 Entry 转换为 RowChange对象
示例:
RowChange rowChange = null;
try
{
rowChange = RowChange.Parser.ParseFrom(entry.StoreValue);
}
catch (Exception e)
{
_logger.LogError(e);
}
通过 RowChange.EventType
来Row是什么变化,Update、Delete和 Insert 对应 sql 中的 update、delete 和 insert 语句
通过 RowChange.RowDatas
属性,来访问 RowChange 对象中包含的行变化数据集合。
示例,遍历 RowChange 中的行数据:
foreach (var rowData in rowChange.RowDatas)
{
//删除的数据
if (eventType == EventType.Delete)
{
PrintColumn(rowData.BeforeColumns.ToList());
}
//插入的数据
else if (eventType == EventType.Insert)
{
PrintColumn(rowData.AfterColumns.ToList());
}
//更新的数据
else
{
_logger.LogInformation("-------> before");
PrintColumn(rowData.BeforeColumns.ToList());
_logger.LogInformation("-------> after");
PrintColumn(rowData.AfterColumns.ToList());
}
}
private static void PrintColumn(List<Column> columns)
{
foreach (var column in columns)
{
Console.WriteLine($"{column.Name} : {column.Value} update= {column.Updated}");
}
}
- Column
Column 如其名,代表数据库中表的每一列的信息。
属性名 | 说明 |
---|---|
Column.Name | 列名 |
Column.Value | 列的值 |
Column.Updated | 列是否被更新 |
如执行 sql update user set Name='Allen'
,那么获取到的数据变更则有
Column.Name = 'Name';
Column.Value = 'Allen';
Column.Value = True
- 应答机制
应答机制可以保证消费数据的准确性,Canal 服务端会记录 Client 消费的进度,需要客户端发送 ACK 消息,服务端才会更新进度。类似于在消息队列中的 ACK 机制,如 RabbitMQ。
- 自动应答
await conn.GetAsync(1024);//获取数据并自动应答
- 手动应答
var msg = await conn.GetWithoutAckAsync(1024);//获取数据
await conn.AckAsync(msg.Id);//手动应答
await conn.RollbackAsync(msg.Id);//回滚
4、启动客户端
新建数据库test,和添加表t1,并添加一条记录,就会收到canal服务器传过来的数据
客户端完整代码如下:
using CanalSharp.Connections;
using CanalSharp.Protocol;
using Microsoft.Extensions.Logging;
using System;
namespace CanalClientDemo
{
internal class Program
{
static async Task Main(string[] args)
{
//1.初始化日志
var loggerFactory = LoggerFactory.Create(builder =>
{
builder
.AddFilter("Microsoft", LogLevel.Debug)
.AddFilter("System", LogLevel.Information)
.AddConsole();
});
var logger = loggerFactory.CreateLogger<SimpleCanalConnection>();
//2.创建连接
var conn = new SimpleCanalConnection(new SimpleCanalOptions("127.0.0.1", 11111, "1234"), logger);
//连接到 Canal Server
await conn.ConnectAsync();
//订阅
await conn.SubscribeAsync();
//3.获取数据
while (true)
{
var msg = await conn.GetAsync(1024);
if (msg.Entries.Count <= 0)
{
Thread.Sleep(1000);
continue;
}
foreach (var entry in msg.Entries)
{
//不处理事务标记
if (entry.EntryType == EntryType.Transactionbegin || entry.EntryType == EntryType.Transactionend)
{
continue;
}
RowChange rowChange = RowChange.Parser.ParseFrom(entry.StoreValue);
foreach (var rowData in rowChange.RowDatas)
{
}
}
}
}
}
}