c语言sscanf函数的用法是什么
293
2022-11-30
Seata json decode exception, Cannot construct instance of `java.time.LocalDateTime` 报错原因/解决方案最全汇总版
文章目录
一、报错详情
1、环境信息2、Seata undo_log日志表结构3、详细异常信息
二、原因分析三、解决方案
方案1、降低mysql-connector-java版本方案2、更换Seata的undo_log序列化方式
1)Seata undo配置类2)自定义Seata undo_log序列化
方案3、将数据库字段类型从datetime修改为timestamp方案4、使Jackson可以解析`java.time.LocalDateTime`类型
一、报错详情
1、环境信息
Spring Boot : 2.4.2Spring Cloud:2020.0.1Spring Cloud Alibaba:2021.1Seata:1.3.0mysql-connector-java:8.0.28和报错相关的是Seata 和 mysql-connector-java的版本信息
2、Seata undo_log日志表结构
其中 log_created、log_modified字段的类型是datetime。
3、详细异常信息
在分布式全局事务执行失败进行全局回滚时,需要通过Seata 的 undoLog回滚的服务会出现报错信息,如下:
2022-08-05 18:04:03.583 ERROR 16225 --- [h_RMROLE_1_8_16] i.s.r.d.u.parser.JacksonUndoLogParser : json decode exception, Cannot construct instance of `java.time.LocalDateTime` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator) at [Source: (byte[])"{"@class":"io.seata.rm.datasource.undo.BranchUndoLog","xid":"192.168.1.5:8091:298880381343518720","branchId":298880382744416257,"sqlUndoLogs":["java.util.ArrayList",[{"@class":"io.seata.rm.datasource.undo.SQLUndoLog","sqlType":"UPDATE","tableName":"stock_tbl","beforeImage":{"@class":"io.seata.rm.datasource.sql.struct.TableRecords","tableName":"stock_tbl","rows":["java.util.ArrayList",[{"@class":"io.seata.rm.datasource.sql.struct.Row","fields":["java.util.ArrayList",[{"@class":"io.seata.rm.dataso"[truncated 12232 bytes]; line: 1, column: 3987] (through reference chain: io.seata.rm.datasource.undo.BranchUndoLog["sqlUndoLogs"]->java.util.ArrayList[1]->io.seata.rm.datasource.undo.SQLUndoLog["afterImage"]->io.seata.rm.datasource.sql.struct.TableRecords["rows"]->java.util.ArrayList[0]->io.seata.rm.datasource.sql.struct.Row["fields"]->java.util.ArrayList[6]->io.seata.rm.datasource.sql.struct.Field["value"])com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `java.time.LocalDateTime` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator) at [Source: (byte[])"{"@class":"io.seata.rm.datasource.undo.BranchUndoLog","xid":"192.168.1.5:8091:298880381343518720","branchId":298880382744416257,"sqlUndoLogs":["java.util.ArrayList",[{"@class":"io.seata.rm.datasource.undo.SQLUndoLog","sqlType":"UPDATE","tableName":"stock_tbl","beforeImage":{"@class":"io.seata.rm.datasource.sql.struct.TableRecords","tableName":"stock_tbl","rows":["java.util.ArrayList",[{"@class":"io.seata.rm.datasource.sql.struct.Row","fields":["java.util.ArrayList",[{"@class":"io.seata.rm.dataso"[truncated 12232 bytes]; line: 1, column: 3987] (through reference chain: io.seata.rm.datasource.undo.BranchUndoLog["sqlUndoLogs"]->java.util.ArrayList[1]->io.seata.rm.datasource.undo.SQLUndoLog["afterImage"]->io.seata.rm.datasource.sql.struct.TableRecords["rows"]->java.util.ArrayList[0]->io.seata.rm.datasource.sql.struct.Row["fields"]->java.util.ArrayList[6]->io.seata.rm.datasource.sql.struct.Field["value"]) at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1615) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1077) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1332) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:331) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:199) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:166) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedForId(AsPropertyTypeDeserializer.java:132) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:99) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromAny(AsPropertyTypeDeserializer.java:195) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer$Vanilla.deserializeWithType(UntypedObjectDeserializer.java:710) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:138) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:293) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:194) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:166) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedForId(AsPropertyTypeDeserializer.java:132) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:99) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeWithType(BeanDeserializerBase.java:1209) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:292) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:249) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:26) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._deserialize(AsArrayTypeDeserializer.java:120) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer.deserializeTypedFromArray(AsArrayTypeDeserializer.java:53) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserializeWithType(CollectionDeserializer.java:318) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:138) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:293) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:194) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:166) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedForId(AsPropertyTypeDeserializer.java:132) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:99) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeWithType(BeanDeserializerBase.java:1209) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:292) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:249) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:26) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._deserialize(AsArrayTypeDeserializer.java:120) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer.deserializeTypedFromArray(AsArrayTypeDeserializer.java:53) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserializeWithType(CollectionDeserializer.java:318) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:138) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:293) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:194) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:166) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedForId(AsPropertyTypeDeserializer.java:132) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:99) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeWithType(BeanDeserializerBase.java:1209) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:138) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:293) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:194) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:166) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedForId(AsPropertyTypeDeserializer.java:132) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:99) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeWithType(BeanDeserializerBase.java:1209) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:292) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:249) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:26) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._deserialize(AsArrayTypeDeserializer.java:120) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer.deserializeTypedFromArray(AsArrayTypeDeserializer.java:53) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserializeWithType(CollectionDeserializer.java:318) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:138) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:293) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:194) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:166) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedForId(AsPropertyTypeDeserializer.java:132) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:99) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeWithType(BeanDeserializerBase.java:1209) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:68) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4526) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3529) ~[jackson-databind-2.11.4.jar:2.11.4] at io.seata.rm.datasource.undo.parser.JacksonUndoLogParser.decode(JacksonUndoLogParser.java:139) ~[seata-all-1.3.0.jar:1.3.0] at io.seata.rm.datasource.undo.AbstractUndoLogManager.undo(AbstractUndoLogManager.java:276) [seata-all-1.3.0.jar:1.3.0] at io.seata.rm.datasource.DataSourceManager.branchRollback(DataSourceManager.java:178) [seata-all-1.3.0.jar:1.3.0] at io.seata.rm.AbstractRMHandler.doBranchRollback(AbstractRMHandler.java:125) [seata-all-1.3.0.jar:1.3.0] at io.seata.rm.AbstractRMHandler$2.execute(AbstractRMHandler.java:67) [seata-all-1.3.0.jar:1.3.0] at io.seata.rm.AbstractRMHandler$2.execute(AbstractRMHandler.java:63) [seata-all-1.3.0.jar:1.3.0] at io.seata.core.exception.AbstractExceptionHandler.exceptionHandleTemplate(AbstractExceptionHandler.java:116) [seata-all-1.3.0.jar:1.3.0] at io.seata.rm.AbstractRMHandler.handle(AbstractRMHandler.java:63) [seata-all-1.3.0.jar:1.3.0] at io.seata.rm.DefaultRMHandler.handle(DefaultRMHandler.java:63) [seata-all-1.3.0.jar:1.3.0] at io.seata.core.protocol.transaction.BranchRollbackRequest.handle(BranchRollbackRequest.java:35) [seata-all-1.3.0.jar:1.3.0] at io.seata.rm.AbstractRMHandler.onRequest(AbstractRMHandler.java:150) [seata-all-1.3.0.jar:1.3.0] at io.seata.core.rpc.processor.client.RmBranchRollbackProcessor.handleBranchRollback(RmBranchRollbackProcessor.java:63) [seata-all-1.3.0.jar:1.3.0] at io.seata.core.rpc.processor.client.RmBranchRollbackProcessor.process(RmBranchRollbackProcessor.java:58) [seata-all-1.3.0.jar:1.3.0] at io.seata.core.rpc.netty.AbstractNettyRemoting.lambda$processMessage$2(AbstractNettyRemoting.java:265) [seata-all-1.3.0.jar:1.3.0] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_275] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_275] at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-all-4.1.58.Final.jar:4.1.58.Final] at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_275]
二、原因分析
全局事务进行回滚时,会去查询undo_log 表中的回滚信息,回滚信息中记录了当前数据操作前后的镜像。
Seata 默认采用的序列化方式是 jackson,报错信息显示jackson 反序列化失败,我们定位到JacksonUndoLogParser类的decode()方法:
在数据库中,undio_log的时间字段 log_created和log_modified设置的是datetime 类型;
Seata 会自己去查询数据库字段的属性、值并缓存,在插入回滚信息时,将数据库的datetime 被解析为java.time.LocalDateTime。而Seata 在使用Jackson 序列化器时,没有对java.time.LocalDateTime类型序列化进行配置,导致报错。
三、解决方案
方案1、降低mysql-connector-java版本
调整mysql-connector-java版本 <= 8.0.22;
在该版本下,数据库的datetime 被解析为java.sql.Timestamp,因此也就不存在java.time.LocalDateTime无法反序列化的问题了。
这种方案最简单、快速,推荐;
方案2、更换Seata的undo_log序列化方式
seata支持以下几种序列化方式:
FastjsonUndoLogParser:Fastjson序列化工具FstUndoLogParser:Fst序列化工具(seata 1.4.x版本开始支持)JacksonUndoLogParser:Jackson序列化工具KryoUndoLogParser:Kryo序列化工具ProtostuffUndoLogParser:Protostuff序列化工具
有些序列化方式是不行的,实测结果如下:
仅有Protostuff、Kryo、Fst三种序列化方式是可行的;Fastjson 和Jackson均不支持;
此外,seata 1.5.x版本修复了 FastjsonUndoLogParser 中 LocalDataTime 类型无法回滚的问题,也就是说seata 1.5.x版本Fastjson序列化方式也是可行的。
1)Seata undo配置类
UndoProperties中包含四个配置项:
相关常量:
public static final String SEATA_PREFIX = "seata";public static final String CLIENT_PREFIX = SEATA_PREFIX + ".client";public static final String UNDO_PREFIX = CLIENT_PREFIX + ".undo";public static final boolean DEFAULT_TRANSACTION_UNDO_DATA_VALIDATION = true;// 默认采用jsckson序列化协议public static final String DEFAULT_TRANSACTION_UNDO_LOG_SERIALIZATION = "jackson";public static final String DEFAULT_TRANSACTION_UNDO_LOG_TABLE = "undo_log";public static final boolean DEFAULT_ONLY_CARE_UPDATE_COLUMNS = true;
2)自定义Seata undo_log序列化
修改log-serialization配置即可,默认使用的是jackson;如果需要修改为其他的,则需要在pom.xml中引入相关的序列化包依赖;一般不建议修改序列化方式,因为jackson是Sring Boot已集成的,无需再添加第三方包。
以protostuff序列化为例;
1> application.yml文件:
seata: client: undo: # 指定undo的序列化协议为protostuff log-serialization:
如果seata使用的是file配置方式,也可以选择直接在file.conf中修改:
client { undo { dataValidation = true logSerialization = "protostuff" logTable = "undo_log" }}
2> pom.xml中引入protostuff相关依赖包:
方案3、将数据库字段类型从datetime修改为timestamp
这种方式不推荐,尤其是对于正常业务表,如果业务已经上线,再修改数据类型就很难搞。
方案4、使Jackson可以解析java.time.LocalDateTime类型
从seata 1.4.2版本开始 ;JacksonUndoLogParser源码中增加了对LocalDateTime类的序列化和反序列化处理;
从代码逻辑来看,我们需要一个实现JacksonSerializer的类,其中负责处理LocalDateTime类型,具体操作步骤如下:
1> 自定义支持可以解析java.time.OffsetDateTime类型的解析类;例如:
public class JsonDateTimeSerializer implements JacksonSerializer
2>在 META-INF/services 目录中定义名称为io.seata.rm.datasource.undo.UndoLogParser的文件,内容为JacksonSerializer实现类的全路径名;
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~