LazyInitializationException尝试获取懒惰的初始化实例 [英] LazyInitializationException trying to get lazy initialized instance

查看:141
本文介绍了LazyInitializationException尝试获取懒惰的初始化实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我尝试获取延迟初始化的实体时,我在IDE中看到以下异常消息(我无法找到它在代理实体中的存储位置,因此无法为该异常提供整个堆栈跟踪):

I see the following exception message in my IDE when I try to get lazy initialized entity (I can't find where it is stored in the proxy entity so I can't provide the whole stack trace for this exception):

Method threw 'org.hibernate.LazyInitializationException' exception. Cannot evaluate com.epam.spring.core.domain.UserAccount_$$_jvste6b_4.toString()

这是我尝试访问要使用的惰性初始化实体的字段后得到的堆栈跟踪:

Here is a stack trace I get right after I try to access a field of the lazy initialized entity I want to use:

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

    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:165)

    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:286)

    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)

    at com.epam.spring.core.domain.UserAccount_$$_jvstfc9_4.getMoney(UserAccount_$$_jvstfc9_4.java)

    at com.epam.spring.core.web.rest.controller.BookingController.refill(BookingController.java:128) 

我正在使用Spring Data,已配置JpaTransactionManager,数据库是MySql,ORM提供程序是Hibernate4.注释@EnableTransactionManagement已启用,@ Transactional放置在我能想象的任何地方,但无济于事.

I'm using Spring Data, configured JpaTransactionManager, database is MySql, ORM provider is Hibernate 4. Annotation @EnableTransactionManagement is on, @Transactional was put everywhere I could imagine but nothing works.

这里是一个关系:

@Entity
public class User extends DomainObject implements Serializable {

    ..

    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "user_fk")
    private UserAccount userAccount;

    ..

@Entity
public class UserAccount extends DomainObject {

    ..

    @OneToOne(mappedBy = "userAccount")
    private User user;

    ..

..一项配置:

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(env.getRequiredProperty(PROP_NAME_DATABASE_DRIVER));
        dataSource.setUrl(env.getRequiredProperty(PROP_NAME_DATABASE_URL));
        dataSource.setUsername(env.getRequiredProperty(PROP_NAME_DATABASE_USERNAME));
        dataSource.setPassword(env.getRequiredProperty(PROP_NAME_DATABASE_PASSWORD));
        return dataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setDataSource(dataSource());
        entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
        entityManagerFactoryBean.setPackagesToScan(env.getRequiredProperty(PROP_ENTITYMANAGER_PACKAGES_TO_SCAN));
        entityManagerFactoryBean.setJpaProperties(getHibernateProperties());            
        return entityManagerFactoryBean;
     }

    @Bean
    public JpaTransactionManager transactionManager(@Autowired DataSource dataSource,
                                                    @Autowired EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
        jpaTransactionManager.setEntityManagerFactory(entityManagerFactory);
        jpaTransactionManager.setDataSource(dataSource);

        return jpaTransactionManager;
    }

..这就是我要检索UserAccount的方式:

.. and this is how I want to retrieve UserAccount:

    @RequestMapping(...)
    @Transactional()
    public void refill(@RequestParam Long userId, @RequestParam Long amount) {
        User user = userService.getById(userId);
        UserAccount userAccount = user.getUserAccount();
        userAccount.setMoney(userAccount.getMoney() + amount);
    }

Hibernate版本为4.3.8.Final,Spring Data 1.3.4.RELEASE和MySql连接器5.1.29.

Hibernate version is 4.3.8.Final, Spring Data 1.3.4.RELEASE and MySql connector 5.1.29.

请问我是否还需要其他东西.预先谢谢你!

Please, ask me if something else is needed. Thank you in advance!

推荐答案

首先,您应该了解问题的根源不是事务.我们有一个事务和一个持久的上下文(会话).使用@Transactional注释,Spring创建一个事务并打开持久上下文.调用方法后,持久性上下文将关闭.

Firstly, you should understand that the root of the problem is not a transaction. We have a transaction and a persistent context (session). With @Transactional annotation Spring creates a transaction and open persistent context. After method is invoked a persistent context becomes closed.

当调用user.getUserAccount()时,您有一个包装UserAccount的代理类(如果不使用User加载UserAccount).因此,当关闭持久性上下文时,在调用UserAccount的任何方法(例如toString())期间会有一个LazyInitializationException.

When you call a user.getUserAccount() you have a proxy class that wraps UserAccount (if you don't load UserAccount with User). So when a persistent context is closed, you have a LazyInitializationException during call of any method of UserAccount, for example toString().

@Transactional仅在userService级别上起作用.要使@Transactional工作,将@Transactional批注放在方法上是不够的.您需要使用Spring Context中的方法获取类的对象.因此,要更新资金,您可以使用其他服务方法,例如updateMoney(userId, amount).

@Transactional working only on the userService level, in your case. To get @Transactional work, it is not enough to put the @Transactional annotation on a method. You need to get an object of a class with the method from a Spring Context. So to update money you can use another service method, for example updateMoney(userId, amount).

如果要在控制器方法上使用@Transactional,则需要从Spring Context获取控制器. Spring应该理解,它应该使用特殊方法包装每个@Transactional方法,以打开和关闭持久性上下文.另一种方法是使用每个请求的会话数"反模式.您将需要添加特殊的HTTP过滤器.

If you want to use @Transactional on the controller method you need to get a controller from the Spring Context. And Spring should understand, that it should wrap every @Transactional method with a special method to open and close a persistent context. Other way is to use Session Per Request Anti pattern. You will need to add a special HTTP filter.

https://vladmihalcea.com/the-open- session-in-view-anti-pattern/

这篇关于LazyInitializationException尝试获取懒惰的初始化实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆