2013-11-18 5 views
0

Я не могу понять это. Am get «Исключение из потока» main «org.hibernate.LazyInitializationException: не удалось лениво инициализировать коллекцию роли: org.sandy.domain.Location.items, сеанс или сеанс закрыты» Я понимаю, что сеанс закрыт но tx: annotation-driver @Transactional должен обеспечить открытый сеанс. Он отлично работает с извлечением EAGER. О, да, это - пример из весны 3 примера.Исключение LazyLoadInit с Spring + Spring JPA data + hibernate

Но, может быть, я не понимаю эту концепцию - я имею в виду, когда я отлаживаю «getFirst()» в SomeService. Я могу видеть все элементы в коллекции, но после обратных ударов - исключение LazyInit выбрано ...

package org.sandy.main; 

    import org.sandy.domain.Item; 
    import org.sandy.domain.Location; 
    import org.springframework.beans.factory.annotation.Autowired; 
    import org.springframework.context.support.GenericXmlApplicationContext; 
    import org.springframework.stereotype.Service; 

@Service(value = "main") 
public class EntryPoint { 

    @Autowired 
    private SomeService ss; 

    public static void main(String args[]) { 
     GenericXmlApplicationContext ctx = new GenericXmlApplicationContext(); 
     ctx.load("classpath:*-beans.xml"); 
     ctx.refresh(); 

     EntryPoint entryPoint = (EntryPoint) ctx.getBean("main"); 

     Item item = new Item(); 
     Location location = new Location(); 

     item.setLocation(location); 
     location.getItems().add(item); 

     entryPoint.getSs().save(location); 

     System.out.println(entryPoint.getSs().findFirst()); 

     ctx.registerShutdownHook(); 
    } 

    public SomeService getSs() { 
     return ss; 
    } 

    public void setSs(SomeService ss) { 
     this.ss = ss; 
    } 
} 

и сервис

package org.sandy.main; 

import org.sandy.domain.Item; 
import org.sandy.domain.Location; 
import org.sandy.repo.ItemRepo; 
import org.sandy.repo.LocationRepo; 
import org.springframework.beans.factory.annotation.Autowire; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.stereotype.Repository; 
import org.springframework.stereotype.Service; 
import org.springframework.transaction.annotation.Transactional; 

import java.util.List; 

@Service(value = "ss") 
@Repository 
@Transactional 
public class SomeService { 
    @Autowired 
    private ItemRepo itemRepo; 
    @Autowired 
    private LocationRepo locationRepo; 

    @Transactional 
    public void save(Location location) { 
     locationRepo.save(location); 
    } 

    @Transactional(readOnly = true) 
    public List<Item> findFirst() { 
     System.out.println("ONE"); 
     Iterable<Location> it = locationRepo.findAll(); 
     System.out.println("TWO"); 
     Location l = it.iterator().next(); 
     System.out.println("THREE"); 
     List<Item> r = l.getItems(); 
     return r; 
    } 

    @Transactional 
    public Iterable finAll() { 
     return locationRepo.findAll(); 
    } 

    public void setItemRepo(ItemRepo itemRepo) { 
     this.itemRepo = itemRepo; 
    } 

    public void setLocationRepo(LocationRepo locationRepo) { 
     this.locationRepo = locationRepo; 
    } 
} 

и расположение репо

package org.sandy.repo; 

import org.sandy.domain.Location; 
import org.springframework.data.repository.CrudRepository; 

public interface LocationRepo extends CrudRepository<Location, Long> { 
} 

Объекты:

@Entity 
@Table(name = "Locations") 
public class Location extends Entry { 

    private List<Item> items = new ArrayList<Item>(); 

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "location") 
    public List<Item> getItems() { 
     return items; 
    } 

    public void setItems(List<Item> items) { 
     this.items = items; 
    } 
} 

package org.sandy.domain; 

import javax.persistence.*; 

@Entity 
@Table(name = "Items") 
public class Item extends Entry { 
    private Location location; 

    @ManyToOne(cascade = CascadeType.ALL) 
    @JoinColumn() 
    public Location getLocation() { 
     return location; 
    } 

    public void setLocation(Location location) { 
     this.location = location; 
    } 
} 

И все могучее XML боб конфигурации:

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc" 
     xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" 
     xmlns:jpa="http://www.springframework.org/schema/data/jpa" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> 

    <jdbc:embedded-database id="dataSource" type="H2" /> 

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
     <property name="entityManagerFactory" ref="emf"/> 
    </bean> 

    <tx:annotation-driven transaction-manager="transactionManager" /> 

    <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" > 
     <property name="dataSource" ref="dataSource" /> 
     <property name="jpaVendorAdapter"> 
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" /> 
     </property> 
     <property name="packagesToScan" value="org.sandy.domain" /> 
     <property name="jpaProperties"> 
      <props> 
       <prop key="hibernate.dialect"> 
        org.hibernate.dialect.H2Dialect 
       </prop> 
       <prop key="hibernate.max_fetch_depth">3</prop> 
       <prop key="hibernate.jdbc.fetch_size">50</prop> 
       <prop key="hibernate.jdbc.batch_size">10</prop> 
       <prop key="hibernate.show_sql">true</prop> 
       <prop key="hibernate.hbm2ddl.auto">create</prop> 
       <prop key="hibernate.enable_lazy_load_no_trans">true</prop> 
      </props> 
     </property> 
    </bean> 

    <context:annotation-config/> 

    <jpa:repositories base-package="org.sandy.repo" entity-manager-factory-ref="emf" transaction-manager-ref="transactionManager" /> 

    <context:component-scan base-package="org.sandy" /> 
</beans> 
+0

В вашем классе 'Item' есть метод' toString() '? –

+0

Да, в этом примере нет - это просто для шоу и рассказать. – Xeperis

+0

Это действительно актуально, можете ли вы опубликовать его? –

ответ

2

Этот фрагмент кода

System.out.println(entryPoint.getSs().findFirst()); 

эквивалентно

/* 1 */ SomeService ss = entryPoint.getSs(); 
/* 2 */ List<Item> items = ss.findFirst(); // Session opens and closes for @Transactional 
/* 3 */ String toPrint = items.toString(); // no more Session 
/* 4 */ System.out.println(toPrint); 

Таким образом, вы можете видеть, что Session граница включена завернув вызов findFirst(). Если вы загружаете свои объекты лениво, то в строке 3 элементы в items не инициализируются. Когда вы пытаетесь позвонить toString() внутри List#toString(), который вызывает toString() на каждый элемент, вы получите LazyInitializationException.

Вы должны полностью инициализировать свои объекты перед их использованием. Это должно быть сделано в границах сеанса.

+1

У меня возникло недоразумение о том, как загружается загрузка LAZY - я представил себе, что он будет извлекать все зарубежные записи по запросу после транзакции, когда захочу, получается нет. – Xeperis

+0

@xe Я не знаю, планируете ли вы переносить это в веб-среду, но есть вещи, которые вы можете сделать, чтобы сеанс обертывал всю вашу логику, а не только один метод. Помните сеанс! = Транзакция –

+0

Это на самом деле сволочь, но все же привело меня к пониманию шаблона сеанса за запрос. И да, это будет веб-приложение. Поэтому мой последний вопрос: должен ли я управлять своим подразделением, правильно настроив атрибуты изоляции и распространения методов @Transactional, для каждого запроса для достижения требуемых целей? Я просто пытаюсь привести себя в правильное мышление. – Xeperis