【问题标题】:Thread hangs on calling getResultList()线程在调用 getResultList() 时挂起
【发布时间】:2018-12-17 10:21:21
【问题描述】:

我对 JPA 有一个奇怪的问题。在我的调度器中执行下一个代码

@SuppressWarnings("unchecked")
 @Transactional
 public void refreshSmsStatuses() {
    try {
        log.info("Enter refreshSmsStatuses");

        EntityManager em = hibernateHelper.getEntityManager();

        log.info("EM created");

        List<Sms> lSms = null;

        log.info("lSms = null;");

        TypedQuery<Sms> smsQuery = em.createQuery(
            "SELECT sms FROM Sms AS sms 
             join sms.status as status 
             WHERE status.isFinal = 0 
             and sms.remoteId is not null 
             and sms.sendDate > sysdate - 3", Sms.class);

        log.info("sqlQuery created");

        lSms = smsQuery.getResultList();

        log.info("Query SMS executed");
        .....

在计划夜间重启后,它会运行几次并挂起。有下一个字符串

2018-12-17 00:10:33,802 [SmsDao.java:pool-2-thread-1:166] - lSms = null;
2018-12-17 00:10:33,802 [SmsDao.java:pool-2-thread-1:168] - sqlQuery created

在日志文件中。查询不在 DB 中执行,它挂在 JPA 的某个地方。问题仅在生产服务器上。挂起任何sheduler的方法后都不起作用,因为,我认为他们等待该方法结束。 如果有人遇到类似的问题,请帮助我。 非常感谢

更新

@Table( name = "ZUSB_SMS") 
@Entity
public class Sms extends BaseModel {
    private static final long serialVersionUID = -3624326750555670797L;
    @Id
    @SequenceGenerator(name = "generator", sequenceName = "ZUSB_SMS_SEQ")
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "generator")
    @Column(name = "id")
    private Long id;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "REF_SMS_TEMPLATE_ID", referencedColumnName = "id")
    private SmsTemplate template;
    @Column(name = "name")
    private String name;
    @Column(name = "send_date")
    private Date sendDate;
    @Column(name = "phone")
    private String phone;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "REF_CLIENT_ID", referencedColumnName = "id")
    private Client client;
    @Column(name = "text")
    private String text;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "REF_SMS_STATUS_ID", referencedColumnName = "id")
    private SmsStatus status;


    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "REF_USER_ID", referencedColumnName = "id")
    private User user;
    @Column(name = "remote_id")
    private Long remoteId;
    private String log = "";

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "REF_CLE_STATUS_ID", referencedColumnName = "id")
    private SmsCleStatus cleStatus;
    @Column(name = "cle_text")
    private String cleText;
    @Column(name = "cle_id")
    private Long cleId;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public SmsTemplate getTemplate() {
        return template;
    }
    public void setTemplate(SmsTemplate template) {
        this.template = template;
    }
    public Date getSendDate() {
        return sendDate;
    }
    public void setSendDate(Date sendDate) {
        this.sendDate = sendDate;
    }
    public String getPhone() {
        return phone;
    }
    public void setPhone(String phone) {
        this.phone = phone;
    }
    public Client getClient() {
        return client;
    }
    public void setClient(Client client) {
        this.client = client;
    }
    public String getText() {
        return text;
    }
    public void setText(String text) {
        this.text = text;
    }
    public SmsStatus getStatus() {
        return status;
    }
    public void setStatus(SmsStatus status) {
        this.status = status;
    }
    public User getUser() {
        return user;
    }
    public void setUser(User user) {
        this.user = user;
    }
    public Long getRemoteId() {
        return remoteId;
    }
    public void setRemoteId(Long remoteId) {
        this.remoteId = remoteId;
    }
    public String getLog() {
        return log;
    }

    public void setLog(String log) {
        DateFormat df = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
        Date today = Calendar.getInstance().getTime();        
        String reportDate = df.format(today);
        if(log.equals(""))
            this.log = reportDate + " " + log;
        else
            this.log = this.log + "\n" + reportDate + " " + log;
    }

    public SmsCleStatus getCleStatus() {
        return cleStatus;
    }

    public void setCleStatus(SmsCleStatus cleStatus) {
        this.cleStatus = cleStatus;
    }

    public String getCleText() {
        return cleText;
    }

    public void setCleText(String cleText) {
        this.cleText = cleText;
    }

    public Long getCleId() {
        return cleId;
    }

    public void setCleId(Long cleId) {
        this.cleId = cleId;
    }






}

附:对不起我的英语

【问题讨论】:

  • 错误信息是什么?
  • 您确定您的查询不会永远运行,这是一个看起来很奇怪的连接吗?为什么所有东西都命名为sms,表,列,别名,(域?)这使得查询很难阅读
  • 没有任何错误信息。在那条线上,踏板只是挂着
  • 你要加入ON 什么?为什么你甚至需要 join ?可能你想要这样的查询 - FROM Sms s WHERE s.isFinal = 0 and s.remoteId is not null and s.sendDate &gt; sysdate - 3 你能告诉我们你的SMS 类吗?
  • 为什么 hibernateHelper.getEntityManager() 感觉不对,您应该在 EntityManager 类型的字段上简单地使用 @PersistenceContext 并使用它。看起来你正在获得 Spring 范围之外的东西。以应有的方式做事并删除您的HibernateHelper

标签: java spring hibernate jpa


【解决方案1】:

首先,您的查询不正确,因为您没有指定 ON 您要加入的内容。其次,您不需要明确地joinSmsStatus 表,因为您使用@ManyToOne 映射它。

像这样更新你的查询-

TypedQuery<Sms> smsQuery = em.createQuery(
        "FROM Sms s                            
         WHERE s.status.isFinal = 0
         AND s.remoteId IS NOT NULL   
         AND s.sendDate > sysdate-3", Sms.class);

这或许能解决问题。

【讨论】:

  • 在查询中加入一个基本的 JOIN 与线程挂起无关;当您想明确定义连接时,这是一件完全正常的事情。要调试线程挂起,请执行线程转储并查看实际挂起的内容,或者只查看 JPA 提供程序日志
  • Billy Frost,您的版本看起来不错。今天我将尝试在 log4j.logger.org.springframework.orm.jpa=DEBUG 上切换。但是,不幸的是,这个问题可能会消失一段时间。我希望日志记录对我有帮助
  • 第一次查看代码时,很明显 OP 的查询不正确。因此,微不足道的假设是更正查询。我同意我的回答没有完全符合 op 的问题,但也不是完全错误!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-28
  • 2013-08-18
  • 1970-01-01
  • 2020-03-13
相关资源
最近更新 更多