项目用到了阿里云的数据传输服务DTS,主要是数据监听。
参考文档:https://help.aliyun.com/document_detail/26647.html?spm=a2c4g.11186623.2.19.100e6099zLpsGv
用了一段时间,也踩了一些坑,现在做个总结。
数据过滤
DTS读取的是数据库的binlog文件,每秒一次,获取到的数据量是非常庞大的,但是这些数据并不都是我们需要的,尤其是心跳数据,如果不过滤的话,日志文件很快就爆炸。
过滤的方式很简单,只要增加一个判断语句即可。
"INSERT".equals(message.getRecord().getOpt().toString())
DTS的sdk提供为我们提供了以下过滤选项:
INSERT、UPDATE、DELETE、REPLACE、HEARTBEAT、CONSISTENCY_TEST、BEGIN、COMMIT、DDL、ROLLBACK、DML、UNKNOWN;
汉字编码
数据库设计的编码格式是utf8mb4,但是sdk默认数据的是utf8格式,输出的汉字乱码,需要转换。
for (DataMessage.Record.Field field:fieldList) {
String record = field.encoding;
String vlaue = "";
if (record.equals("utf8mb4")){
vlaue= field.getValue().toString("utf8mb4");
}else if (record.equals("utf8")){
vlaue= field.getValue().toString("utf8");
}else {
vlaue= field.getValue().toString();
}
String type = field.getType().toString();
String name = field.getFieldname();
System.out.println("===========字段名:"+name+",字段类型:"+type+",字段编码:"+record+",字段数据:"+vlaue);
}
数据重复
DTS智能保证监听到的数据不丢失,但是不能保证不重复,需要自己进行判断。
每次消费数据后都保存消费位点数据。
String checkPoint = message.getRecord().getCheckpoint();
消费新的数据前与之前的消费位点进行比对。
public boolean equleCheckPoint(String checkPointOld,String checkPointYoung){
//先比较文件后缀,同一个binlog文件的话再比较位点位置
String[] checkPointOlds = checkPointOld.split("@");
String[] checkPointYoungs = checkPointYoung.split("@");
if (checkPointOlds[1].compareTo(checkPointYoungs[1])<=0){
if (checkPointOlds[0].compareTo(checkPointYoungs[0])<0){
return true;
}
}
return false;
}
日期格式
dts获取的所有数据都是String格式的,这也能理解,但是最不能理解的是它会把数据库中“2019-12-19”的数据输出为“2019:12:19”,非人哉。
String dateString = "2019:12:19";
String timeString = "10:55:12";
String dateTimeString = "2019-12-19 10:55:12";
String timeStampString = "1576726159654";
//Date格式
SimpleDateFormat dateSdf = new SimpleDateFormat("yyyy-MM-dd");
dateString.replace(":", "-");
try {
Date date = dateSdf.parse(dateString);
} catch (Exception e) {
System.out.println("date格式转化失败");
}
//Time
Time time = Time.valueOf(timeString);
//DateTime
try {
Long timestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateTimeString).getTime();
} catch (Exception e) {
e.printStackTrace();
}
//TimeStamp
Timestamp timestamp = new Timestamp(Long.valueOf(timeStampString));
完整代码
public void incremental() {
studentMapper.deleteData2();
try {
logger.info("<=====================查询数据开始=============================>");
/* 创建一个context */
RegionContext context;
context = new RegionContext();
context.setUsePublicIp(true);
context.setAccessKey(myak);
context.setSecret(mysk);
final ClusterClient client = new DefaultClusterClient(context);
ClusterListener listener = new ClusterListener() {
@Override
public void notify(List<ClusterMessage> messages) throws Exception {
for (ClusterMessage message : messages) {
try {
//如果是INSERT类型的操作则获取监听到的数据
if ("INSERT".equals(message.getRecord().getOpt().toString())) {
//循环出一条sql中所有的字段信息
List<DataMessage.Record.Field> fieldList = message.getRecord().getFieldList();
/**
* DTS返回的所有数据格式都是字符串形式的,如下数据在mysql中分别是Date,Time,DateTime,TimeStamp
*
* String dateString = "2019:12:19";
* String timeString = "10:55:12";
* String dateTimeString = "2019-12-19 10:55:12";
* String timeStampString = "1576726159654";
*
*/
String dataStr = fieldList.get(1).getValue().toString();
String timeStr = fieldList.get(2).getValue().toString();
String dateTimeStr = fieldList.get(3).getValue().toString();
String timeStampStr = fieldList.get(4).getValue().toString();
DateTimeEntity dateTimeEntity = new DateTimeEntity();
//Date格式
SimpleDateFormat dateSdf = new SimpleDateFormat("yyyy-MM-dd");
dataStr.replace(":", "-");
Date date;
try {
date = dateSdf.parse(dataStr);
dateTimeEntity.setMydate(date);
} catch (Exception e) {
System.out.println("date格式转化失败");
}
//Time
dateTimeEntity.setMytime(Time.valueOf(timeStr));
//DateTime
Long timestamp = null;
try {
timestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateTimeStr).getTime();
} catch (Exception e) {
e.printStackTrace();
}
dateTimeEntity.setMydatetime(new Timestamp(timestamp));
//TimeStamp
dateTimeEntity.setMytimestamp(new Timestamp(Long.valueOf(timeStampStr)));
studentMapper.insertDataLocla(dateTimeEntity);
/**
* 数据库如果设计的是utf8mb4格式,默认输出的汉字会乱码,需要转换
*
* */
for (DataMessage.Record.Field field:fieldList) {
String record = field.encoding;
String vlaue = "";
if (record.equals("utf8mb4")){
vlaue= field.getValue().toString("utf8mb4");
}else if (record.equals("utf8")){
vlaue= field.getValue().toString("utf8");
}else {
vlaue= field.getValue().toString();
}
String type = field.getType().toString();
String name = field.getFieldname();
System.out.println("===========字段名:"+name+",字段类型:"+type+",字段编码:"+record+",字段数据:"+vlaue);
}
} else {
System.out.println("》》》》》》》》》》》》》》》》》》没有数据变化");
}
/**
* 每条数据消费结束后必须给dts返回一个响应,此处指的是List<ClusterMessage> 中的所有message,而不能只限于自己需要的数据,否在消息堆积到4096条数据则sdk消费失败
* */
message.ackAsConsumed();
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
}
@Override
public void noException(Exception e) {
logger.warn("", e);
}
};
/* 设置监听者 */
client.addConcurrentListener(listener);
/* 设置请求的guid */
client.askForGUID(mysubID);
/* 启动后台线程 */
client.start();
} catch (Exception e) {
logger.info("<===========================查询失败==================================>");
e.printStackTrace();
}
}