Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2012/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 滚动时使用Session.save()时,ScrollableResultSet.next()会逐渐变慢_Java_Hibernate_H2_Scrollableresults - Fatal编程技术网

Java 滚动时使用Session.save()时,ScrollableResultSet.next()会逐渐变慢

Java 滚动时使用Session.save()时,ScrollableResultSet.next()会逐渐变慢,java,hibernate,h2,scrollableresults,Java,Hibernate,H2,Scrollableresults,我使用ScrollableResults对象从表中滚动大约500000到1000000行。滚动时,我使用每次迭代的结果实体创建不同的实体,并使用session.save持久化此对象。下面是示例代码,其中真正的代码更复杂,但本质上做的是相同的事情 Session = getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); ScrollableResults results = session.c

我使用ScrollableResults对象从表中滚动大约500000到1000000行。滚动时,我使用每次迭代的结果实体创建不同的实体,并使用session.save持久化此对象。下面是示例代码,其中真正的代码更复杂,但本质上做的是相同的事情

Session = getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
ScrollableResults results = session.createQuery("from Foo_Table f join f.bars b")
    .scroll(ScrollMode.FORWARD_ONLY);
int i = 0;
while(results.next())
{
    Foo foo = (Foo) results.get(0);
    Bar bar = new Baz(foo);
    bar.setFoo(foo);

    session.save(bar)

    if(i % 50 == 0)
    {
        session.flush();
        session.clear();
    }
}

tx.commit();
session.close();
重要实体:

@Entity
@Table(name = "FOO_TABLE")
public class Foo_Entity implements Serializable {
    @Id    
    @Column(name = "Foo_ID", nullable=false)
    private String id;

    @OneToMany(fetch = FetchType.EAGER, //FetchType.LAZY fixes the slow down 
               mappedBy = "fooParent", cascade = CascadeType.ALL)
    private Set<Bar> bar_entities = new HashSet<>(0);
}

@Entity
@Table(name = "BAR_TABLE")
public class Bar_Entity implements Serializable {
    @Id
    @GeneratedValue
    @Column(name="Id")
    private Long id;

    @ManyToOne
    @JoinColumn(name="foo_pk")
    private Foo fooParent;

    // setFoo, getFoo...

}
当我对这个事务计时时,运行时间从每500次迭代大约100ms开始,但在大约20000次迭代之后,逐渐上升到每500次迭代几秒。因此,事务的性能非常差。唯一需要花费时间的代码行是results.next,它的执行时间越来越长

如果我将Foo中Bar实体的fetch类型从eager更改为lazy,那么问题就解决了。我不明白为什么对尚未填充的集合使用“急取”类型会导致在包含关系的实体之间滚动出现问题。在session.flush上滚动时,确实会填充该集合,但在我的场景中,该集合通常只填充一到两个元素,这就是为什么我更希望将此获取类型设置为eager

有人知道为什么在这种特殊情况下会出现这种减速吗


请注意,在我意识到更改获取类型解决了问题之前,这个问题是第一次发布的,因此,现在的问题已经从如何解决这个问题转移到了为什么这是一个问题?

BAR_TABLE上缺少索引。foo_pk列将通过快速获取来降低速度,因为将首先执行完整的表扫描以加载与每个foo实体关联的BAR实体,

,如果fetch是eager,这意味着延迟加载为false,那么只要加载Foo_实体,就会加载Bar_实体。所以,要么删除查询中的连接,要么将fetch设置为lazy。两者兼备是多余的

第二,关于减速。因为您正在打开一个有状态会话。由于hibernate一级缓存,每个对象都缓存在内存中。在这种情况下,减速与懒惰、渴望或加入无关。速度减慢是由于hibernate在缓存内存中保留的对象数量。尝试使用无状态会话。然后慢下来应该消失了。请参考以下网址


您是否尝试过使用探查器查找内存泄漏?即使没有剖析器,我敢打赌你也可以用和找出答案。另外,如果您使用eclipse,我强烈推荐@durron597,谢谢,我将在java VisualVM中查看一下。但是内存泄漏会如何降低下一次执行的速度呢?不是Oracle的每一次机会@Bret否,h2,对不起,我忘了提到这一点。@Bret另外,我只需要FORWARD_作为滚动模式。