Java LazyInitializationException问题无法初始化代理-无会话
我在hibernate中遇到了一个著名的LazyInitializationException问题。我已经看到了很多关于这个的问题,但仍然不能解决我的问题 我有这样一种多对多的关系:Java LazyInitializationException问题无法初始化代理-无会话,java,json,hibernate,spring-mvc,jackson,Java,Json,Hibernate,Spring Mvc,Jackson,我在hibernate中遇到了一个著名的LazyInitializationException问题。我已经看到了很多关于这个的问题,但仍然不能解决我的问题 我有这样一种多对多的关系: @Transactional public Teen find(String email) { return find(email, false); } @Transactional public Teen find(String email, boolean forceLoad) { Teen
@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;
}
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;
}
真的不知道该怎么办了。我已经尝试在我的方法中添加@Transaction
注释,这导致了错误,并且成功了。但是,当我将Teen对象发送到我的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>
public类实现可序列化{
@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
@JoinTable(name=“TEEN\u FOLLOWER”,
joinColumns=@JoinColumn(name=“teenEmail”),
inverseJoinColumns=@JoinColumn(name=“followerMail”))
私有列表跟随列表;
}
您可以获取类型eager而不是lazy
它将在加载父对象时获取所有子对象
但这会导致性能问题
其他解决方案可以尝试按请求会话模式
您必须拓宽事务上下文,以便代理可以获取实体的其余关系数据:
@Transactional
public void foo() {
List<Teen> teens = (List<Teen>) teenDao.findAll();
for (Teen item : teens) {
...
}
}
@Transactional
公共图书馆{
List teenties=(List)tendao.findAll();
适用于(青少年项目:青少年){
...
}
}
另一种方法是让字段延迟加载,并通过如下查询:
*从十几岁开始,我就加入了青少年名单
问候,
FT对于事务,当您有一个惰性字段时,您无法获取该字段的值,因为您在事务之外,并且您的会话已被释放 一种方法是,将transactionnal注释放在您的控制器上,或者将控制器的内容委托给标记为transactionnal的服务类,并在该服务类的方法中进行操作 确保不能在事务外部调用惰性字段
问候,以下是我最后的做法: 相反,我只有一个只获取惰性数据的
teenDao.findAll()
方法,我创建了另一个接收布尔参数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
为true时,我只初始化我想要的列表。可能的重复项您是否使用Jackson将Json符号中的对象发送到客户端?是的,我使用Jackson。。签入servlet-context.xml->MappingJackson2HttpMessageConverterI我认为@JsonIgnore应该可以工作,当您获取青少年和追随者时,Jackson看到追随者与青少年有关联,并尝试再次获取它,即使它存在。但是它找不到会话。我添加了@JsonIgnore来跟踪青少年,这个异常不再发生。。但是,以下列表不被视为向应用程序发送数据。。它发送除跟随者列表之外的所有内容。。我也想发送此信息,谢谢你的回答,但不幸的是,使用渴望不是我的选择。。这可能会导致严重的性能问题,因为我不想总是吸引一个青少年的所有追随者。@FelipeMosso Ya我接受这一点。。。否则,您可以使用每个请求的会话来解决this@FelipeMosso请检查链接是的,我做了这个。。这开始奏效了。。但是,当我将列表发送到internet时(从foo()方法返回),我再次得到相同的LazyInitializationException..这就是服务层的用途。不能在事务边界之外移交实体。将您需要的数据复制到POJO,然后传递到更高的层。除了@Transaction之外,没有其他选择吗?是的。要么停止从dao返回实体,要么在dao内部调用teen.getFollower().size()
,以贪婪地获取实体。
@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;
}
}
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;
}
@Transactional
public void foo() {
List<Teen> teens = (List<Teen>) teenDao.findAll();
for (Teen item : teens) {
...
}
}
@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;
}