canal客户端报错:Caused by: java.lang.NumberFormatException: empty String
canal
alibaba/canal: Canal 是由阿里巴巴开源的分布式数据库同步系统,主要用于实现MySQL数据库的日志解析和实时增量数据订阅与消费,广泛应用于数据库变更消息的捕获、数据迁移、缓存更新等场景。
项目地址:https://gitcode.com/gh_mirrors/ca/canal

·
使用canal客户端canal-spring-boot-starter数据库变更后报错,信息如下:
[2022-10-11 09:59:11,972] [ERROR] top.javatool.canal.client.handler.CanalThreadUncaughtExceptionHandler canal-execute-thread-17 - thread canal-execute-thread-17 have a exception
java.lang.RuntimeException: parse event has an error , data:header {
version: 1
logfileName: "mysql-bin.000001"
logfileOffset: 255665
serverId: 1
serverenCode: "UTF-8"
executeTime: 1665453551000
sourceType: MYSQL
schemaName: "gdnymall_test"
tableName: "trade_sale_order"
eventLength: 154
eventType: INSERT
props {
key: "rowsCount"
value: "1"
}
}
entryType: ROWDATA
storeValue: "\b\237\001\020\001P\000b\375\025\022,\b\000\020\373\377\377\377\377\377\377\377\377\001\032\002id \001(\0010\000B\a1053625R\nbigint(20)\022!\b\001\020\f\032\aaddress \000(\0010\001R\fvarchar(255)\022\036\b\002\020\f\032\004city \000(\0010\001R\fvarchar(255)\022!\b\003\020\f\032\acity_id \000(\0010\001R\fvarchar(255)\022;\b\004\020\373\377\377\377\377\377\377\377\377\001\032\vcreate_time \000(\0010\000B\r1665453551917R\nbigint(20)\022\"\b\005\020\f\032\bdistrict \000(\0010\001R\fvarchar(255)\022%\b\006\020\f\032\vdistrict_id \000(\0010\001R\fvarchar(255)\0225\b\a\020\f\032\border_no \000(\0010\000B\02149476705521242112R\fvarchar(255)\022$\b\b\020\004\032\vorder_state \000(\0010\000B\002-1R\aint(11)\022!\b\t\020\b\032\bpost_fee \000(\0010\000B\0030.0R\006double\022\"\b\n\020\f\032\bprovince \000(\0010\001R\fvarchar(255)\022%\b\v\020\f\032\vprovince_id \000(\0010\001R\fvarchar(255)\022.\b\f\020\373\377\377\377\377\377\377\377\377\001\032\tsource_id \000(\0010\000B\00212R\nbigint(20)\022\035\b\r\020\f\032\003tel \000(\0010\001R\fvarchar(255)\022(\b\016\020\f\032\016third_order_no \000(\0010\001R\fvarchar(255)\022+\b\017\020\f\032\021third_order_state \000(\0010\001R\fvarchar(255)\022)\b\020\020\b\032\020total_cost_price \000(\0010\000B\0031.9R\006double\022)\b\021\020\b\032\020total_sale_price \000(\0010\000B\0031.9R\006double\022\036\b\022\020\f\032\004town \000(\0010\001R\fvarchar(255)\022!\b\023\020\f\032\atown_id \000(\0010\001R\fvarchar(255)\022\'\b\024\020\f\032\rcancle_reason \000(\0010\001R\fvarchar(255)\022)\b\025\020\f\032\017express_company \000(\0010\001R\fvarchar(255)\022$\b\026\020\f\032\nexpress_no \000(\0010\001R\fvarchar(255)\022!\b\027\020\f\032\acard_no \000(\0010\001R\fvarchar(255)\022#\b\030\020\004\032\vsource_type \000(\0010\000B\0010R\aint(11)\022*\b\031\020\f\032\020c_third_order_no \000(\0010\001R\fvarchar(255)\022&\b\032\020\f\032\fexpress_code \000(\0010\001R\fvarchar(255)\022#\b\033\020\f\032\tconsignee \000(\0010\001R\fvarchar(255)\0226\b\034\020\373\377\377\377\377\377\377\377\377\001\032\rmain_order_id \000(\0010\000B\006670241R\nbigint(20)\022)\b\035\020\b\032\020total_real_price \000(\0010\000B\0031.9R\006double\022%\b\036\020\f\032\vfail_reason \000(\0010\001R\fvarchar(255)\022)\b\037\020\373\377\377\377\377\377\377\377\377\001\032\bpay_time \000(\0010\001R\nbigint(20)\022.\b \020\373\377\377\377\377\377\377\377\377\001\032\rdelivery_time \000(\0010\001R\nbigint(20)\022-\b!\020\373\377\377\377\377\377\377\377\377\001\032\freceive_time \000(\0010\001R\nbigint(20)\022%\b\"\020\f\032\006remark \000(\0010\000B\003cesR\fvarchar(255)\022-\b#\020\f\032\023sale_service_remark \000(\0010\001R\fvarchar(255)\022;\b$\020\373\377\377\377\377\377\377\377\377\001\032\vupdate_time \000(\0010\000B\r1665453551929R\nbigint(20)\022)\b%\020\f\032\020express_customer \000(\0010\001R\vvarchar(56)\022)\b&\020\f\032\017delivery_remark \000(\0010\001R\fvarchar(255)\022+\b\'\020\004\032\026logistics_query_status \000(\0010\001R\aint(11)\022-\b(\020\373\377\377\377\377\377\377\377\377\001\032\fconfirm_time \000(\0010\001R\nbigint(20)\022/\b)\020\373\377\377\377\377\377\377\377\377\001\032\016shipments_time \000(\0010\001R\nbigint(20)\022#\b*\020\f\032\torigin_id \000(\0010\001R\fvarchar(255)\022+\b+\020\f\032\021activity_batch_no \000(\0010\001R\fvarchar(100)\022/\b,\020\373\377\377\377\377\377\377\377\377\001\032\016u8_in_order_id \000(\0010\001R\nbigint(20)\022\'\b-\020\f\032\016u8_in_order_no \000(\0010\001R\vvarchar(50)\0223\b.\020\372\377\377\377\377\377\377\377\377\001\032\022u8_in_order_status \000(\0010\001R\ntinyint(4)\0221\b/\020\373\377\377\377\377\377\377\377\377\001\032\020u8_in_order_time \000(\0010\001R\nbigint(20)\022/\b0\020\373\377\377\377\377\377\377\377\377\001\032\016u8_ex_order_id \000(\0010\001R\nbigint(20)\022\'\b1\020\f\032\016u8_ex_order_no \000(\0010\001R\vvarchar(50)\0223\b2\020\372\377\377\377\377\377\377\377\377\001\032\022u8_ex_order_status \000(\0010\001R\ntinyint(4)\0221\b3\020\373\377\377\377\377\377\377\377\377\001\032\020u8_ex_order_time \000(\0010\001R\nbigint(20)\022,\b4\020\b\032\022total_price_person \000(\0010\001R\fdouble(10,2)\022-\b5\020\b\032\023total_price_company \000(\0010\001R\fdouble(10,2)\022*\b6\020\b\032\020total_price_cash \000(\0010\001R\fdouble(10,2)\022&\b7\020\371\377\377\377\377\377\377\377\377\001\032\tjd_cancel \000(\0010\001R\006bit(1)\022+\b8\020\f\032\021supplier_order_no \000(\0010\001R\fvarchar(100)\0221\b9\020\b\032\027payment_discount_amount \000(\0010\001R\fdouble(10,2)\0225\b:\020\f\032\034payment_discount_activity_id \000(\0010\001R\vvarchar(80)\0228\b;\020\f\032\036payment_discount_activity_name \000(\0010\001R\fvarchar(150)\0228\b<\020\b\032\036payment_discount_refund_amount \000(\0010\001R\fdouble(10,2)\022+\b=\020\372\377\377\377\377\377\377\377\377\001\032\norder_type \000(\0010\001R\ntinyint(4)\022%\b>\020\f\032\vpostal_code \000(\0010\001R\fvarchar(255)\022*\b?\020\373\377\377\377\377\377\377\377\377\001\032\tsign_time \000(\0010\001R\nbigint(20)"
at top.javatool.canal.client.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:52)
at top.javatool.canal.client.handler.impl.AsyncMessageHandlerImpl.lambda$handleMessage$0(AsyncMessageHandlerImpl.java:30)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NumberFormatException: empty String
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1842)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at top.javatool.canal.client.util.StringConvertUtil.convertType(StringConvertUtil.java:31)
at top.javatool.canal.client.util.FieldUtil.setFieldValue(FieldUtil.java:17)
at top.javatool.canal.client.factory.EntryColumnModelFactory.newInstance(EntryColumnModelFactory.java:71)
at top.javatool.canal.client.factory.EntryColumnModelFactory.newInstance(EntryColumnModelFactory.java:33)
at top.javatool.canal.client.factory.EntryColumnModelFactory.newInstance(EntryColumnModelFactory.java:21)
at top.javatool.canal.client.handler.impl.RowDataHandlerImpl.handlerRowData(RowDataHandlerImpl.java:34)
at top.javatool.canal.client.handler.impl.RowDataHandlerImpl.handlerRowData(RowDataHandlerImpl.java:16)
at top.javatool.canal.client.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:48)
... 4 common frames omitted
问题排查:
经过canal客户端源码排查,发现是变更数据项的某个字段在数据库表中为空字符串,并且字段类型为Double,当执行 Double.parseDouble(columnValue)时报转换类型异常。
package top.javatool.canal.client.util;
import java.lang.reflect.Field;
public class FieldUtil {
public FieldUtil() {
}
public static void setFieldValue(Object object, String fieldName, String value) throws NoSuchFieldException, IllegalAccessException {
Field field;
try {
field = object.getClass().getDeclaredField(fieldName);
} catch (NoSuchFieldException var6) {
field = object.getClass().getSuperclass().getDeclaredField(fieldName);
}
field.setAccessible(true);
Class<?> type = field.getType();
//value字段为空字符串,并且字段类型为double
Object result = StringConvertUtil.convertType(type, value);
field.set(object, result);
}
}
StringConvertUtil.convertType部分源码:
static Object convertType(Class<?> type, String columnValue) {
if (columnValue == null) {
return null;
} else if (type.equals(Integer.class)) {
return Integer.parseInt(columnValue);
} else if (type.equals(Long.class)) {
return Long.parseLong(columnValue);
} else if (type.equals(Boolean.class)) {
return convertToBoolean(columnValue);
} else if (type.equals(BigDecimal.class)) {
return new BigDecimal(columnValue);
} else if (type.equals(Double.class)) {
return Double.parseDouble(columnValue);
} else if (type.equals(Float.class)) {
return Float.parseFloat(columnValue);
} else if (type.equals(Date.class)) {
return parseDate(columnValue);
} else {
return type.equals(java.sql.Date.class) ? parseDate(columnValue) : columnValue;
}
}
解决思路:
将改字段的接收实体对应空的字段从Double改为String类型,后续再自己转换。




alibaba/canal: Canal 是由阿里巴巴开源的分布式数据库同步系统,主要用于实现MySQL数据库的日志解析和实时增量数据订阅与消费,广泛应用于数据库变更消息的捕获、数据迁移、缓存更新等场景。
最近提交(Master分支:23 天前 )
af937544 - 1 个月前
9f2fc740 - 1 个月前
更多推荐
所有评论(0)