简体   繁体   English

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

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

So we are developing a high concurrency web application that is pretty much a big multiplayer game. 因此,我们正在开发一个高度并发的Web应用程序,这是一个非常大的多人游戏。

Our server is using spring MVC , spring data , MySQL and JPA. 我们的服务器使用spring MVC,spring数据,MySQL和JPA。

We are now discussion the methodology we should use in regard to concurrency. 我们现在讨论我们应该在并发方面使用的方法。

One of the suggestions that came up pretty much got me out of my comfort zone: 提出的一个建议几乎让我脱离了我的舒适区:

I'm used to use the good old fashioned orm style: 我习惯使用老式的orm风格:

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

now, the suggestion that came up said the following: 现在,提出的建议如下:

since the above methodology is prone to concurrency mishaps (and probably mitigated by locking mechanism), why don't we use SQL \\ JPQL updates instead? 由于上述方法容易出现并发错误(并且可能通过锁定机制而减轻),为什么我们不使用SQL \\ JPQL更新呢? why even bothering fetching the user if our only goal is to update its fields? 如果我们唯一的目标是更新其字段,为什么甚至打扰取用户?

we could do something like this: 我们可以这样做:

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

Now , i have some question about this methodology: 现在,我对这种方法有一些疑问:

1) How common is the practice of using update queries instead of updating through the ORM alone? 1)使用更新查询而不是仅通过ORM进行更新的做法有多常见?

2) What exactly are the pitfalls of this methodology? 2)这种方法的缺陷究竟是什么?

3) Are there any hybrid solutions? 3)有没有混合解决方案? or another alternative that i haven't spoke of? 或者我没有谈到的另一种选择?

4) Can anyone that actually used this methodology tell some of the rules \\ realizations he got ? 4)任何真正使用这种方法的人都能说出他得到的一些规则\\实现吗?

Thanks! 谢谢!

First of all, I'd like to mention that your good old fashioned orm style shouldn't use save() at all. 首先,我想提一下,你的老式风格不应该使用save() Attached entities are automatically persistent. 附加实体自动持久化。 The save() call is useless. save()调用没用。 Every change made to an attached entity will be persisted at commit time (or sooner). 对附加实体所做的每个更改都将在提交时(或更早)保留。

I'd also like to point that there are no more concurrency problems with this approach than there are with an approach consisting in using update queries. 我还想指出,与使用更新查询的方法相比,此方法不再存在并发问题。 To the contrary: if optimistic locking (using @Version) is used, the old fashioned way of doing has less concurrency problems than the update query approach (which simply updates the state regardless of whether some concurrent transaction also has updated it). 相反:如果使用乐观锁定(使用@Version),那么旧式的执行方式比更新查询方法(它只是更新状态而不管某些并发事务是否也更新它)的并发性问题更少。

Regarding your different points: 关于你的不同点:

  1. Not very common, because this is much more cumbersome than just modifying the entities and let JPA handle the update queries. 不常见,因为这比仅修改实体并让JPA处理更新查询要麻烦得多。 It's also much more complex to handle complex use cases, and makes to code look like JDBC code, which JPA allows avoiding in the first place. 处理复杂的用例也要复杂得多,并且使代码看起来像JDBC代码,JPA首先允许这样做。

  2. The pitfalls are that optimistic locking is bypassed if you use update queries, as is the first-level cache. 如果您使用更新查询,则会绕过乐观锁定的缺陷,就像第一级缓存一样。 So if you have loaded an entity and use an update query to update its state, the loaded entity will still hold the old state. 因此,如果您已加载实体并使用更新查询来更新其状态,则加载的实体仍将保持旧状态。

  3. You can use both approaches together. 您可以一起使用这两种方法。 Just beware of the pitfalls I mentioned at point 2. 请注意我在第2点提到的陷阱。

  4. Update queries can make sense, especially if the goal is to update many entities at once. 更新查询是有意义的,特别是如果目标是一次更新许多实体。 I would only downgrade to such an approach if you have proven that you had a performance problem, and that this performance problem could be solved by using this approach. 如果您已经证明存在性能问题,我只会降级到这种方法,并且可以通过使用此方法解决此性能问题。 Otherwise, it's just premature optimization, which has a high productivity and robustness cost. 否则,它只是过早优化,具有高生产率和稳健性成本。

Hibernate supports batch updates via HQL/JPSQL, see here an example : 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();

This is usual in the case of batch processing, when you need to issue a modification query that changes a lot of entities in the database, but don't want to incur the overhead of loading all entities in-memory, dirty checking them and flushing changes to the database. 这通常是在批处理的情况下,当您需要发出修改数据库中的许多实体的修改查询,但不希望产生加载内存中的所有实体,脏检查它们和刷新的开销更改数据库。

The pitfall is that batch queries can modify objects in the database that are already in the session, and in that case the data in the session will be stale. 缺点是批处理查询可以修改数据库中已经在会话中的对象,在这种情况下,会话中的数据将是陈旧的。

It is possible to have the update incrementing the version by using the keyword versioned in front of update . 通过使用在updateversioned的关键字,可以使更新增加版本。

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

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