处理多个插入的最佳方法

时间:2013-04-14 17:41:57

标签: java database performance jpa playframework

目前我们正在使用Java和MySQL的play 1.2.5。我们有一个简单的JPA模型(一个扩展模型类的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:无法插入:[SimpleModel ]“因为第一个请求会锁定表,但在第二个请求超时之前不会执行。 这导致多个:

  

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

另一个消毒方法是插入过程中的CPU使用率变得很疯狂。

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

3 个答案:

答案 0 :(得分:0)

Play Framwork 1.2.5上的JPAPlugin不是线程安全的,你不会使用这个版本的Play来解决这个问题。

Play 2.x上修复了这个问题,但如果你无法迁移,请尝试直接使用hibernate。

答案 1 :(得分:0)

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

如果任务耗时,则将插入放在控制器方法或异步作业中。

工作和控制器都处理交易。

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

答案 2 :(得分:0)

您真的需要整个插入的交易吗?数据导入期间数据库是否未锁定是否重要?

您只需创建一个作业并为每个插入执行它:

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

这将为每个插件创建一个事务,并消除数据库锁定问题。