如何在休眠/弹簧中更新多对多集合(延迟加载)?

Posted

技术标签:

【中文标题】如何在休眠/弹簧中更新多对多集合(延迟加载)?【英文标题】:how to update many-to-many collection (lazy-loading) in hibernate/spring? 【发布时间】:2015-03-27 19:54:29 【问题描述】:

我有三个表和两个类。两个表/类之间存在多对多关系。OYS_USER -->带有“oys_lesson”的多对多 OYS_LESSON-->使用“oys_user”的多对多 OYS_LESSON_STUDENT-->关系 User.class

@ManyToMany(cascade= CascadeType.ALL,fetch=FetchType.LAZY)
@JoinTable(name="oys_lesson_student", 
    joinColumns =   @JoinColumn(name="student_id",referencedColumnName="id"),
    inverseJoinColumns = @JoinColumn(name="lesson_id",referencedColumnName="id") )
@Fetch(FetchMode.SUBSELECT)
private Set<Lesson> studentLessons;

Lesson.class

@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
@JoinTable(name = "oys_lesson_student", joinColumns =  @JoinColumn(name = "lesson_id", referencedColumnName = "id") , inverseJoinColumns =  @JoinColumn(name = "student_id", referencedColumnName = "id") )
@Fetch(FetchMode.SUBSELECT)
private Set<User> lessonStudents;

我用以下代码更新了集合:

@Override
public void addLessonToStudent(Lesson lesson) 
        // TODO Auto-generated method stub
    String username = SecurityContextHolder.getContext()
            .getAuthentication().getName();
            Criteria criteria = openSession().createCriteria(User.class)
                    .add(Restrictions.eq("username", username));
            User user=(User) criteria.uniqueResult();
            log.info("'"+lesson.getLessonName()+"' lesson added to '"+user.getUsername()+"'");
            /*user.getStudentLessons().add(lesson);
            updateUser(user);
            */
            lesson.getLessonStudents().add(user);
            updateLesson(lesson);
         catch (HibernateException e) 
            // TODO Auto-generated catch block
            e.printStackTrace();
        


@Override
public void updateLesson(Lesson lesson) 
    log.info(lesson.getLessonName()+" updated.");
    openSession().update(lesson);

当我将当前用户添加到课程收藏(或课程添加到当前用户收藏)时。 更新/插入查询不会出现在休眠统计信息中(控制台日志)。 因此不能将记录添加到任何集合中。 基本上,我想向多对多集合添加新对象。我做错了什么?

我使用hibernate 4.3.5.Final(摆脱延迟加载异常) 我使用 org.springframework.orm.hibernate4.support.OpenSessionInViewFilter 来摆脱延迟加载异常)。 我用 FetchType.JOIN 尝试了 CascadeType.EAGER。但没有改变结果。更新/插入查询没有出现在休眠统计信息(控制台日志)中。

我在 application-context.xml(spring-hibernate-configuration) 中使用以下属性进行休眠:

    <property name="hibernateProperties">
    <props>
        <prop key="hibernate.dialect">org.hibernate.dialect.mysqlDialect</prop>
        <prop key="hibernate.show_sql">true</prop>
        <prop key="hibernate.generate_statistics">true</prop>
        <prop key="hibernate.cache.use_second_level_cache">true</prop>
        <prop key="hibernate.cache.use_query_cache">true</prop>
        <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory
        </prop>
        <prop key="hibernate.enable_lazy_load_no_trans">true</prop>
        <prop key="use_sql_comments">true</prop>
        <prop key="hibernate.bytecode.use_reflection_optimizer">true</prop>
        <prop key="hibernate.connection.autocommit">true</prop>
        <prop key="net.sf.ehcache.configurationResourceName">/myehcache.xml</prop>
    </props>
</property>

和弹簧 txManager:

        <!-- Enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="txManager" />

<!-- Transaction Manager is defined -->
<bean id="txManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="SessionFactory" />
</bean>

我使用 spring/security、hibernate 4.3.5.Final、jpa2.1、jsf2.2。提前致谢。

【问题讨论】:

这个jsf有什么关系? 不,你也没有使用 JPA API 你到底是什么意思?我使用 jpa 2.1 for hibernate 4.3.5.Final。你有什么建议来解决这个问题吗?谢谢@Neil-Stockton 您使用的是 Hibernate 的 API,而不是 JPA API。 JPA 中没有“会话”。 JPA 中没有任何限制,而且还在继续。 我该怎么做? 【参考方案1】:

你快到了。

首先,您需要确定您的关系的哪个站点是“可控的”。是用户还是教训。并且你只在其中一个上定义连接表,例如: - 你让用户保持原样 - 在你改变的课程上

@ManyToMany(mappedBy="studentLessons" ...)

然后,您需要手动将关系添加到关系的两个站点(实际上,添加到负责映射的站点通常就足够了)。

所以

user.getUserLesseson().add(lesson);
lesson.getLessonStudents().add(user);

如果两者都在事务内部发出,则会导致插入

【讨论】:

感谢回复。我尝试了上面的代码。但没有改变。当我编码“log.info(user.getStudentLessons().toString());” ,我看到所有信息(用户的表列,oys_user_lesson 表信息),我看到这个结果的“选择查询”。我看到增加 getStudentLessons 列表的大小。到目前为止一切正常。但是没有做更新过程。我不在控制台中查看更新/插入查询。所以我在 oys_student_lesson 表中没有看到记录。:/ 你是insed交易吗?我自己没有使用hibernate和spring,只有jpa,对于非托管事务,代码将是 EM.getTransaction().begin();用户用户 = EM.find()..; .add(教训);... EM.getTransaction().commit();在 Spring 中,它是通过围绕方法或类似方法的 @Transactional 注释来完成的(对不起,不是 spring 用户)。与您设法插入持久新用户或课程的方式相同。 我在服务类/层中使用@Transactional注解。我使用自动提交。你可以在休眠属性中看到。通常用户可以更新/我可以更新。但是当我将课程对象添加到用户的课程集合时,不更新。 它必须工作,代码看起来没问题,映射没问题(如果你修复了 mappedby),这就是它在 JPA 中的完成方式。所以嫌疑人是你的交易/会话。尝试在 addLessonToStudent 方法中修改用户/课程的属性,并检查方法退出后是否发出 sql 更新。估计不会有更新了。 我在 updateUser(user);.Updating only user(user table).hibernate 表现得好像 studentLessons 集合没有改变之前手动检查了对用户名的更改。

以上是关于如何在休眠/弹簧中更新多对多集合(延迟加载)?的主要内容,如果未能解决你的问题,请参考以下文章

休眠延迟加载不适用于多对一映射

hibernate 的 关联关系之多对多 和 延迟加载

mybat 中的缓存,多对多

克服 Hibernate 中的延迟加载问题,多对多关系

NHibernate之(12):初探延迟加载机制

Mybatis学习笔记—高级映射,延迟加载