0

在我的 Jboss7 Java EE 6 Web 应用程序中,我需要管理一个简单的“类别”实体的树结构,如下所示:

@Entity
@Table(name="categorie")
@NamedQueries({ 
    @NamedQuery(name="selezionaTutti", query="select c from Categoria c left join fetch c.children left join fetch c.parent")
})
public class Categoria implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotNull
    private String nome;

    @OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
    @JoinColumn(name = "parent_id")
    private List<Categoria> children = new LinkedList<Categoria>();

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name = "parent_id",insertable=false,updatable=false)
    private Categoria parent;

... //various getter, setter, and so on
}

命名查询一次加载我的整个(小)树,第一次,然后它停留在持久性上下文中。

然后我想“探索”这棵树,所以我得到根节点并将其传递给这个函数:

private List<Categoria> getAlberoCategorie(Categoria root, int profondita) {
        List<Categoria> tmpList = new ArrayList<Categoria>();
        root.setProfondita(profondita);
        if ( root.getParent() != null ) {
            tmpList.add(root);
        }
        if (!root.getChildren().isEmpty()) {
            profondita++;
            for (Categoria figlia : root.getChildren()) {
                tmpList.addAll(getAlberoCategorie(figlia,profondita)); // this line generates the stack overflow!!! 
            }
        }
        return tmpList;
    }

异常的确切堆栈跟踪是:

java.lang.StackOverflowError org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:112) org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:137) org.hibernate.collection.internal.PersistentBag .isEmpty(PersistentBag.java:249) it.trew.data.CategoriaFacade.getAlberoCategorie(CategoriaFacade.java:59)

在我的本地机器上,确实一切正常。在小型测试服务器上,读取类别时崩溃!

我怎样才能改善我的功能?

4

1 回答 1

0

您的堆栈空间已超出。你在堆栈上放了太多数据。这可能是因为您使用了太多的局部变量(局部变量保存在堆栈中)或者因为递归深度太深或无限。

您可以做什么: 按此顺序:

1)检查无限递归。如果类别实体在其子列表中包含其自身或其父或祖先,则可能发生这种情况。在这种情况下,您会得到一个无限循环(由于无限递归),当堆栈已满时会中断,而这正是您遇到的异常。

要检查这一点,您可以查看您的数据库或调试代码,或者将递归深度打印到 System.out(您已经在参数中获得了深度profondita)。

如果没有不定式循环:

2) tmpList 在栈上。可能是,那里需要太多空间。将其作为参数而不是返回值(肯定不那么漂亮,但使用的资源更少):

private void getAlberoCategorie(List<Categoria> list, Categoria root, int profondita) {
    root.setProfondita(profondita);
    if ( root.getParent() != null ) {
        list.add(root);
    }
    if (!root.getChildren().isEmpty()) {
        profondita++;
        for (Categoria figlia : root.getChildren()) {
            getAlberoCategorie(list, figlia,profondita); 
        }
    }
}

如果这仍然没有帮助并且深度很深但不是无限的:

3)用迭代替换递归(常见的编程技术,但在这种情况下非常难看,因为这是为递归而设计的)。

可能1)(我猜)或2)会解决问题。

于 2012-05-16T11:38:10.610 回答