2012-06-08 2 views
1

У меня проблема с ленивой инициализацией. Я не могу найти решение.spring, hibernate: не удалось лениво инициализировать коллекцию

Исключение:

[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. продержать сессию открытым (Google для связывания спящего режима сеанса нитки, или если метод readStatusCache в весеннем управляемом объекте, просто добавьте @Transactional аннотации к нему, или точка входа, из которой она вызывается).
  2. Измените коллекцию приложений на нужную нагрузку
  3. У вас есть dao-слой, полностью инициализирующий коллекцию приложений (см. Метод Hibernate.initialize), пока сеанс все еще открыт.
+0

Спасибо за ответ. Проблема в том, что он работал на одном серверном кластере, а другой - на другом. хорошие рекомендации на этом этапе, я попробую позже. – spinner0815

+0

Спасибо за такое ясное решение ... Это был кошмар для меня (обыскали по интернету в течение 2 часов). Основная проблема для меня в том, что я не мог сделать 1 (метод был вне весеннего объекта) PLUS Я работаю над настольным приложением. Я пошел с 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

Я не знаю, правильно ли использую транзакцию и т. Д. Я новичок, используя весну и спящий режим. Класс ScheduledProcessor, в котором используется метод readStatusCache(), аннотируется как Transactional, а serviceFacade - Transactional. Также я попытался синхронизировать readStatusCache(), но исключение все еще существует. Также проект использует «GenericDaoImpl extends HibernateDaoSupport». Надеюсь, ты знаешь, что я имею в виду. – spinner0815

+0

Кажется, все в порядке.Единственная причина, по которой я могу думать о том, чтобы бросить ваш стек, - вот что. Так что я все-таки боевой патрон. Удачи .... – Thihara

0

Когда я получил то же исключение, решение заключалось в добавлении аннотации @Transactional к методу в контроллере.

Смежные вопросы