简体   繁体   中英

Hibernate - LazyInitializationException

I have a simple code. I added some players to database and here I want to set nick in first player:

private void mod() {
    Player p = playersService.loadById(1L);
    p.setNick("OtherNick");
}

It gives: org.hibernate.LazyInitializationException: could not initialize proxy - no Session

PlayersService.load():

@Transactional
public Player loadById(Long id) {
    return playersDao.load(id);
}

PlayersDao.load() - extended from AbstractDao:

@SuppressWarnings("unchecked")
public T load(Serializable id) {
    return (T) currentSession().load(getDomainClass(), id);
}

I have here one more question: @Transactional should be in DAO layer or Service layer?

Hibernate Config:

// package declaration and import statements

@Configuration
@ComponentScan(basePackages = { "eniupage" }, excludeFilters = {
        @Filter(type = FilterType.ANNOTATION, value = EnableWebMvc.class) })
@EnableTransactionManagement
public class RootConfig {
    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName( "com.mysql.jdbc.Driver" );
        dataSource.setUrl( "jdbc:mysql://localhost:3306/eniupage" );
        dataSource.setUsername( "eniupage" );
        dataSource.setPassword( "qwer1234" );
        return dataSource;
    }

    @Autowired
    @Bean
    public LocalSessionFactoryBean sessionFactory( DataSource dataSource ) {
        LocalSessionFactoryBean sfb = new LocalSessionFactoryBean();
        sfb.setDataSource( dataSource );
        sfb.setPackagesToScan( new String[] { "eniupage.domain"} );
        Properties props = new Properties();
        props.setProperty( "hibernate.dialect", "org.hibernate.dialect.MySQLDialect" );
        props.setProperty( "hibernate.hbm2ddl.auto", "create-drop" );
        props.setProperty( "hibernate.show_sql", "true" );

        sfb.setHibernateProperties( props );
        return sfb;
    }



    @Bean
    public BeanPostProcessor persistenceTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }

    @Autowired
    @Bean(name = "transactionManager")
    public HibernateTransactionManager getTransactionManager(
            SessionFactory sessionFactory) {
        HibernateTransactionManager transactionManager = new HibernateTransactionManager(
                sessionFactory);

        return transactionManager;
    }
}

The load method in Hibernate may return a proxy and not the real object. The proxy will then load the entity state when one of the persistent properties is accessed whilst the Hibernate session is still open.

In your case the Hibernate session is bound to the transaction created due to the presence of @Transactional. When the transaction is completed the session is closed before the proxy has loaded. Change the following method to use get method which always fetches the entity state. NB get method returns null if no row is found in the database for the provided key

Change from

return (T) currentSession().load(getDomainClass(), id);

to

return (T) currentSession().get(getDomainClass(), id);

NB Your mod() method won t result in the player s nickname being updated in the database. There is no session which is active to monitor the changes and flush to the database. The player entity is in a detached state and is not managed You need to merge the player into an active session

For example

private void mod() {
    Player p = playersService.loadById(1L);
    p.setNick("OtherNick");
    playerService.updatePlayer(p);
}

Then in PlayerService

@Transactional
public void updatePlayer(Player player){
   session.merge(player);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM