简体   繁体   English

休眠-LazyInitializationException

[英]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 它给出: org.hibernate.LazyInitializationException: could not initialize proxy - no Session

PlayersService.load(): PlayersService.load():

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

PlayersDao.load() - extended from AbstractDao: PlayersDao.load()-从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? 我在这里还有一个问题: @Transactional应该在DAO层还是Service层?

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. Hibernate中的load方法可能返回一个代理,而不是实际对象。 The proxy will then load the entity state when one of the persistent properties is accessed whilst the Hibernate session is still open. 然后,当在Hibernate会话仍处于打开状态时访问持久属性之一时,代理将加载实体状态。

In your case the Hibernate session is bound to the transaction created due to the presence of @Transactional. 在您的情况下,Hibernate会话绑定到由于存在@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. 将以下方法更改为使用始终获取实体状态的get方法。 NB get method returns null if no row is found in the database for the provided key NB get方法如果在数据库中找不到提供的键的行,则返回null

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. 注意:您的mod()方法t result in the player数据库中更新t result in the player的昵称。 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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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