0

我尝试从表中删除超过给定时间的行。行的start是时间戳。

EntityManager em = ...
long interval = ... // long value read from a properties file

String template = "DELETE FROM %s WHERE current_timestamp() - start > :interval";
String jpql = String.format(template , MyClass.class.getCanonicalName());

Query q = em.createQuery(jpql);
q.setParameter("interval", TimeUnit.DAYS.toMillis(interval));
q.executeUpdate();

MyClass.java

@Entity
@Table(name = "ROWS")
public class MyClass implements Serializable {

    private static final long serialVersionUID = 6070604872038740340L;

    puyblic MyClass() {
    }

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(name = "start", columnDefinition="TIMESTAMP WITH TIME ZONE")
    @Temporal(TemporalType.TIMESTAMP)
    private Date start;

    // getters ans setters...
}

但是,我得到以下异常:

原因:java.lang.IllegalArgumentException:参数值 [604800000] 与 org.hibernate.ejb.AbstractQueryImpl.registerParameterBinding(AbstractQueryImpl.java:360) 的 org.hibernate.ejb.QueryImpl 中的类型 [java.lang.Double] 不匹配.setParameter(QueryImpl.java:364) 在 org.hibernate.ejb.QueryImpl.setParameter(QueryImpl.java:72)

我究竟做错了什么 ?

4

3 回答 3

2

这里我如何解决我的问题:

我没有在 JPQL 中进行计算和比较,而是在我的 Java 代码中进行所有计算。最后的比较留给 JPQL。

String template = "DELETE FROM %s WHERE start < :calculatedStop";
String jpql = String.format(template , MyClass.class.getCanonicalName());

long calculatedStop = new java.util.Date().getTime() - INTERVAL;// INTERVAL is a constant

Query q = em.createQuery(jpql);
q.setParameter("calculatedStop", calculatedStop);
q.executeUpdate();
于 2013-10-03T23:07:50.203 回答
1

答案很简单。

String template = "DELETE FROM %s WHERE current_timestamp() - start > :interval"; 构建这个查询 Hibernate 期望这个间隔值是 Double 类型。

所以这样做可以解决你的问题:

q.setParameter("interval", (double)TimeUnit.DAYS.toMillis(interval));

如果需要,我们都希望 Java 能够从 long 转换为 double。但是由于 long 值是装箱的,Hibernate 只是尝试Long 转换为 Double,这确实没有任何成果。

因此,如果您首先将其转换为双精度,则它会被装箱为双精度,而双精度显然可以转换为双精度。

那么Double是从哪里来的呢?

我检查了 SqlDate 和 Date 类型的实现,它们都映射到 date 并且能够从 long 值转换为 long 值。时间戳也映射到日期。

所以我尝试了这个:

String template = "DELETE FROM %s WHERE current_timestamp() > :interval"; 它失败了,因为 Hibernate 抱怨 Long 与 java.util.Date 不兼容。因此,仅使用 current_timestamp() 映射到 Date 值。

这也是如此:

String template = "DELETE FROM %s WHERE start > :interval";

当一个人试图从另一个日期中减去一个日期时,双重作用就会发挥作用。所以使用任何一个: String template = "DELETE FROM %s WHERE current_timestamp() - current_timestamp() > :interval";String template = "DELETE FROM %s WHERE start - start > :interval";

由于 Date - Date 的结果应该是一个 Double 值,因此间隔应该是一个双精度值。这就是 Hibernate 抱怨的原因。

有点奇怪,但这就是它的方式,这就是对正在发生的事情的确切解释。

于 2013-10-01T22:10:32.957 回答
0

请查看 HSQL。该问题可能与 currentTimestamp 和 start 有关。我想不出它是 HSQL 关键字或有效属性。

您是否尝试过使用未命名的参数并使用其索引设置参数?

更新

您的设置似乎不正确。您想使用字符串(开始)进行算术计算。

我最近做了类似的事情。我只有一个任务,我设置了时间,之后我检查任务是否超时(没有完成,但时间戳比之前小)。

这是一些代码:

1/ 映射

long timestamp = 0; //default is 0

2/ 设置时间戳

task.setTimestamp(System.currentTimeMillis()); session.getTransaction().commit()

3/ 查询超时方法

   session.beginTransaction();
   long currentTime = System.currentTimeMillis();
   Criteria criteria = session.createCriteria(Task.class);
   criteria.add(Restrictions.eq("done", false));
   criteria.add(Restrictions.le("timestamp", currentTime - Task.TASK_TIMEOUT));
   Task task = (Task)criteria.uniqueResult();
   if(task != null) {
        task.setTimestamp(currentTime);
   }
   session.getTransaction().commit();

你可以看到我在这里只使用条件搜索,因为它更简单。另请注意,我使用 uniqueResult 但您可以轻松更改它以检索列表。

于 2013-09-30T17:13:38.680 回答