Issue with LazyInitializationException could not initialize proxy - no Session
我在Hibernate中遇到了LazyinitializationException的这个著名问题。我已经看到很多关于这个的问题,但仍然不能解决我的问题。
我有这样一种多对多的关系:
java青少年
1 2 3 4 5 6 7 8 | 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; } |
追随者.java
1 2 3 4 5 6 7 8 | 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个追随者,一个追随者可以跟踪N个青少年。
我的数据库中已经有一些条目,我正在从中提取所有的青少年。
1 2 3 4 5 6 7 8 9 |
当我试图读取getFollowerList()方法得到的关注者列表时,上面的代码出现了异常。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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) |
。
真的不知道该怎么办了。我已经尝试在我的方法中添加
我的配置文件是:
servlet-context.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | <?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 --> <!-- 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> |
持久jpaconfig.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | @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; } } |
。
我最终是这样做的:
相反,我只有一个仅获取惰性数据的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | @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; } |
这样,当传递
对于事务,当您有一个懒惰的字段时,您无法获取该字段的值,因为您在事务之外,并且您的会话已被释放。
一种方法,将Transactional注释放在Controller上,或者将Controller的内容委托给标记为Transactional的服务类,并在此服务类的方法中进行操作。
当然,不能在事务外部调用惰性字段。
当做,
另一种方法是让您的字段具有延迟加载,并传递这样的查询:*从青少年加入fecth t.teenlist followerlist
当做,
英尺
您必须扩大事务上下文,以便代理可以获取实体的其余关系数据:
1 2 3 4 5 6 7 8 | @Transactional public void foo() { List<Teen> teens = (List<Teen>) teenDao.findAll(); for (Teen item : teens) { ... } } |
号
1 2 3 4 5 6 7 8 | 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