当我运行以下代码时,我继续收到此错误“线程中的异常”主“org.hibernate.LazyInitializationException:无法初始化代理 - 拥有的会话已关闭”:
public ArrayList<ProfileDTO> getInitialProfiles(Contracts ct){
SessionFactory sessionFactory=new Configuration().configure().buildSessionFactory();
Session session=sessionFactory.openSession();
Transaction tx=session.beginTransaction();
ArrayList<ProfileDTO> profileDTOs=new ArrayList<ProfileDTO>();
try{
Hibernate.initialize(ct);
SQLQuery query=session.createSQLQuery("select {b.*},{p.*},{t.*} from bidtool.bt_boiler_plates b,bidtool.bt_profile p,bidtool.bt_trade_lane t where b.contract_id=:val AND p.contract_id=:val AND t.contract_id=:val")
.addEntity("b",Boiler_Plates.class)
.addEntity("p",BidToolProfiles.class)
.addEntity("t",BidToolTradeLanes.class);
query.setParameter("val", ct.getContract_id());
List list=query.list();
Iterator iteContract = list.iterator();
while ( iteContract.hasNext() ) {
Object[] pair =(Object[]) iteContract.next();
Boiler_Plates bp=(Boiler_Plates)pair[0];
BidToolProfiles p=(BidToolProfiles)pair[1];
ProfileDTO profileDTO=new ProfileDTO();
profileDTO.setProfileId(p.getProfileId());
profileDTO.setBt_contracts(p.getBt_contracts());
profileDTO.setCreated(p.getCreated());
profileDTO.setProfileContent(p.getProfileContent());
profileDTO.setEditable(p.getEditable());
profileDTO.setProfileName(p.getProfileName());
profileDTOs.add(profileDTO);
}
return profileDTOs;
}
catch(Exception ex){
System.out.println(ex.getMessage());
return profileDTOs;
}
finally{
session.flush();
session.close();
}
}
每当我不关闭会话时它都能正常工作但我不能这样做。我需要关闭会话。我们将不胜感激。谢谢。
答案 0 :(得分:5)
在会话关闭后访问hibernate实体中的关联或集合时会引发错误。看看你的代码,我猜这个问题可能在于以下几行:
profileDTO.setBt_contracts(p.getBt_contracts());
当您尝试从其他会话中的代码中的其他位置访问此集合时。
尝试将您的查询更改为:
select {b.*},{p.*},{t.*} from bidtool.bt_boiler_plates b,bidtool.bt_profile p,bidtool.bt_trade_lane t left join fetch p.bt_contracts btcontracts where b.contract_id=:val AND p.contract_id=:val AND t.contract_id=:val
请注意,我在集合中添加了一个连接提取。这应该确保在获取BidToolProfiles
实体的同时获取合同集合。在DTO中设置之前,请尝试初始化集合。
Hibernate.initialize(p.getBt_contracts());
profileDTO.setBt_contracts(p.getBt_contracts());
答案 1 :(得分:3)
好吧,您需要在会话关闭后初始化您计划使用的每个对象。
假设您的User实体与其地址具有OneToOne延迟关联。并假设您在会话打开时加载用户。由于地址是延迟加载的,所以第一次调用地址上的方法(例如user.getAddress().getStreet()
)时,Hibernate将执行查询以加载用户的地址,从而能够为您提供访问权限到它的街道。但是如果会话关闭,则不再与数据库建立连接,用户实体被分离,因此Hibernate会抛出此异常。
使用Hibernate.initialize()
初始化您需要的对象,或执行具有必要提取的查询以一次加载所需的所有内容。
旁注:您的异常处理非常糟糕。当被要求返回配置文件时,而不是说:“抱歉,但由于以下异常而无法执行此操作”,您基本上忽略了该异常并说“数据库中没有配置文件”。请想象一下癌症检测系统就是这样运作的。您是否希望您的癌症未被发现,因为该系统有例外?
答案 2 :(得分:0)
你是如何使用这种方法的?你的映射是什么样的?你有什么属性启用延迟加载?这是一个网络应用程序?您正在创建一个ProfileDTO但是getBt_contracts呢。这将从“启用会话”的BidToolProfiles中返回内容,因此如果在该方法返回后访问延迟加载的属性,则会出现此错误。
这只是我认为错误的一个例子,因为我看不到你的映射。这里重要的是,在延迟加载所有需要执行所需任务的属性后,会话应该关闭。
再次 - 取决于这是否是一个Web应用程序,您可以选择不同的会话m管理策略(Web应用程序上的每个请求会话,如果它是桌面应用程序的每个线程会话等)
答案 3 :(得分:0)
使用session.merge()
将从旧会话加载的实例与新会话合并。顺便说一句,这意味着Hibernate再次从数据库加载实体。
另一种可能性是避免延迟加载 - 无论是在映射中还是在会话仍然打开时访问必要的值(即使在那一刻不需要值)。