Spring Boot Data JPA:Hibernate Session问题

时间:2014-06-24 11:08:00

标签: spring hibernate jpa spring-data spring-boot

我正在开发基于Spring Boot的Web应用程序。我严重依赖@ComponentScan@EnableAutoConfiguration以及没有明确的XML 配置。

我有以下问题。我有一个名为UserSettings JPA -Annotated Entity类:

@Entity public class UserSettings {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @OneToMany(cascade = CascadeType.ALL)
    private Set<Preference> preferences; // 'Preference' is another @Entity class

    public UserSettings() {
         this.preferences = new HashSet<Preference>();
    }

// some more primitive properties, Getters, Setters...
}

我按照this教程创建了一个扩展JpaRepository<UserSettings,Long>的存储库接口。

此外,我有一个UserManager bean:

@Component public class SettingsManager {

@Autowired
UserSettingsRepository settingsRepository;

@PostConstruct
protected void init() {
    // 'findGlobalSettings' is a simple custom HQL query 
    UserSettings globalSettings = this.settingsRepository.findGlobalSettings();
    if (globalSettings == null) {
        globalSettings = new UserSettings();
        this.settingsRepository.saveAndFlush(globalSettings);
    }
}

稍后在代码中,我再次使用UserSettings查询加载此处创建的findGlobalSetttings对象。

问题是:每当我尝试访问设置对象的@OneToMany属性时,我都会遇到以下异常:

  

org.hibernate.LazyInitializationException:无法懒惰地初始化角色org.example.UserSettings.preferences的集合,无法初始化代理 - 没有会话

据我所知,每个HTTP会话都有自己的Hibernate会话,如this question的接受答案中所述,但这不适用于我的情况(目前我在同一个HTTP会话中对此进行测试) ),这就是为什么我不知道这个例外的来源。

我做错了什么,如何避免错误?

3 个答案:

答案 0 :(得分:4)

如果您希望能够访问事务之外的映射实体(您似乎正在执行此操作),则需要将其标记为&#34; eager&#34;加入。即。

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)

答案 1 :(得分:3)

@Steve已经很好地回答了这个问题。但是,如果您仍想维护lazy loading实施,则可能需要尝试此操作

import javax.servlet.Filter;

import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.hibernate4.support.OpenSessionInViewFilter;  

@Configuration
@ComponentScan
public class AppConfig {

    @Bean
    public FilterRegistrationBean filterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(openSessionInView());
        registration.addUrlPatterns("/*");

        return registration;
    }

    @Bean
    public Filter openSessionInView() {
        return new OpenSessionInViewFilter();
    }
}

这个配置的作用是,它在路径"/*"的请求上注册Filter,使您的Hibernate会话在您的视图中保持打开状态。

这是anti-pattern,必须谨慎使用。

注意:从Spring Boot 1.3.5.RELEASE开始,当您使用Spring Data JPA自动配置的默认配置时,您不应该遇到此问题

答案 2 :(得分:1)

我在弹簧启动应用程序中遇到类似问题,谷歌搜索后我可以通过将以下代码添加到我的应用程序来解决此问题。

    @Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder, DataSource dataSource) {
    LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
    entityManagerFactoryBean.setDataSource(dataSource);
    entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
    Properties jpaProperties = new Properties();
    jpaProperties.put("hibernate.enable_lazy_load_no_trans", true);
    entityManagerFactoryBean.setJpaProperties(jpaProperties);
    return entityManagerFactoryBean;
}

提到here