2012-06-08 161 views
1

我有懒惰的初始化问题。我找不到解决方案。春天,休眠:未能懒洋洋地初始化集合

例外:

[pool-1-thread-12] ERROR:12:20:14.840 o.h.LazyInitializationException - failed to lazily initialize a collection of role: de.beeld.forges.domain.Server.applications, no session or session was closed 
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: de.beeld.forges.domain.Server.applications, no session or session was closed 
    at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380) 
    at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372) 
[pool-2-thread-1] ERROR:12:20:14.840 o.s.s.support.MethodInvokingRunnable - Invocation of method 'readStatusCache' on target class [class de.beeld.forges.task.annotation.ScheduledProcessor$$EnhancerByCGLIB$$ee649dc3] failed 
java.util.ConcurrentModificationException: null 
    at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372) 
    at java.util.AbstractList$Itr.next(AbstractList.java:343) 

hibernate.xml

<!-- Hibernate SessionFactory --> 
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" 
    p:dataSource-ref="standardDataSource" p:lobHandler-ref="defaultLobHandler"> 
    <property name="annotatedClasses"> 
     <list> 
      <value>de.beeld.forges.domain.Server</value> 
      <value>de.beeld.forges.domain.Application</value> 
      <value>de.beeld.forges.domain.Forge</value> 
     </list> 
    </property> 
</property> 
</bean> 
<bean id="defaultLobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler" /> 
<!-- Read in DAOs from the hibernate package --> 
<context:component-scan base-package="de.beeld.forges.dao" /> 
<bean id="transactionManager" 
    class="org.springframework.orm.hibernate3.HibernateTransactionManager" 
    p:sessionFactory-ref="sessionFactory" /> 

<bean id="transactionTemplate" 
    class="org.springframework.transaction.support.TransactionTemplate"> 
    <property name="transactionManager" ref="transactionManager" /> 
</bean> 

<tx:annotation-driven transaction-manager="transactionManager" /> 
    <context:component-scan base-package="de.beeld"> 
    <context:exclude-filter expression="org.springframework.stereotype.Controller" 
     type="annotation" /> 
    <context:exclude-filter expression="org.springframework.stereotype.Repository" 
     type="annotation" /> 
</context:component-scan> 
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" /> 

readStatusCache方法:

public void readStatusCache() { 
    String execCommand = "java -jar ..."; 
    List<Future<Map<Long, Integer>>> list = new ArrayList<Future<Map<Long, Integer>>>(); 
    String serverName = null; 
    for (Server server : serviceFacade.getServers()) { 
     serverName = server.getName(); 

     Callable<Map<Long, Integer>> worker = new ApplicationStatusReader2(server.getApplications(), 
       sshConnector, execCommand, serverName); 
     Future<Map<Long, Integer>> submit = this.serviceFacade.getExecutor().submit(worker); 
     list.add(submit); 
    } 

    for (Future<Map<Long, Integer>> future : list) { 
     //do stuff 
    } 
} 

Server.java

@Entity 
@org.hibernate.annotations.Entity(dynamicUpdate = true) 
public class Server implements DomainObject, Comparable<Server> { 
private static final long serialVersionUID = -8920952435734596243L; 

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

@Column(unique = true, nullable = false) 
@NotEmpty 
private String name; 

@Column(nullable = false) 
@NotEmpty 
@Pattern(regexp = "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])$", message = "The ip must be in format xxx.xxx.xxx.xxx") 
private String ip; 

@Column(nullable = false) 
@NotEmpty 
private String fqdn; 

@OneToMany(mappedBy = "server", fetch = FetchType.LAZY) 
private List<Application> applications; 

@Version 
private int version; 

//getter and setter 
} 

Application.java

@Entity 
public class Application implements DomainObject { 
private static final long serialVersionUID = -8127137156319959239L; 
@Id 
@GeneratedValue(strategy = GenerationType.IDENTITY) 
private Long id; 
@ManyToOne(fetch = FetchType.LAZY) 
private Server server; 
@Column(nullable = false) 
@NotEmpty 
private String name; 
@Column(nullable = false) 
@NotEmpty 
private String location; 
@Column(nullable = false) 
@NotEmpty 
private String binDir; 
private String confDir; 
private boolean isContainer = false; 
private String containerDir; 
private String startup = "startup.sh"; 
private String shutdown = "shutdown.sh"; 
@ManyToOne(fetch = FetchType.LAZY) 
@Fetch(FetchMode.JOIN) 
private Forge forge; 
@ManyToOne(fetch = FetchType.LAZY) 
@Fetch(FetchMode.JOIN) 
private Application parent; 
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY) 
private List<Application> offsprings; 
@NotEmpty 
private String blueprint; 
private Integer replaceable = 0; 
private Integer running = 0; 
@Version 
private int version; 

//getter and setter 
} 

我真的不知道为什么我不能从服务器

阅读应用程序列表中如果有人能够帮助这将是巨大的。

回答

3

很可能是因为您将应用程序集合设置为延迟加载。因此,当您从初始调用返回serviceFacade.getServers()时,我的猜测是您不再打开用于获取服务器列表的会话。

因此,当您通过应用程序进行迭代时,会话已关闭,因此无法加载集合的实际内容。

你有三种可能性:

  1. 保持会议开幕(谷歌的结合Hibernate的Session线程,或者如果readStatusCache方法是在弹簧管理对象,只是增加一个@Transactional注释,或它被称为的入口点)。
  2. 将应用程序集合更改为热切负载
  3. 当会话仍处于打开状态时,让您的dao层完全初始化应用程序集合(请参阅Hibernate.initialize方法)。
+0

谢谢你的答案。问题在于它在一个服务器群集上工作,而没有在另一个服务器群集上工作。好的建议在这一点上,我会尝试以后 – spinner0815

+0

感谢这样一个明确的解决方案...这是我的噩梦(搜索了2个小时的互联网)。对我来说主要问题是我不能做1(方法是在春天对象之外)加上我正在开发桌面应用程序。我去了Hibernate.initialize(myModel.getRelatedCollection());哪些工作正常 – kosta5

0

两个环路

for (Server server : serviceFacade.getServers()) { 
     serverName = server.getName(); 

     Callable<Map<Long, Integer>> worker = new ApplicationStatusReader2(server.getApplications(), 
       sshConnector, execCommand, serverName); 
     Future<Map<Long, Integer>> submit = this.serviceFacade.getExecutor().submit(worker); 
     list.add(submit); 
    } 

    for (Future<Map<Long, Integer>> future : list) { 
     //do stuff 
    } 

正在被同时两个单独的线程调用。您可以通过同步readStatusCache()方法来检查是否属于这种情况。但是这应该在Spring层完成。您是否正确使用交易等?

请阅读本答案以获取有关弹簧和休眠时线程安全性的更多信息。 Spring-Hibernate used in a webapp,what are strategies for Thread safe session management

+0

我不知道我是否正确使用交易等。我是通过使用spring和hibernate来创建新的。其中readStatusCache()方法的类ScheduledProcessor被注释为Transactional,而serviceFacade也是Transactional。此外,我试图同步readStatusCache(),但异常仍然存在。 此外,该项目使用'GenericDaoImpl扩展HibernateDaoSupport'。我希望你明白我的意思。 – spinner0815

+0

看起来没问题。我能想到抛出你的堆栈跟踪的唯一原因是这样的。所以我都是outa弹药伴侣。祝你好运.... – Thihara

0

当我遇到同样的异常时,解决方案是将@Transactional注释添加到控制器中的方法中。

相关问题