休眠挂起或抛出延迟初始化没有会话或会话被关闭 [英] Hibernate hangs or throws lazy initialization no session or session was closed

查看:93
本文介绍了休眠挂起或抛出延迟初始化没有会话或会话被关闭的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在增强一个旧的Spring / Hibernate应用程序,并且我卡住了。我有一个读取文件长度超过3000行的方法,每行都有一条记录,必须与数据库上的某个记录进行比较,然后必须将一个寄存器添加到数据库中(多到多个表)。



表格和关系为

分支包含多个产品产品位于多个分支中。



产品包含许多产品类别



还有更多的表格可以正常使用。



我创建的新表/对象是 Branch,Product,BranchToProduct
$ b 产品具有一组BranchToProduct 包含3个字段的对象



我需要将BranchToProduct对象添加到Product集合中,其中3个字段是从我从每行的文件。



我添加了一个简单的代码行,应用程序抛出:


product =
productDAO.findByModel(stringModel);

未能延迟初始化
角色集合:
com.bamboo.catW3。 domain.Product.products,
没有会话或会话已关闭

如果我去hibernate映射(hbm fi le)并设置关系product_to_products lazy = false,这条线单独运行,但如果我试图把它放在文件循环中,应用程序总是挂起在正在处理的第18行,不管我使用哪个文件或顺序的内容,控制台停止工作,不得不关闭Java查杀进程。

无论哪种方式,在调试中,我得到很多HQL的简单查找,13直到我得到我的错误,当lazy = true时,以及当我使用lazy = false并将其放在循环中时,很多行。



我认为我应该尝试用lazy = true来解决问题。



这种情况让我怀疑:



1.-当lazy = true时。我怎么能不能运行这个命令的这一行的单行,但它在类的其他方法上工作正常?顺便说一下,这是一个名为CatalogFacade的类,它实现了其他类的方法:(CategoryFacade,ContainerFacade,ProductFacade,ProductOptionFacade,ProductStatusFacade,UserFacade,EmailFacade,FileFacade,BranchOfficeFacade )



这是
productDao.find()的代码:

<$ p (Product Integer id)抛出DataAccessException {

Product product =(Product)super.find(Product.class,id); (product!= null){
product.setProductAttributes(new TreeSet< ProductAttribute>(product.getProductAttributes()));


(Product ptp:product.getProducts()){
ptp.setProductAttributes(new TreeSet< ProductAttribute>(ptp.getProductAttributes()));



}

}

例外是最后为:

  pptp.setProductAttributes(新的TreeSet< ProductAttribute>(ptp.getProductAttributes( )))

在Intelij的调试器中,我可以看到由查询错误地形成的对象:



product.getProducts()= {org.hibernate.collection.PersistentSet@4312}unable to evaluate the expression Method threw'org.hibernate.LazyInitializationException'exception。



其他属性如何可以。该产品甚至没有其他产品在数据库中。



更新






product.find(int)


在获取异常之前的行中,我们可以在调试中看到product.products数组有错误,而不是您可以看到lazyInitialitationException的值。 如何,如果我从另一个方法调用它,数组就是find。所以它不能在它内部即使该方法只接收一个整数。



另外,我们发现这一切都发生在所有应用程序的生命周期,某些时候员工复制了一个类似它的方法,但将其更改为将空值设置为此损坏的数组。所以我100%肯定这个应用程序正在消耗更多的资源,然后它应该。



它在Flex中有视图,后来在JSTL中创建视图,调用这些方法时,对于相同的方法,异常会以不同的方式抛出。



添加更多信息。这是如何在AbstractDAOImpl中实现produt.find:
$ b

  public final Object find(Class clazz,Integer id)throws DataAccessException { 

return getHibernateTemplate()。get(clazz,id);
}

这是我的事务管理器配置,第一个答案中描述的注释方法通过fillip不起作用:


 < bean id =catalogFacadeclass =org。 springframework.transaction.interceptor.TransactionProxyFactoryBean> 
< property name =transactionManager>
< ref local =transactionManager/>
< / property>
< property name =target>
< ref local =catalogFacadeTarget/>
< / property>
< property name =transactionAttributes>
<道具>
< prop key =add *> PROPAGATION_REQUIRED< / prop>
< prop key =save *> PROPAGATION_REQUIRED< / prop>
< prop key =update *> PROPAGATION_REQUIRED< / prop>
< prop key =delete *> PROPAGATION_REQUIRED< / prop>
< prop key =remove *> PROPAGATION_REQUIRED< / prop>
< prop key =get *> PROPAGATION_SUPPORTS,readOnly< / prop>
< prop key =find *> PROPAGATION_SUPPORTS,readOnly< / prop>
< prop key =contains *> PROPAGATION_SUPPORTS,readOnly< / prop>
< prop key =login *> PROPAGATION_SUPPORTS,readOnly< / prop>
< /道具>
< / property>
< / bean>



解决方案

获取懒惰的初始化异常,因为在访问产品的成员变量之前会话正在关闭。当执行以下行时:

  Product product =(Product)super.find(Product.class,id)

Hibernate打开会话,检索您要查找的内容,然后关闭会话。任何lazy = true的字段此时都检索为 not ;相反,这些字段由代理填充。当您尝试检索代理对象的实际值时,它将尝试使用活动会话回到数据库以检索数据。如果没有会话可以找到,你会看到你看到的异常。设置lazy = true具有优势,因为它可以防止整个对象图形立即加载;嵌套的对象是独自留下,直到你特意请求它们。

有两种常见的技巧可以解决您的问题。您已经确定的第一个,即设置lazy = false。如果产品始终具有产品属性,并且您通常使用产品并将其属性组合在一起,则这很好。如果您经常只需要Product对象而不使用它的属性,那么您就会创建不必要的数据库负载。第二种技术是使用Spring注释将方法标记为事务性。

  @Transactional 
public Product find(Integer id)throws DataAccessException {

}

一些注释:


  1. 对于
    工作(@Transactional注释
    是不够的),您需要额外的
    配置。有关
    的更多信息,请参阅此处

  2. 最佳实践规定您在服务层中注释方法,而不是数据访问层。


I'm enhancing an old Spring/Hibernate application and im stuck. I have a method that reads a file 3000+ lines long, each line has a record which has to be compared with something on the database and then a register has to be added to the database (a many to many table).

Tables and relations are

Branch have many Product , Product are in many Branches.

Products have many Products, and a Category has many Products

And there are more tables that were there and work ok.

The new tables/objects that I created are Branch, Product, BranchToProduct.

Products have a Set of BranchToProduct objects, which have 3 fields

I need to add BranchToProduct objects to the set of Product, with the 3 fields filled from info I get from each line of the file.

I add a simple line and the application throws:

product = productDAO.findByModel(stringModel);

failed to lazily initialize a collection of role: com.bamboo.catW3.domain.Product.products, no session or session was closed

If i go to hibernate mapping (hbm file) and set the relation product_to_products lazy=false, the line runs fine alone, but if i try to put it on the file cycle the application hangs always at the 18 th line being processed, doesn´t matter which file i use or the order of the content, console stops working, have to shut java killing the process.

Either way, in debug, I get a lot of HQL's for a simple find, 13 lines of HQL until I get my error when lazy=true, and a LOT of lines when i use lazy=false and put it on the cycle.

I think I should try to fix the problem with lazy=true.

This situation make me wonder:

1.- When lazy=true. How come I cant run a single line of this command this method, but it works fine on other methods of the class?

by the way, this is a class called CatalogFacade that implements methods of other clasess: (CategoryFacade,ContainerFacade,ProductFacade,ProductOptionFacade,ProductStatusFacade,UserFacade,EmailFacade,FileFacade,BranchOfficeFacade)

This is the code for the
productDao.find():

public Product find(Integer id) throws DataAccessException {

        Product product= (Product) super.find(Product.class, id);


        if(product!=null){
            product.setProductAttributes(new TreeSet<ProductAttribute>(product.getProductAttributes()));

            for (Product ptp : product.getProducts()){
               ptp.setProductAttributes(new TreeSet<ProductAttribute>(ptp.getProductAttributes()));

             }

         } 

The exception is been thrown right in this line, at the last for:

pptp.setProductAttributes(new TreeSet<ProductAttribute>(ptp.getProductAttributes()))  

in Intelij's debugger, I can see the object wrongly formed from the query:

product.getProducts() = {org.hibernate.collection.PersistentSet@4312}unable to evaluate the expression Method threw 'org.hibernate.LazyInitializationException' exception.

How ever the other attributes are ok. This product doesn´t even have other products in the database.

UPDATE

DIGGING DEEPER on the situation, inside the

product.find(int)

In the line before I get the exception, we can see on the debug that the product.products array has an error, instead of the value you can see the lazyInitialitationException. How ever, if I call it from another method, the array is find. So it can´t be inside of it EVEN though the method only receives an Integer.

Also, we found that this has happened along all the life cycle of the application, some times the staff replicated a method just like it but changing it setting null to this corrupted arrays. So I'm 100% sure this application is consuming more resources then it should.

It has views in Flex, and later views in JSTL where created, and depending who is calling the methods, the exceptions are thrown in different ways for the same methods.

Adding more info. This is how produt.find is implemented in the AbstractDAOImpl:

public final Object find(Class clazz, Integer id) throws DataAccessException{

        return getHibernateTemplate().get(clazz,id);
}

and this is my Transaction Manager configuration, the annotation method described in the first answer by fillip did not work:

<bean id="catalogFacade" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager">
        <ref local="transactionManager"/>
    </property>
    <property name="target">
        <ref local="catalogFacadeTarget"/>
    </property>
    <property name="transactionAttributes">
        <props>
            <prop key="add*">PROPAGATION_REQUIRED</prop>
            <prop key="save*">PROPAGATION_REQUIRED</prop>
            <prop key="update*">PROPAGATION_REQUIRED</prop>
            <prop key="delete*">PROPAGATION_REQUIRED</prop>
            <prop key="remove*">PROPAGATION_REQUIRED</prop>
            <prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>
            <prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop>
            <prop key="contains*">PROPAGATION_SUPPORTS,readOnly</prop>
            <prop key="login*">PROPAGATION_SUPPORTS,readOnly</prop>
        </props>
    </property>
</bean>

解决方案

You're getting a lazy initialization exception because your session is being closed before you access Product's member variables. When the following line is executed:

Product product= (Product) super.find(Product.class, id)

Hibernate opens a sessions, retrieves what you're looking for, then closes then session. Any fields that have lazy=true are not retrieved at this time; instead, these fields are populated by proxies. When you try to retrieve the actual value of proxied object, it will attempt to go back to the database using the active session to retrieve the data. If no session can be found, you get the exception that you're seeing. Setting lazy=true has advantages because it prevents the entire object graph from being loaded immediately; nested objects are left alone until you specifically ask for them.

There are two common techniques to deal with your problem. The first you've already identified, which is setting lazy=false. This is fine if a product always has product attributes, and you typically use a product and it's attributes together. If you often need just the Product object without its attributes, you're creating unnecessary database load.

The second technique is to mark a method as transactional using Spring annotations.

@Transactional
public Product find(Integer id) throws DataAccessException {

}

A few notes:

  1. You need some additional configuration for transactions to work (the @Transactional annotation isn't enough). See here for more information.
  2. Best practices dictate that you annotate methods in your service layer, rather than your data access layer.

这篇关于休眠挂起或抛出延迟初始化没有会话或会话被关闭的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆