目前我们正在使用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使用率变得很疯狂。
为了解决这个问题,我想创建一个事务感知队列来顺序插入实体,但这会导致大量的插入时间。 处理这种情况的正确方法是什么?
答案 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();
}
这将为每个插件创建一个事务,并消除数据库锁定问题。