我正在尝试打印来自一个用户的所有帖子,但是一组帖子不会加载,我得到此异常(下面的Stacktrace)。
控制器
@RequestMapping(value = "/mainPage", method = RequestMethod.GET)
public ModelAndView getMainPage(Authentication authentication, /*@ModelAttribute("post") Post post, */ModelMap modelMap)
{
ModelAndView modelAndView = new ModelAndView("mainPage", "command", new Post());
modelAndView.addObject(ERROR_ATTRIBUTE, modelMap.get(ERROR_ATTRIBUTE));
//TODO what if don't find?
//User user = userManager.findByUsername(authentication.getName());
//modelAndView.addObject("user", user);
//modelAndView.addObject("posts", userManager.getUsersPosts(user.getUsername()));
// //modelAndView.addObject("user", user);
modelAndView.addObject("posts", userManager.getUsersPosts(authentication.getName()));
return modelAndView;
//return new ModelAndView("mainPage", "command", new Post());
}
的UserManager
@Service
@Transactional
public class DefaultUserManager implements UserManager{
@Override
public User findByUsername(String username) {
return userDao.findByUsername(username);
}
@Override
public Set<Post> getUsersPosts(String username) {
User user = findByUsername(username);
return user.getPosts();
}
@Override
public List<Post> getUsersPosts(String username) {
return userDao.findPostsByUsername(username);
}
}
用户
@Entity
@Table(name = "Users")
public class User extends BaseObject implements UserDetails {
/** User's posts */
private Set<Post> posts;
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
//@BatchSize(size = 5) /* Na základě odhadu, že průměrný uživatel bude mít max 5-10 šablon */
//@OrderBy(" DESC")
@JoinColumn(name="createdBy_ID")
public Set<Post> getPosts() {
return posts;
}
}
我正在通过@Transactional
课程中的服务层访问帖子,所以我不确定到底出了什么问题。起初我在评论中使用了代码,所以我认为这是因为我在user
首先和稍后的帖子中获得Controller
但是改为在一行中调用它并没有帮助。你能告诉我如何解决这个问题吗?
我想避免使用FetchType.EAGER
。
Stacktrace
root cause
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: sk1x1.domain.User.posts, could not initialize proxy - no Session
org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:575)
org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:214)
org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:554)
org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:142)
org.hibernate.collection.internal.PersistentSet.iterator(PersistentSet.java:180)
org.apache.taglibs.standard.tag.common.core.ForEachSupport.toForEachIterator(ForEachSupport.java:348)
org.apache.taglibs.standard.tag.common.core.ForEachSupport.supportedTypeForEachIterator(ForEachSupport.java:224)
org.apache.taglibs.standard.tag.common.core.ForEachSupport.prepare(ForEachSupport.java:155)
javax.servlet.jsp.jstl.core.LoopTagSupport.doStartTag(LoopTagSupport.java:256)
org.apache.jsp.WEB_002dINF.pages.mainPage_jsp._jspx_meth_c_005fforEach_005f0(mainPage_jsp.java:451)
org.apache.jsp.WEB_002dINF.pages.mainPage_jsp._jspService(mainPage_jsp.java:157)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:168)
org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1244)
org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1027)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:971)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:115)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:121)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:100)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
修改
我尝试使用Kayaman方法,因此编辑了我的代码,现在我得到了这个:
org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=null,role=sk1x1.domain.User.posts,tableName=Posts,tableAlias=posts1_,origin=Users user0_,columns={user0_.id ,className=sk1x1.domain.Post}}]
这是我改变后的UserDaoJpa
public List<Post> findPostsByUsername(String username)
{
User user = findByUsername(username);
if(user == null) {
throw new UsernameNotFoundException(username + " was not found.");
}
TypedQuery<Post> query = em.createQuery("select u.posts from User u left join fetch u.posts where u.username = :username", Post.class);
query.setParameter("username", username);
try {
return query.getResultList();
}
catch (NoResultException e)
{
return null;
}
}
你有什么建议吗?
答案 0 :(得分:2)
当你return user.getPosts();
你正在返回未初始化的懒惰代理时。当在JSP中访问它时,事务上下文早已消失,并且您不希望使用Open Session In View反模式来保持事务上下文在此之前保持打开状态。
我会写一个单独的查询来获取帖子,并使用JOIN FETCH
来热切地获取帖子,而不会让关系变得热切。
如下所示,有两个选项,具体取决于您是否也需要User
。
public Set<Post> getUsersPosts(String username) {
return userDao.findPostsByUsername(username);
}
// Only select posts from a user, without user entity. No JOIN needed.
@Query("SELECT u.posts FROM User u WHERE u.username = :username")
Set<Post> findPostsByUsername(@Param("username") String username);
// A Left join brings us the user even if it doesn't have posts, and
// FETCH gets the posts eagerly, so no lazy loading or performance hit
@Query("SELECT u FROM User u LEFT JOIN FETCH u.posts WHERE u.username = :username")
User findUserAndPostsByUsername(@Param("username") String username);
答案 1 :(得分:0)
您的交易仅在DefaultUserManager
左右,但不在其所在位置。
你写道你不想要FetchType.EAGER
。那么如果你在交易期间强制手动取出它们会发生什么呢?
例如天真的方法:
@Override
public Set<Post> getUsersPosts(String username) {
Set<Post> ret = new HashSet<Post>();
User user = findByUsername(username);
ret.addAll(user.getPosts());
return ret;
}
答案 2 :(得分:0)
在事务中强制延迟收集初始化:
@Override
public Set<Post> getUsersPosts(String username) {
User user = findByUsername(username);
Hibernate.initialize(user.getPosts());
return user.getPosts();
}
答案 3 :(得分:0)
在我看来,你的映射有问题。
您将Post
指定为关系的拥有方,在这种情况下,用户需要指定其他属性:
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="createdBy_ID", insertable = false, updatable = false)
public User getAuthor()
但理想情况下,我认为你的映射应该如下:
在Post
:
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="createdBy_ID")
public User getAuthor()
和User
:
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL
, orphanRemoval = true, mappedBy="author")
public Set<Post> getPosts()
<强>更新强>
关于仅返回基于用户的帖子的查询。应该没有抓取:
TypedQuery<Post> query = em.createQuery(
"select p from User u left join u.posts p where u.username = :username"
, Post.class);