解决方法在最下面,可以直接跳过前面解析部分。
具体错误日志如下:
org.quartz.JobPersistenceException: Couldn't store trigger 'Axxxx' for 'Bxxxx' job:Couldn't retrieve job because the BLOB couldn't be deserialized: com.demo.TaskClass; local class incompatible: stream classdesc serialVersionUID = 4545949010006210417, local class serialVersionUID = -7472559171496155799
at org.quartz.impl.jdbcjobstore.JobStoreSupport.storeTrigger(JobStoreSupport.java:1228)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.doUpdateOfMisfiredTrigger(JobStoreSupport.java:1042)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.recoverMisfiredJobs(JobStoreSupport.java:991)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.doRecoverMisfires(JobStoreSupport.java:3264)
at org.quartz.impl.jdbcjobstore.JobStoreSupport$MisfireHandler.manage(JobStoreSupport.java:4012)
at org.quartz.impl.jdbcjobstore.JobStoreSupport$MisfireHandler.run(JobStoreSupport.java:4033)
Caused by: org.quartz.JobPersistenceException: Couldn't retrieve job because the BLOB couldn't be deserialized: com.demo.TaskClass; local class incompatible: stream classdesc serialVersionUID = 4545949010006210417, local class serialVersionUID = -7472559171496155799
at org.quartz.impl.jdbcjobstore.JobStoreSupport.retrieveJob(JobStoreSupport.java:1397)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.storeTrigger(JobStoreSupport.java:1210)
... 5 common frames omitted
Caused by: java.io.InvalidClassException: com.demo.TaskClass; local class incompatible: stream classdesc serialVersionUID = 4545949010006210417, local class serialVersionUID = -7472559171496155799
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:699)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:2003)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1850)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2160)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1667)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:503)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:461)
at java.util.HashSet.readObject(HashSet.java:341)
at sun.reflect.GeneratedMethodAccessor1011.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1184)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2296)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2187)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1667)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2405)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2329)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2187)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1667)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:503)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:461)
at java.util.HashMap.readObject(HashMap.java:1412)
at sun.reflect.GeneratedMethodAccessor486.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1184)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2296)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2187)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1667)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2405)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2329)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2187)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1667)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:503)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:461)
at org.quartz.impl.jdbcjobstore.StdJDBCDelegate.getObjectFromBlob(StdJDBCDelegate.java:3201)
at org.quartz.impl.jdbcjobstore.StdJDBCDelegate.selectJobDetail(StdJDBCDelegate.java:860)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.retrieveJob(JobStoreSupport.java:1390)
... 6 common frames omitted
1、这个错误真的把我搞得头疼,一开始不太明白错误的点在哪,一直在搜索"Couldn't retrieve job because the BLOB couldn't be deserialized"这个关键错误,网上有关于这个错误的解决方案,可以参考https://www.yepk.cn/archives/quartz-error.html
2、经过方案的查阅也了解到了是由于任务实体类com.demo.TaskClass被改了,导致了定时器不认识这个类之前的样子了
3、主要错误日志其实是这里:local class incompatible: stream classdesc serialVersionUID = 12345, local class serialVersionUID = 6789。错误复现步骤,一开始创建一个A定时任务,定时任务正常工作,然后改一下实体类TaskClass的数据结构,比如加个属性,启动服务后就会报这个错,这是因为没有自定义序列化serialVersionUID。
4、创建定时任务实体类要实现Serizlizable接口,这时候启动服务这个类会被分配一个序列化ID也就是serialVersionUID,如果没有自定义序列化ID,那么系统就会给这个类自动生成一个序列化ID,这个序列化ID是根据这个类的hash值生成的,所以修改实体类数据结构后,hash值会变,序列化ID也就变了,就像第三个步骤里由12345变成了6789,导致了定时器去反序列化的时候会去找6789,但是找到了老任务A时,A的序列化ID是12345,定时器就不认识了,就没办法反序列化,就会报错。
5、解决方案:给实体类自定义序列化ID为老的12345即可。
6、代码展示:
//实体类 此时序列化ID是12345
public class TaskClass implements Serializable {
private String name;
}
//修改实体类数据结构 此时序列化ID会变成6789
public class TaskClass implements Serializable {
private String name;
private String age;
}
//解决方法 自定义序列化ID为12345,这时这个类的序列化ID就不会因为改变结构而变化了 因为被写死了
public class TaskClass implements Serializable {
private static final long serialVersionUID = 12345L;
private String name;
private String age;
}
7、关于序列化ID自动生成,因为我们一般也不会自己去定义序列化ID,毕竟自己可能会定义到一个重复的,IDEA有自动生成序列化ID的快捷方式,保证会根据类的HASH值生成序列化ID,这样就不会重复了,操作步骤如下:
进入IDEA->File->setting->Editor->inspections,然后搜索serialVersionUID,勾选以下两个选项,然后Apply
光标放在类名下面,按Alt+Enter 创建UID即可