2012-06-08 37 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註釋添加到控制器中的方法中。

相關問題