4

目前我们正在使用带有 Java 和 MySQL 的 play 1.2.5。我们有一个简单的 JPA 模型(一个扩展 Model 类的 Play 实体),我们保存到数据库中。

SimpleModel() test = new SimpleModel();
test.foo = "bar";
test.save();

在每个 Web 请求中,我们保存多个 SimpleModel 实例,例如:

JPAPlugin.startTx(false);
for (int i=0;i<5000;i++)
{
     SimpleModel() test = new SimpleModel();
     test.foo = "bar";
     test.save();
}
JPAPlugin.closeTx(false);

我们正在使用 JPAPlugin.startTx 和 closeTx 来手动启动和结束事务。如果只有一个请求执行事务,一切正常。我们注意到,如果第二个请求尝试同时执行循环,则第二个请求会收到“超过锁定等待超时;尝试重新启动事务 javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not insert: [SimpleModel ]”,因为第一个请求锁定了表,但直到第二个请求超时才完成。这导致多个:

错误 AssertionFailure:45 - 发生断言失败(这可能表明 Hibernate 中存在错误,但更可能是由于会话使用不安全) org.hibernate.AssertionFailure: SimpleModel 条目中的空 id(在发生异常)

另一个消毒是插入期间的 CPU 使用率变得疯狂。

为了解决这个问题,我正在考虑创建一个事务感知队列来顺序插入实体,但这会导致插入时间很长。处理这种情况的正确方法是什么?

4

3 回答 3

0

你真的需要整个插入的事务吗?数据导入过程中数据库没有锁定有关系吗?

您可以简单地创建一个作业并为每个插入执行它:

for (int i=0;i<5000;i++)
{
     new Job() { 
       doJob(){ 
          SimpleModel() test = new SimpleModel();
          test.foo = "bar";
          test.save();
      }.now();
}

这将为每个插入创建一个事务并摆脱您的数据库锁定问题。

于 2013-04-15T13:47:27.053 回答
0

在这种情况下,您不需要自己处理事务。

相反,如果任务很耗时,请将您的插入放入控制器方法或异步作业中。

作业和控制器都处理事务。

但是,请检查这是否真的是您想要实现的目标。每个 http 请求创建 5000 条记录似乎并不现实。也许拥有一个带有集合的容器模型会更有意义?

于 2013-04-15T05:44:06.923 回答
0

Play Framwork 1.2.5 上的 JPAPlugin 不是线程安全的,您无法使用此版本的 Play 解决此问题。

该问题在 Play 2.x 上已修复,但如果您无法迁移,请尝试直接使用休眠。

于 2013-04-15T01:03:24.363 回答