通过 Hibernate 更新计数器

Posted

技术标签:

【中文标题】通过 Hibernate 更新计数器【英文标题】:Updating counters through Hibernate 【发布时间】:2011-02-23 21:21:45 【问题描述】:

这是一种极其常见的情况,所以我期待一个好的解决方案。基本上我们需要更新表中的计数器。以网页访问为例:

Web_Page
--------
Id
Url
Visit_Count

所以在hibernate中,我们可能会有这样的代码:

webPage.setVisitCount(webPage.getVisitCount()+1);

mysql默认读取不关注事务的问题。因此,高流量网页的计数会不准确。

我习惯做这种事情的方式就是调用:

update Web_Page set Visit_Count=Visit_Count+1 where Id=12345;

我想我的问题是,我如何在 Hibernate 中做到这一点?其次,如何在 Hibernate 中进行这样的更新,这有点复杂?

update Web_Page wp set wp.Visit_Count=(select stats.Visits from Statistics stats where stats.Web_Page_Id=wp.Id) + 1 where Id=12345;

【问题讨论】:

【参考方案1】:

mysql默认读取不关注事务的问题。因此,高流量网页的计数会不准确。

的确如此。我会在这里使用 DML 风格的操作(参见章节13.4. DML-style operations):

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

String hqlUpdate = "update webPage wp set wp.visitCount = wp.visitCount + 1 where wp.id = :id";
int updatedEntities = s.createQuery( hqlUpdate )
        .setLong( "newName", 1234l )
        .executeUpdate();
tx.commit();
session.close();

这应该会导致

update Web_Page set Visit_Count=Visit_Count+1 where Id=12345;

其次,如何在 Hibernate 中进行这样的更新,这有点复杂?

嗯...我很想说“你完蛋了”...需要多考虑一下。

【讨论】:

谢谢帕斯卡。我不知道我可以在 HQL 中进行更新。看起来很容易。但是对于我更复杂的示例,这是否会成为不关注交易的同一个 SELECT 问题的受害者?你建议我如何处理?【参考方案2】:

stored procedure 有几个好处:

    如果架构发生变化,如果代码是call increment($id),则无需更改代码 可以本地化并发问题。 在许多情况下执行速度更快。

一个可能的实现是:

create procedure increment (IN id integer)
begin
    update web_page
      set visit_count = visit_count + 1
      where `id` = id;
end

【讨论】:

以上是关于通过 Hibernate 更新计数器的主要内容,如果未能解决你的问题,请参考以下文章

定时器更新事件

Java Hibernate 计数行

spring+Hibernate 一对多计数行

从文件中解析普罗米修斯指标并更新计数器

如何通过读取、递增和更新数据库中的列来有效地保持计数

Grails:乐观锁定,StaleObjectStateException 与 Spring Security 会话中的域,更新计数器