Martin Häusler
Martin Häusler

Reputation: 7254

Spring Boot Data JPA: Hibernate Session issue

I'm developing a Spring Boot based web application. I heavily rely on @ComponentScan and @EnableAutoConfiguration and no explicit XML configuration in place.

I have the following problem. I have a JPA-Annotated Entity class called UserSettings:

@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...
}

I followed this tutorial and created a repository interface that extends JpaRepository<UserSettings,Long>.

Furthermore, I have a 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);
    }
}

Later in the code, I load the UserSettings object created here, again with the findGlobalSetttings query.

The problem is: Every time I try to access the @OneToMany attribute of the settings object, I get the following exception:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role org.example.UserSettings.preferences, could not initialize proxy - no Session

I understand that each HTTP Session has its own Hibernate Session, as described in the accepted answer of this question, but that does not apply in my case (currently I'm testing this within the same HTTP Session), which is why I have no idea where this exception comes from.

What am I doing wrong and how can I achieve circumvent the error?

Upvotes: 2

Views: 13014

Answers (3)

Srikanth Kallam
Srikanth Kallam

Reputation: 13

I faced similar issue in spring boot application, after googling I'm able to fix this issue by adding the following code to my application.

    @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;
}

Referred here.

Upvotes: 1

Julius Krah
Julius Krah

Reputation: 422

This question has been answered beautifully by @Steve. However, if you still want to maintain your lazy loading implementation, you may want to try this

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();
    }
}

What this configuration does is, it registers a Filter on requests to path "/*" which keeps your Hibernate Session open in your view.

This is an anti-pattern and must be used with care.

NOTE: As of Spring Boot 1.3.5.RELEASE, when you use the default configuration with Spring Data JPA auto-configuration, you shouldn't encounter this problem

Upvotes: 3

Steve
Steve

Reputation: 9480

If you want to be able to access mapped entities outside the transaction (which you seem to be doing), you need to flag it as an "eager" join. i.e.

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

Upvotes: 4

Related Questions