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

Urb*_*leg 3 java concurrency spring hibernate jpa

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

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

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

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

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

 @Transactional
 @public void doSomeMagic() {
    User user = userDao.findById(id);
    user.setStuff(stuff);
    ...       
 }
Run Code Online (Sandbox Code Playgroud)

现在,提出的建议如下:

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

我们可以这样做:

 userDao.updatePlayer(stuffParameters);   // "update Player p set stuffParameters...."
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

谢谢!

JB *_*zet 6

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

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

关于你的不同点:

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

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

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

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