【问题标题】:Hibernate - failed to lazily initialize a collection of role - could not initialize proxy - no Session休眠 - 无法延迟初始化角色集合 - 无法初始化代理 - 无会话
【发布时间】:2015-02-01 20:58:03
【问题描述】:

问题:无法通过 User 对象在 Spring Controller 中添加 Address 对象。

UserAddress 类 -> @Entity

User 有一个 List<Address>FetchType=LAZY

@Repository
public class UserDao{
    @Autowired
    private SessionFactory sessionFactory;
    ...
    public User get(String username) {
        Session session = sessionFactory.getCurrentSession();
        return (User)session.get(User.class, username);
    }
    ...
    public void update(User user){
        Session session = sessionFactory.getCurrentSession();
        session.saveOrUpdate(user);
    }
    ...
}


@Service
@Transnational
public class UserService{
    @AutoWired
    private UserDao userDao;
    ...

    @Transactional(readOnly = true)
    public User get(String username) {
        Session session = sessionFactory.getCurrentSession();
        return (User)session.get(User.class, username);
    }

    public void update(User user){
        userDao.update(user);
    } 
    ...
}

@Controller
public class UserController{
    @AutoWired
    private UserService userService;
    ....
    public String update(){
        User user = userService.get("user0001");
        user.getAddressList.add(new Address("new street"));
        return "update";
    }
}

Spring.xml

<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<tx:annotation-driven transaction-manager="transactionManager" />

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location">
        <value>classpath:jdbc.properties</value>
    </property>
</bean>

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${jdbc.driverClassName}" />
    <property name="jdbcUrl" value="${jdbc.url}" />
    <property name="user" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
</bean>

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource">
        <ref bean="dataSource"/>
    </property>
    <property name="packagesToScan" value="com.entity" />
    <property name="hibernateProperties">
       <props>
         <prop key="hibernate.dialect">${hibernate.dialect}</prop>
         <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
       </props>
    </property> 
</bean>

一切正常。但我无法更改 @Controller 内的 user 对象。

user 对象在@Controller 级别发生变化时,该对象不涉及此类Hibernate 会话。不知何故,该对象超出了休眠上下文。

@Controller 中的 .add(new Address("new street")); 语句发生错误。

为什么禁止更改通过 Hibernate 会话接收的 Controller 内的对象?

我遵循的方式不正确?如果不是,我做错了什么?

--Spring 4,休眠 4

【问题讨论】:

    标签: spring hibernate dao


    【解决方案1】:

    User 有一个List&lt;Address&gt;。当您从数据库而不是列表中获取用户时,hibernate 会插入一个代理来处理地址的获取。

    这个代理需要有一个会话才能做任何事情。当您尝试添加地址时,您超出了事务注释的范围,因此没有会​​话。

    最好的方法是在 UserService 中添加一个带有 @Transactional 注释的方法,以添加地址。

    【讨论】:

    • 是的。我试过了,它奏效了。你能在你的回答中解释一下proxy吗?我们不能指示代理不要立即响应吗?但是Controller 不知道代理是休眠的还是任何东西。所以有一个耦合+规则是“不要更新Controllers内的对象/实体”。这样可以吗?
    • 您同时使用两个系统,Spring 和 Hibernate。他们都为您做事以使您的生活更轻松,但您需要了解每个人的作用。 Hibernate 使用事务的概念。您创建一个会话,获取一些对象,更改它们并将它们提交到数据库,然后关闭会话。如果发生任何异常,您将回滚并中止。这称为交易。你可以在这里阅读更多信息:docs.jboss.org/hibernate/orm/3.3/reference/en/html/…
    • 现在每次编写所有这些样板代码都是对每次的血腥浪费。这就是 @Transactional 注释的用武之地。通过将其添加到方法中,您可以告诉框架(在本例中为 Spring)将会话的样板代码包装在方法周围。
    • 一旦对象离开此方法,就会出现混乱。一旦离开该方法,围绕该方法的事务代码就会清理并关闭会话。当 Hibernate 为您获取对象时,它添加了一个代理以允许您延迟获取集合(更多样板代码的包装!)。但是,代理需要此会话才能执行任何操作。然而,当对象离开事务范围时,此会话被关闭。由于会话已关闭,因此无法获取或添加数据。
    • TLDR:规则是:不要在事务之外更改您的数据。这也意味着您可能会取消 DAO 和服务,而只需为每个用户使用一个控制器来处理修改,但这并不是我的专业领域。
    猜你喜欢
    • 1970-01-01
    • 2016-07-06
    • 2015-07-02
    • 2018-02-25
    • 2017-01-30
    • 2016-06-04
    • 2018-11-21
    • 2014-12-23
    • 2019-05-21
    相关资源
    最近更新 更多