You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring JPA出现could not deserialize反序列化错误(EOFException)求助

问题:Spring JPA原生查询反序列化失败(org.springframework.orm.jpa.JpaSystemException: could not deserialize)

在Spring JPA开发中,调用TeamRepo的自定义原生查询方法(如getAll、findTeam)时,抛出org.springframework.orm.jpa.JpaSystemException: could not deserialize异常,根因为java.io.EOFException。

实体类代码

@Entity
@Table(name = "report_queue")
public class Team implements Serializable {   
    @Id
    private Long id;
    private String queue;
    private Number offered;
    private Number answered;
    private Number answerRate;
    @Column(name="abandoned")
    private Number abandoned;
    private Number unmanaged;
    private String avgAbandonTime;
    @Temporal(TemporalType.TIMESTAMP)
    private Date totalTalkTime;
    private Number avgTalkTime;

    public Team() {
        String queue;
        Number offered;
        Number answered;
        Number answerRate;
        Number abandoned;
        Number unmanaged;
        String avgAbandonTime;
        Date totalTalkTime;
        Number avgTalkTime;
    }

    public Team(Long id, String queue, Number answered, Number offered, Number answerRate, Number abandoned, String avgAbandonTime, Date totalTalkTime, Number avgTalkTime, Number unmanaged) {
       this.id = id;
       this.queue = queue;
       this.answered = answered;
       this.offered = offered;
       this.answerRate = answerRate;
       this.abandoned = abandoned;
       this.avgAbandonTime = avgAbandonTime;
       this.totalTalkTime = totalTalkTime;
       this.avgTalkTime =  avgTalkTime;
       this.unmanaged=unmanaged;
   }
   // getters and setters..
}

Repository代码

public interface TeamRepo extends JpaRepository<Team, Long>{

    @Query(value="select q.id, q.queue,q.offered,q.answered,q.answerRate,q.abandoned,q.unmanaged,q.totalTalkTime,q.avgTalkTime,q.avgAbandonTime from(SELECT id as \"id\", queue AS \"queue\", COUNT(DISTINCT uniqueid) AS \"offered\", SUM(queuecallercomplete) AS \"answered\", ROUND(SUM(queuecallercomplete)/COUNT(DISTINCT uniqueid)*100,1) AS \"answerRate\", SUM(queuecallerabandon) AS \"abandoned\", SUM(queuecallerexit) AS \"unmanaged\", SUM(UNIX_TIMESTAMP(queuecallercompleteAt)-UNIX_TIMESTAMP(queuecallerleaveAt)) AS \"totalTalkTime\", ROUND(AVG(UNIX_TIMESTAMP(queuecallercompleteAt)-UNIX_TIMESTAMP(queuecallerleaveAt))) AS \"avgTalkTime\", ROUND(AVG(UNIX_TIMESTAMP(queuecallerAbandonAt)-UNIX_TIMESTAMP(queuecallerjoinAt))) AS \"avgAbandonTime\" FROM report_queue  GROUP BY queue)q",nativeQuery = true)
    List<Team> getAll();

    @Query(value="SELECT id as \"id\", queue AS \"queue\", COUNT(DISTINCT uniqueid) AS \"offered\", SUM(queuecallercomplete) AS \"answered\", ROUND(SUM(queuecallercomplete)/COUNT(DISTINCT uniqueid)*100,1) AS \"answerRate\", SUM(queuecallerabandon) AS \"abandoned\", SUM(queuecallerexit) AS \"unmanaged\", SUM(UNI X_TIMESTAMP(queuecallercompleteAt)-UNIX_TIMESTAMP(queuecallerleaveAt)) AS \"totalTalkTime\", ROUND(AVG(UNIX_TIMESTAMP(queuecallercompleteAt)-UNIX_TIMESTAMP(queuecallerleaveAt))) AS \"avgTalkTime\", ROUND(AVG(UNIX_TIMESTAMP(queuecallerAbandonAt)-UNIX_TIMESTAMP(queuecallerjoinAt))) AS \"avgAbandonTime\" FROM report_queue where  GROUP BY queue",nativeQuery = true)
    public List<Team> findTeam();

    void deleteTeamById(Long id);

    Optional<Team> findTeamById(Long id);
}

错误栈信息

ERROR 87656 --- [nio-8090-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.orm.jpa.JpaSystemException: could not deserialize; nested exception is org.hibernate.type.SerializationException: could not deserialize] with root cause
java.io.EOFException: null

排查与解决方案

核心问题分析

  1. 字段类型不匹配:totalTalkTime在SQL中是时间差的秒数(数值型),但实体类中定义为Date类型,Hibernate无法将数值反序列化为Date,直接引发转换异常。
  2. Number类型的不确定性:使用抽象类型Number作为数值属性,Hibernate无法确定具体的子类(Integer/Double等),反序列化时无法正确映射。
  3. 无参构造函数不规范:实体类的无参构造函数内部声明了局部变量,未初始化实例属性,不符合JPA实体类规范,可能导致实例化异常。
  4. SQL语法错误:findTeam方法的SQL中存在where GROUP BY的无效语法,导致SQL执行返回异常结果,间接引发反序列化失败。

具体修复步骤

1. 修正实体类字段类型与构造函数

将抽象的Number替换为具体数值类型,修正totalTalkTime的类型为Long(存储秒数总和),并规范无参构造函数:

@Entity
@Table(name = "report_queue")
public class Team implements Serializable {   
    @Id
    private Long id;
    private String queue;
    private Integer offered;
    private Integer answered;
    private Double answerRate;
    @Column(name="abandoned")
    private Integer abandoned;
    private Integer unmanaged;
    private Double avgAbandonTime; // 原SQL返回数值,替换String为Double
    private Long totalTalkTime; // 替换Date为Long,存储秒数总和
    private Double avgTalkTime;

    // 规范的无参构造函数
    public Team() {
    }

    // 构造函数参数与修改后的字段类型匹配
    public Team(Long id, String queue, Integer answered, Integer offered, Double answerRate, Integer abandoned, Double avgAbandonTime, Long totalTalkTime, Double avgTalkTime, Integer unmanaged) {
       this.id = id;
       this.queue = queue;
       this.answered = answered;
       this.offered = offered;
       this.answerRate = answerRate;
       this.abandoned = abandoned;
       this.avgAbandonTime = avgAbandonTime;
       this.totalTalkTime = totalTalkTime;
       this.avgTalkTime =  avgTalkTime;
       this.unmanaged=unmanaged;
   }
   // getters and setters..
}

2. 修复Repository中的SQL错误

移除findTeam方法SQL中多余的where关键字,并修正UNI X_TIMESTAMP的拼写错误:

public interface TeamRepo extends JpaRepository<Team, Long>{

    @Query(value="select q.id, q.queue,q.offered,q.answered,q.answerRate,q.abandoned,q.unmanaged,q.totalTalkTime,q.avgTalkTime,q.avgAbandonTime from(SELECT id as \"id\", queue AS \"queue\", COUNT(DISTINCT uniqueid) AS \"offered\", SUM(queuecallercomplete) AS \"answered\", ROUND(SUM(queuecallercomplete)/COUNT(DISTINCT uniqueid)*100,1) AS \"answerRate\", SUM(queuecallerabandon) AS \"abandoned\", SUM(queuecallerexit) AS \"unmanaged\", SUM(UNIX_TIMESTAMP(queuecallercompleteAt)-UNIX_TIMESTAMP(queuecallerleaveAt)) AS \"totalTalkTime\", ROUND(AVG(UNIX_TIMESTAMP(queuecallercompleteAt)-UNIX_TIMESTAMP(queuecallerleaveAt))) AS \"avgTalkTime\", ROUND(AVG(UNIX_TIMESTAMP(queuecallerAbandonAt)-UNIX_TIMESTAMP(queuecallerjoinAt))) AS \"avgAbandonTime\" FROM report_queue GROUP BY queue)q",nativeQuery = true)
    List<Team> getAll();

    @Query(value="SELECT id as \"id\", queue AS \"queue\", COUNT(DISTINCT uniqueid) AS \"offered\", SUM(queuecallercomplete) AS \"answered\", ROUND(SUM(queuecallercomplete)/COUNT(DISTINCT uniqueid)*100,1) AS \"answerRate\", SUM(queuecallerabandon) AS \"abandoned\", SUM(queuecallerexit) AS \"unmanaged\", SUM(UNIX_TIMESTAMP(queuecallercompleteAt)-UNIX_TIMESTAMP(queuecallerleaveAt)) AS \"totalTalkTime\", ROUND(AVG(UNIX_TIMESTAMP(queuecallercompleteAt)-UNIX_TIMESTAMP(queuecallerleaveAt))) AS \"avgTalkTime\", ROUND(AVG(UNIX_TIMESTAMP(queuecallerAbandonAt)-UNIX_TIMESTAMP(queuecallerjoinAt))) AS \"avgAbandonTime\" FROM report_queue GROUP BY queue",nativeQuery = true)
    List<Team> findTeam();

    void deleteTeamById(Long id);

    Optional<Team> findTeamById(Long id);
}

3. 额外建议

如果原生查询返回的结果不需要作为持久化实体操作,建议使用DTO(数据传输对象)接收结果,避免实体类与查询结果的强绑定,进一步降低反序列化风险。


内容的提问来源于stack exchange,提问作者Kiran Basavapattana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 16:30:49