我似乎有一个很奇怪的问题。我在JSP中显示用户及其角色。由于某些原因,仅在首次加载页面时显示角色。我刷新页面,所有角色都从数据库中删除!
我的设置是标准的Spring MVC,JPA + Hibernate(基于Spring Data)应用程序。(Spring 3.2.x,Hibernate 4.1.8)
我有两个实体- User并且Role如下图所示(假设getter和setter方法)
User
Role
@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; }
我有一个Spring Data仓库,它没有定义任何额外的方法。
public interface UserRepository extends CrudRepository<User, Integer> { }
我有一个服务和一个控制器,其相关方法如下。
// 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"; }
在我的JSP中,我试图显示所有用户和任何相关角色。
<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>
就像我之前说的,user_role呈现此页面后,表中的记录将被删除。
user_role
启用后DEBUG的org.hibernate和启用查询日志记录,这里是我在日志中发现:
DEBUG
org.hibernate
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]
显然,这里有些鱼腥味。为什么我的收藏集首先被取消引用?
这是我的JPA实体管理器工厂定义。
<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>
我在这里错过明显的东西吗?
由于您发布的代码似乎正确,因此我猜这里。
我建议的第一件事是删除此初始化(这似乎是删除角色的唯一位置),这本身通常是一个好主意(请参阅下面的评论),我认为这可能会干扰hibernate.enable_lazy_load_no_trans=true已知的泄漏连接。过去:
hibernate.enable_lazy_load_no_trans=true
private Set<Role> roles = new HashSet<>();
第二种尝试是检查是否还用mapBedBy注释了ManyToMany关系的反面以及发生了什么变化。
第三次尝试是,如果急于加载该集合解决了该问题(甚至使FactType,Hibernate.initialize()任意使用)解决了该问题(甚至进一步加剧了enable_lazy_load_no_trans位置)。
最后一个是摆脱enable_lazy_load_no_trans并使用OpenSessionInView
编辑:啊,最后一个,您可能*有此错误(受影响的hibernate4.1.8和4.1.9):https : //hibernate.onjira.com/browse/HHH-7971
因此,使用4.1.7射击可能会带来更好的结果(或可能更糟)。
* 可能的意图是:“您的案例是如此相似,因此邀请您将代码作为测试案例发送到错误报告中”。
*