繁体   English   中英

高并发Web应用程序上的Hibernate \ JPA用法

[英]Hibernate \ JPA usage on a high concurrency web application

因此,我们正在开发一个高度并发的Web应用程序,这是一个非常大的多人游戏。

我们的服务器使用spring MVC,spring数据,MySQL和JPA。

我们现在讨论我们应该在并发方面使用的方法。

提出的一个建议几乎让我脱离了我的舒适区:

我习惯使用老式的orm风格:

 @Transactional
 @public void doSomeMagic() {
    User user = userDao.findById(id);
    user.setStuff(stuff);
    ...       
 }

现在,提出的建议如下:

由于上述方法容易出现并发错误(并且可能通过锁定机制而减轻),为什么我们不使用SQL \\ JPQL更新呢? 如果我们唯一的目标是更新其字段,为什么甚至打扰取用户?

我们可以这样做:

 userDao.updatePlayer(stuffParameters);   // "update Player p set stuffParameters...."

现在,我对这种方法有一些疑问:

1)使用更新查询而不是仅通过ORM进行更新的做法有多常见?

2)这种方法的缺陷究竟是什么?

3)有没有混合解决方案? 或者我没有谈到的另一种选择?

4)任何真正使用这种方法的人都能说出他得到的一些规则\\实现吗?

谢谢!

首先,我想提一下,你的老式风格不应该使用save() 附加实体自动持久化。 save()调用没用。 对附加实体所做的每个更改都将在提交时(或更早)保留。

我还想指出,与使用更新查询的方法相比,此方法不再存在并发问题。 相反:如果使用乐观锁定(使用@Version),那么旧式的执行方式比更新查询方法(它只是更新状态而不管某些并发事务是否也更新它)的并发性问题更少。

关于你的不同点:

  1. 不常见,因为这比仅修改实体并让JPA处理更新查询要麻烦得多。 处理复杂的用例也要复杂得多,并且使代码看起来像JDBC代码,JPA首先允许这样做。

  2. 如果您使用更新查询,则会绕过乐观锁定的缺陷,就像第一级缓存一样。 因此,如果您已加载实体并使用更新查询来更新其状态,则加载的实体仍将保持旧状态。

  3. 您可以一起使用这两种方法。 请注意我在第2点提到的陷阱。

  4. 更新查询是有意义的,特别是如果目标是一次更新许多实体。 如果您已经证明存在性能问题,我只会降级到这种方法,并且可以通过使用此方法解决此性能问题。 否则,它只是过早优化,具有高生产率和稳健性成本。

Hibernate通过HQL / JPSQL支持批量更新,请参见此处的示例

String jpqlUpdate =
        "update Customer c " +
        "set c.name = :newName " +
        "where c.name = :oldName";
int updatedEntities = entityManager.createQuery( jpqlUpdate )
        .setString( "newName", newName )
        .setString( "oldName", oldName )
        .executeUpdate();

这通常是在批处理的情况下,当您需要发出修改数据库中的许多实体的修改查询,但不希望产生加载内存中的所有实体,脏检查它们和刷新的开销更改数据库。

缺点是批处理查询可以修改数据库中已经在会话中的对象,在这种情况下,会话中的数据将是陈旧的。

通过使用在updateversioned的关键字,可以使更新增加版本。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM