我正在增强一个旧的Spring/Hibernate应用程序并且卡住了.我有一个方法,读取3000多行的文件,每行有一个记录,必须与数据库上的东西进行比较,然后必须将一个寄存器添加到数据库(多对多表).
表和关系是
分公司有很多产品,产品分布在很多分公司.
产品有很多产品,而且一个类别有很多产品
还有更多的桌子在那里工作正常.
我创建的新表/对象是Branch,Product,BranchToProduct.
产品有一组BranchToProduct对象,它们有3个字段
我需要将BranchToProduct对象添加到Product集合中,从我从文件的每一行获得的信息填充3个字段.
我添加一个简单的行,应用程序抛出:
product = productDAO.findByModel(stringModel);
未能懒惰地初始化角色集合:com.bamboo.catW3.domain.Product.products,没有会话或会话被关闭
如果我去hibernate映射(hbm文件)并设置关系product_to_products lazy = false,该行单独运行,但如果我尝试将它放在文件循环中,应用程序将始终挂起正在处理的第18行,不会无论我使用哪个文件或内容的顺序,控制台都停止工作,必须关闭java查杀进程.
无论哪种方式,在调试中,我得到了很多HQL用于简单的查找,13行HQL,直到我在lazy = true时得到我的错误,并且当我使用lazy = false并将其放在循环上时有很多行.
我想我应该尝试用lazy = true解决问题.
这种情况让我想知道:
1.-当懒惰=真.为什么我不能运行此命令的这一行的单行,但它在该类的其他方法上工作正常?
顺便说一下,这是一个名为CatalogFacade的类,它实现了其他clasess的方法:(CategoryFacade,ContainerFacade,ProductFacade,ProductOptionFacade,ProductStatusFacade,UserFacade,EmailFacade,FileFacade,BranchOfficeFacade)
这是
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()));
}
}
Run Code Online (Sandbox Code Playgroud)
在这一行中抛出了异常,最后是:
pptp.setProductAttributes(new TreeSet<ProductAttribute>(ptp.getProductAttributes()))
Run Code Online (Sandbox Code Playgroud)
在Intelij的调试器中,我可以看到查询错误地形成的对象:
product.getProducts()= {org.hibernate.collection.PersistentSet@4312}无法评估表达式方法抛出'org.hibernate.LazyInitializationException'异常.
其他属性怎么样都没问题.该产品甚至没有数据库中的其他产品.
UPDATE
深入了解情况,内心深处
product.find(INT)
在我得到异常之前的行中,我们可以在调试中看到product.products数组有错误,而不是您可以看到lazyInitialitationException的值.但是,如果我从另一个方法调用它,则会找到该数组.所以即使该方法仅接收整数,它也不能在其内部.
此外,我们发现这已经发生在应用程序的所有生命周期中,有时候工作人员复制了一个类似于它的方法,但是更改它将null设置为此损坏的数组.所以我100%确定这个应用程序正在消耗更多的资源.
它在Flex中有视图,后来在JSTL中创建了视图,并且根据谁调用方法,对于相同的方法,异常以不同的方式抛出.
添加更多信息.这就是在AbstractDAOImpl中实现produt.find的方法:
public final Object find(Class clazz, Integer id) throws DataAccessException{
return getHibernateTemplate().get(clazz,id);
}
Run Code Online (Sandbox Code Playgroud)
这是我的事务管理器配置,由fillip在第一个答案中描述的注释方法不起作用:
Run Code Online (Sandbox Code Playgroud)<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>
Fil*_*Fil 28
您正在获得延迟初始化异常,因为在访问Product的成员变量之前会话正在关闭.执行以下行时:
Product product= (Product) super.find(Product.class, id)
Run Code Online (Sandbox Code Playgroud)
Hibernate打开会话,检索您要查找的内容,然后关闭会话.此时不检索任何lazy = true的字段; 相反,这些字段由代理填充.当您尝试检索代理对象的实际值时,它将尝试使用活动会话返回到数据库以检索数据.如果找不到会话,您将获得您所看到的例外情况.设置lazy = true具有优势,因为它可以防止立即加载整个对象图; 嵌套对象保持不变,直到您特别要求它们为止.
有两种常用技巧可以解决您的问题.你已经确定的第一个,即设置lazy = false.如果产品始终具有产品属性,并且您通常使用产品及其属性,则这很好.如果您经常只需要没有其属性的Product对象,那么您将创建不必要的数据库负载.
第二种技术是使用Spring注释将方法标记为事务.
@Transactional
public Product find(Integer id) throws DataAccessException {
}
Run Code Online (Sandbox Code Playgroud)
几点说明:
我以前也遇到过同样的问题,并通过使用不同的休眠方法修复了它。我用
getHibernateTemplate().loadAll(class)
Run Code Online (Sandbox Code Playgroud)
为了得到所有的东西,并且
getHibernateTemplate().get(class, id)
Run Code Online (Sandbox Code Playgroud)
找到一个单一的东西。这两个我用起来都没有问题。我发现 .find() 给了我会话已关闭错误。
我还没有真正研究过这是为什么。
除了使用另一种方法之外,我能想到的唯一其他选择是自己打开和关闭会话,但我认为您不喜欢这样做。
| 归档时间: |
|
| 查看次数: |
41762 次 |
| 最近记录: |