2015-09-25 68 views
0

我在Hibernate中遇到LazyInitializationException这个着名的问题。我已经看到很多关于这个问题,但仍然无法解决我的问题。LazyInitializationException问题无法初始化代理 - 无会话

我有一个多对多的关系是这样的:

Teen.java

public class Teen implements Serializable { 

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) 
    @JoinTable(name = "TEEN_FOLLOWER", 
      joinColumns = @JoinColumn(name = "teenEmail"), 
      inverseJoinColumns = @JoinColumn(name = "followerEmail")) 
    private List<Follower> followerList; 
} 

Follower.java

public class Follower implements Serializable { 

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) 
    @JoinTable(name = "TEEN_FOLLOWER", 
      joinColumns = @JoinColumn(name = "followerEmail"), 
      inverseJoinColumns = @JoinColumn(name = "teenEmail")) 
    private List<Teen> teenList; 
} 

一个十几岁的有ñ追随者和一个跟随者可以按照n青少年。

我在我的数据库中已经有一些条目了,我正在从中取出所有的青少年。

List<Teen> teens = (List<Teen>) teenDao.findAll(); 

for (Teen item : teens) { 
    System.out.println("teen " + item.getEmail()); 
    List<Follower> followers = item.getFollowerList(); 
    for (Follower follower : followers) { 
     System.out.println("follower " + follower.getEmail()); 
    } 
} 

当我尝试读取从getFollowerList()方法获得的追随者列表时,上述代码出现异常。

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.capstone.server.model.Teen.followerList, could not initialize proxy - no Session 
    org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:572) 
    org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:212) 
    org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:551) 
    org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:140) 
    org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:294) 
    com.capstone.server.controller.TeenController.visualizar(TeenController.java:38) 
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    java.lang.reflect.Method.invoke(Method.java:606) 
    org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:214) 
    org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132) 
    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) 
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:748) 
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:689) 
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83) 
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:945) 
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:876) 
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:931) 
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:822) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:622) 
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:807) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:729) 
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) 

真的不知道该做什么了。我已经尝试在我的导致错误的方法中添加@Transaction注释,并且这可以工作。然而,当我将青少年对象发送给我的android应用程序时,在将对象转换为json时出现相同的异常。

我的配置文件是:

的servlet-context.xml的

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

    <!-- DispatcherServlet Context: defines this servlet's request-processing 
     infrastructure --> 

    <!-- Enables the Spring MVC @Controller programming model --> 
    <annotation-driven /> 

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving 
     up static resources in the ${webappRoot}/resources directory --> 
    <resources mapping="/resources/**" location="/resources/" /> 

    <!-- Resolves views selected for rendering by @Controllers to .jsp resources 
     in the /WEB-INF/views directory --> 
    <beans:bean 
     class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 
     <beans:property name="prefix" value="/WEB-INF/views/" /> 
     <beans:property name="suffix" value=".jsp" /> 
    </beans:bean> 

    <beans:bean id="messageSource" 
     class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> 
     <beans:property name="basename" value="classpath:messages" /> 
     <beans:property name="defaultEncoding" value="UTF-8" /> 
    </beans:bean> 

    <beans:bean id="localeResolver" 
     class="org.springframework.web.servlet.i18n.CookieLocaleResolver"> 
     <beans:property name="defaultLocale" value="en" /> 
     <beans:property name="cookieName" value="myAppLocaleCookie"></beans:property> 
     <beans:property name="cookieMaxAge" value="3600"></beans:property> 
    </beans:bean> 

    <interceptors> 
     <beans:bean 
      class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"> 
      <beans:property name="paramName" value="locale" /> 
     </beans:bean> 
    </interceptors> 

    <!-- Configure to plugin JSON as request and response in method handler --> 
    <beans:bean 
     class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> 
     <beans:property name="messageConverters"> 
      <beans:list> 
       <beans:ref bean="jsonMessageConverter" /> 
      </beans:list> 
     </beans:property> 
    </beans:bean> 

    <!-- Configure bean to convert JSON to POJO and vice versa --> 
    <beans:bean id="jsonMessageConverter" 
     class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> 
    </beans:bean> 

    <!-- Enable @Transactional annotation --> 
    <tx:annotation-driven /> 

    <mvc:interceptors> 
     <beans:bean class="com.capstone.server.interceptor.LoginInterceptor" /> 
    </mvc:interceptors> 

    <beans:bean id="multipartResolver" 
     class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> 

     <!-- Setting maximum upload size --> 
     <beans:property name="maxUploadSize" value="1000000" /> 
    </beans:bean> 

    <context:component-scan base-package="com.capstone.server" /> 

</beans:beans> 

PersistenceJPAConfig.java

@Configuration 
@EnableTransactionManagement 
@PropertySource("classpath:application.properties") 
public class PersistenceJPAConfig { 

    @Resource 
    private Environment env; 

    @Bean 
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() { 
     LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); 
     em.setDataSource(dataSource()); 
     em.setPackagesToScan(new String[] { 
       Constants.PACKAGE_NAME 
     }); 

     JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); 
     em.setJpaVendorAdapter(vendorAdapter); 
     em.setJpaProperties(additionalProperties()); 

     return em; 
    } 

    @Bean 
    public DataSource dataSource() { 
     DriverManagerDataSource dataSource = new DriverManagerDataSource(); 

     // Connection data 
     dataSource.setDriverClassName(env.getRequiredProperty("db.driver")); 
     dataSource.setUrl(env.getRequiredProperty("db.url")); 
     dataSource.setUsername(env.getRequiredProperty("db.username")); 
     dataSource.setPassword(env.getRequiredProperty("db.password")); 
     return dataSource; 
    } 

    @Bean 
    public PlatformTransactionManager transactionManager(EntityManagerFactory emf) { 
     JpaTransactionManager transactionManager = new JpaTransactionManager(); 
     transactionManager.setEntityManagerFactory(emf); 

     return transactionManager; 
    } 

    @Bean 
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() { 
     return new PersistenceExceptionTranslationPostProcessor(); 
    } 

    Properties additionalProperties() { 
     Properties properties = new Properties(); 

     // Hibernate properties 
     properties.setProperty("hibernate.dialect", env.getRequiredProperty("hibernate.dialect")); 
     properties.setProperty("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql")); 
     properties.setProperty("hibernate.format_sql", 
       env.getRequiredProperty("hibernate.format_sql")); 

     // Updates the database and generate tables, if needed 
     properties.setProperty("hibernate.hbm2ddl.auto", 
       env.getRequiredProperty("hibernate.hbm2ddl.auto")); 

     // Initializes database with admin entry in User table 
     properties.setProperty("hibernate.hbm2ddl.import_files", 
       env.getRequiredProperty("hibernate.hbm2ddl.import_files")); 
     properties.setProperty("hibernate.hbm2ddl.import_files_sql_extractor", 
       env.getRequiredProperty("hibernate.hbm2ddl.import_files_sql_extractor")); 

     return properties; 
    } 
} 
+4

的可能重复[:LazyInitializationException中:休眠无法初始化代理(http://stackoverflow.com/questions/345705/hibernate-lazyinitializationexception-could-not-initialize-proxy)是否使用杰克逊发送对象 – Hannes

+0

Json符号给客户端? –

+0

是的,我使用杰克逊..检查在servlet-context.xml - > MappingJackson2HttpMessageConverter –

回答

1

这里是我最后做的方式:

相反我只有一个teenDao.findAll()其获取只有懒数据的方法,我创造了一个又一个接收一个布尔PARAM forceLoad。实现是这样的:

@Transactional 
public Teen find(String email) { 
    return find(email, false); 
} 

@Transactional 
public Teen find(String email, boolean forceLoad) { 
    Teen teen = em.find(Teen.class, email); 
    if(teen != null && forceLoad) { 
     Hibernate.initialize(teen.getUser()); 
     Hibernate.initialize(teen.getFollowerList()); 
     Hibernate.initialize(teen.getPendingFollowerList()); 
     Hibernate.initialize(teen.getCheckInList()); 
    } 
    return teen; 
} 

有了这个,我只初始化时传递forceLoad为真我的愿望清单。

-1
public class Teen implements Serializable { 

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) 
    @JoinTable(name = "TEEN_FOLLOWER", 
      joinColumns = @JoinColumn(name = "teenEmail"), 
      inverseJoinColumns = @JoinColumn(name = "followerEmail")) 
    private List<Follower> followerList; 
} 

可以获取类型渴望,而不是懒惰。

它将在加载父对象时获取所有子对象。

但它会导致性能问题。

其他的解决方案,您可以尝试每个请求模式会话

http://docs.jboss.org/hibernate/orm/4.2/devguide/en-US/html/ch02.html

+0

感谢您的回答,但不幸的是,使用EAGER不是我的选择..它可以导致严重的性能问题,因为我不想总是抓取所有青少年的追随者。 –

+0

@FelipeMosso雅我接受一个...否则,您可以使用会议每个请求来解决这个 –

+0

@FelipeMosso请检查链接https://skysoftarchive.wordpress.com/2009/07/14/implementing-hibernates-session-每个请求模式使用弹簧mvc/ –

0

你必须扩大你的事务上下文,这样的代理可以抓住实体的关系数据的其余部分:

@Transactional 
public void foo() { 
    List<Teen> teens = (List<Teen>) teenDao.findAll(); 

    for (Teen item : teens) { 
    ... 
    } 
} 
+0

是的,我这样做..这工作起初..但后来当我发送列表到互联网(从foo()方法返回)我得到相同的LazyInitializationException再次.. –

+0

这就是服务层的用途。您不能在交易边界之外交付实体。复制你需要的数据到pojos然后传递到更高层。 – Hannes

+0

@Transaction没有其他选择吗? –

0

另一种方式是让你的领域延迟加载,并通过像这样的查询: * from Teen t JOIN FECTH t.teenList followerList

问候,

FT

0

有交易,当你有一个懒惰的领域,你不能把这个字段的值,因为你是在交易之外,你的会话已经释放。

一种方法,将控件上的事件注释或代理控件的东西放入标记为Transactionnal的服务类中,然后在此服务类的方法中进行操作。

当然你不能在事务外调用一个懒惰的字段。

问候,

相关问题