在选择期间休眠重复的行

Posted

技术标签:

【中文标题】在选择期间休眠重复的行【英文标题】:Hibernate duplicated rows during select 【发布时间】:2018-05-30 02:50:32 【问题描述】:

几个月前,我开始使用 Hibernate 5。我正在创建一个 Spring Boot 应用程序,它需要从数据库视图中获取数据。 我创建了一个 JPA 实体并编写了负责运行查询并将结果映射到 ORM 实体的代码。问题是 Hibernate 在跟踪中生成正确的查询,但将第一行的副本作为列表返回。 Hibernate 创建的查询如下所示:

select
    revenuesum0_.revenueId as revenueI1_9_,
    revenuesum0_.amount as amount2_9_,
    revenuesum0_.calculatedDate as calculat3_9_,
    revenuesum0_.revenueCalculatedDateId as revenueC4_9_,
    revenuesum0_.categoryName as category5_9_,
    revenuesum0_.timeSpan as timeSpan6_9_,
    revenuesum0_.title as title7_9_,
    revenuesum0_.userId as userId8_9_ 
from
    RevenueSummaryView revenuesum0_ 
where
    revenuesum0_.userId=?;

当我在 DBeaver 上运行它并在 mysql 控制台中运行时,结果集是正确的。当我尝试使用 Java JPA 查询执行获取数据时出现问题。负责 bug 的代码在这里:

    package org.pbt.dao;

    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.pbt.HibernateUtil;
    import org.pbt.model.entity.ExpenseSummaryView;
    import org.pbt.model.filter.Filter;
    import org.springframework.stereotype.Repository;

    import javax.persistence.Query;
    import java.util.List;


    @Repository
    public class ExpenseSummaryViewDAOImpl implements ExpenseSummaryViewDAO 
        private SessionFactory sessionFactory = HibernateUtil.getSessionFactory();


        @Override
        public List<ExpenseSummaryView> getFiltered(Filter filter) 
            Session session = this.sessionFactory.openSession();
            String hql = "FROM ExpenseSummaryView WHERE userId = :userId ";

            if (filter.getStartDate() != null && filter.getEndDate() != null) 
                hql += "AND calculatedDate BETWEEN :startDate AND :endDate ";
             else if (filter.getStartDate() != null) 
                hql += "AND calculatedDate >= :startDate ";
             else if (filter.getEndDate() != null) 
                hql += "AND calculatedDate <= :endDate ";
            

            Query query = session.createQuery(hql);
            query.setParameter("userId", filter.getUserId());

            if (filter.getStartDate() != null && filter.getEndDate() != null) 
                query.setParameter("startDate", filter.getStartDate());
                query.setParameter("endDate", filter.getEndDate());
             else if (filter.getStartDate() != null) 
                query.setParameter("startDate", filter.getStartDate());
             else if (filter.getEndDate() != null) 
                query.setParameter("endDate", filter.getEndDate());
            

            List<ExpenseSummaryView> expenseSummaryViews = (List<ExpenseSummaryView>) query.getResultList();
            session.close();

            return expenseSummaryViews;
        
    

在调试整个费用SummaryViews 列表元素时具有相同的对象引用。 JPA 实体如下所示:

package org.pbt.model.entity;

import org.springframework.format.annotation.DateTimeFormat;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.time.LocalDate;


@Entity
@Table(name = "ExpenseSummaryView")
public class ExpenseSummaryView 
    @Id
    @Column(name = "expenseId")
    private int id;

    @Column(name = "expenseCalculatedDateId", nullable = false)
    private int calculatedDateId;

    @Column(name = "userId", nullable = false)
    private int userId;

    @Column(name = "title", nullable = false)
    private String title;

    @Column(name = "amount", nullable = false)
    private double amount;

    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
    @Column(name = "calculatedDate", nullable = false)
    private LocalDate calculatedDate;

    @Column(name = "categoryName", nullable = false)
    private String categoryName;

    @Column(name = "timeSpan", nullable = false)
    private String timeSpan;


    public int getId() 
        return id;
    

    public int getCalculatedDateId() 
        return calculatedDateId;
    

    public int getUserId() 
        return userId;
    

    public String getTitle() 
        return title;
    

    public double getAmount() 
        return amount;
    

    public LocalDate getCalculatedDate() 
        return calculatedDate;
    

    public String getCategoryName() 
        return categoryName;
    

    public String getTimeSpan() 
        return timeSpan;
    

    @Override
    public String toString() 
        return "id:" + id + ", calculatedDateId:" + calculatedDateId + ", userId:" + userId + ", title:" + title + ", amount:" + amount + ", calculatedDate:" + calculatedDate.toString() + ", categoryName:" + categoryName + "";
    

值得一提的是,在非常相似的情况下,我使用 hibernate 从同一应用程序中同一数据库的另一个视图中获取行并且它可以正常工作,但在上述情况下却没有。

有人可以帮忙吗?

【问题讨论】:

您的代码和映射似乎是正确的。也许查看您的存储库配置?在另一件事上,您可以将 setParameter 部分优化为:if (filter.getStartDate() != null) query.setParameter("startDate", filter.getStartDate()); else if (filter.getEndDate() != null) query.setParameter("endDate", filter.getEndDate()); 您好,问题是因为数据库没有真实ID,数据库中的expenseId字段不是真实ID,修改后源代码启动正常。 【参考方案1】:

问题是因为数据库中没有可用的真实ID,数据库中的expenseId字段不是真实ID,更改后,源代码启动正常。

【讨论】:

以上是关于在选择期间休眠重复的行的主要内容,如果未能解决你的问题,请参考以下文章

为啥在更新事务期间休眠调用删除?

更新期间休眠不刷新

休眠查询异常:在 JPA 查询期间无法解析实体属性

如何在线程休眠期间每尝试一定次数后记录错误?

在休眠 saveOrUpdate() 期间获取 org.hibernate.StaleStateException

休眠 - 批量更新从更新返回意外的行数:0 实际行数:0 预期:1