为什么当我所做的只是一个列表时,Hibernate删除我的收集条目? [英] Why is Hibernate deleting my collection entries when all I do is a list?

查看:93
本文介绍了为什么当我所做的只是一个列表时,Hibernate删除我的收集条目?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我似乎有一个相当奇怪的问题。我在JSP中显示用户和他们的角色。出于某种原因,角色仅在首次加载页面时显示。我刷新页面,角色全部从数据库中删除!



我的设置是标准的Spring MVC,JPA + Hibernate(通过Spring数据)应用程序。 (Spring 3.2.x,Hibernate 4.1.8)

我有两个实体 - User Role ,如下所示(假设setter和getters)
$ b

@Entity
public class User {
@Id
@GeneratedValue
private int id;

私人字符串名称;
$ b @ManyToMany
@JoinTable(name =user_role,joinColumns = @JoinColumn(name =user_id),inverseJoinColumns = @JoinColumn(name =role_id))
私人设置<角色> roles = new HashSet<>();
}

@Entity
公共类角色{
@Id
私人字符串ID;

私人字符串名称;
}

我有一个Spring数据库没有定义任何额外的方法。 / p>

  public interface UserRepository扩展CrudRepository< User,Integer> {
}

我有一个服务和一个控制器,其相关方法如下。 / b>

  // service 
@Transactional(readOnly = true)
public Iterable< ;使用者> findAll(){
return userRepository.findAll();
}

//控制器
@RequestMapping
public String showUsers(ModelMap model){
model.put(users,userService.findAll ));

返回admin / users;
}

在我的JSP中,我试图显示所有用户和任何相关角色


$ b

 < c:forEach var =useritems =$ {users} > 
< tr>
< td> $ {user.name}< / td>
< td>
$ {role.name}
< / c:forEach>
< / td>
< / tr>
< / c:forEach>

就像我之前说过的,记录在我的 user_role
$ b

在为启用 DEBUG 后,

  22: 36:25 DEBUG集合取消引用:[com.adarshr.domain.User.roles#1] [Collections.java:76] 
22:36:25 DEBUG刷新:0插入,0更新,0删除到2个对象[AbstractFlushingEventListener.java:117]
22:36:25 DEBUG刷新:0(重新创建),0次更新,1次移除到1次[AbstractFlushingEventListener.java:124]
22:36:25 DEBUG删除集合:[com.adarshr.domain.User.roles#1] [AbstractCollectionPersister.java:1124]
22:36:25 DEBUG
从$ b $删除
user_role
其中
user_id =? [SqlStatementLogger.java:104]
22:36:25 DEBUG完成删除集合[AbstractCollectionPersister.java:1182]

很明显,这里发生了一些可疑的事情。为什么我的集合首先被取消引用?



这是我的JPA实体管理器工厂定义。

 < bean id =entityManagerFactoryclass =org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean> 
< property name =dataSourceref =mainDataSource/>
< property name =packagesToScanvalue =com.adarshr.domain/>
< property name =persistenceProviderClassvalue =org.hibernate.ejb.HibernatePersistence/>
< property name =jpaVendorAdapter>
< bean class =org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter/>
< / property>
< property name =jpaProperties>
<值>
hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
hibernate.format_sql = $ {hibernate.format.sql}
hibernate.ejb.naming_strategy = org.hibernate.cfg.ImprovedNamingStrategy
hibernate.show_sql = $ {hibernate.show.sql}
hibernate.enable_lazy_load_no_trans = true
< / value>
< / property>
< / bean>

我是否在这里错过了一些明显的东西?

解决方案

由于您发布的代码似乎正确,我在这里猜测。

我建议的第一件事是删除这个初始化(它似乎是删除角色的唯一地方),尽管它本身是一个好主意(见注释下面)我认为可能会干扰 hibernate.enable_lazy_load_no_trans = true >泄漏连接

  private设置< Role> roles = new HashSet<>(); 

第二次尝试是检查是否以及如果您还注释了ManyToMany的反面与mappedBy的关系。

第三次尝试是,如果急切地加载集合可以修复问题(加重enable_lazy_load_no_trans位置甚至更多),使用FetchType,Hibernate.initialize()

最后一个是摆脱了enable_lazy_load_no_trans并使用OpenSessionInView



编辑:啊,最后一个,你可能会有这个bug(受到hibernate 4.1.8和4.1.9的影响):
https:// hibernate .onjira.com / browse / HHH-7971



因此,使用4.1.7可以获得更好的结果(或者更糟)。



* 其中可能用于:您的案例非常相似,您被邀请将您的代码作为测试案例在错误报告中。


I seem to have a rather strange problem. I display users and their roles in a JSP. For some reason, the roles are displayed only for the first time the page is loaded. I refresh the page and the roles are all deleted from the database!

My setup is standard Spring MVC, JPA + Hibernate (over Spring Data) application. (Spring 3.2.x, Hibernate 4.1.8)

I have two entities - User and Role as shown below (assume the setters and getters)

@Entity
public class User {
    @Id
    @GeneratedValue
    private int id;

    private String name;

    @ManyToMany
    @JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
    private Set<Role> roles = new HashSet<>();
}

@Entity
public class Role {
    @Id
    private String id;

    private String name;
}

I have a Spring Data repository which doesn't define any extra methods.

public interface UserRepository extends CrudRepository<User, Integer> { 
}

I have a service and a controller whose relevant methods are as follows.

// service
@Transactional(readOnly = true)
public Iterable<User> findAll() {
    return userRepository.findAll();
}

// controller
@RequestMapping
public String showUsers(ModelMap model) {
    model.put("users", userService.findAll());

    return "admin/users";
}

In my JSP, I am trying to display all the users and any associated roles.

<c:forEach var="user" items="${users}">
    <tr>
        <td>${user.name}</td>
        <td>
           <c:forEach var="role" items="${user.roles}">
                ${role.name}
            </c:forEach>
        </td>
    </tr>
</c:forEach>

Like I said earlier, the records in my user_role table get deleted after this page has been rendered.

Upon enabling DEBUG for org.hibernate and enabling query logging, here is what I found in the logs:

22:36:25 DEBUG Collection dereferenced: [com.adarshr.domain.User.roles#1] [Collections.java:76]
22:36:25 DEBUG Flushed: 0 insertions, 0 updates, 0 deletions to 2 objects [AbstractFlushingEventListener.java:117]
22:36:25 DEBUG Flushed: 0 (re)creations, 0 updates, 1 removals to 1 collections [AbstractFlushingEventListener.java:124]
22:36:25 DEBUG Deleting collection: [com.adarshr.domain.User.roles#1] [AbstractCollectionPersister.java:1124]
22:36:25 DEBUG 
    delete 
    from
        user_role 
    where
        user_id=? [SqlStatementLogger.java:104]
22:36:25 DEBUG Done deleting collection [AbstractCollectionPersister.java:1182]

Quite clearly something fishy is going on here. Why is my collection being dereferenced in the first place?

Here is my JPA entity manager factory definition.

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="mainDataSource" />
    <property name="packagesToScan" value="com.adarshr.domain" />
    <property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
    </property>
    <property name="jpaProperties">
        <value>
            hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
            hibernate.format_sql=${hibernate.format.sql}
            hibernate.ejb.naming_strategy=org.hibernate.cfg.ImprovedNamingStrategy
            hibernate.show_sql=${hibernate.show.sql}
            hibernate.enable_lazy_load_no_trans=true
        </value>
    </property>
</bean>

Am I missing something obvious here?

解决方案

As the code you posted seems correct, I am guessing here.

The first thing I would suggest is to remove this initialization (it seems the only place where roles are removed) which while is a good idea by itself in general (see comments below) I think may interfere with hibernate.enable_lazy_load_no_trans=true which has been known to leak connections in the past:

 private Set<Role> roles = new HashSet<>();

A second try would be to check if and what changes if you also annotate the inverse side of your ManyToMany relation with mappedBy.

A third attempt would be if eagerly loading the collection fixes the problem (aggravating enable_lazy_load_no_trans position even more), using FetchType, Hibernate.initialize() of whatever you want.

Last one is getting rid of enable_lazy_load_no_trans and use OpenSessionInView

EDIT: ahh, last one, you may* have it this bug (hibernate 4.1.8 and 4.1.9 affected): https://hibernate.onjira.com/browse/HHH-7971

So having a shot with 4.1.7 could give better results (or maybe worse).

* where may is to be intended as: "your case is so similar you are invited to send your code as a test case in the bug report".

这篇关于为什么当我所做的只是一个列表时,Hibernate删除我的收集条目?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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