无法修复无法延迟初始化角色集合的方法:无法初始化代理-没有会话

时间:2018-12-20 19:07:52

标签: spring hibernate spring-mvc lazy-initialization

当我尝试在jsp forEach调用和控制器类中访问类的延迟获取的属性时,出现org.hibernate.LazyInitializationException。

我阅读了所有先前的答案并进行了尝试,我在服务中使用了@Transactional,并使用了它的dao类方法只是为了确保,我尝试添加了Hibernate.initialize(),该方法不起作用,后来又添加了过滤器,但是与渴望获取相比,这使我的表现更差。当我将其更改为渴望获取时,它可以工作,但是由于性能我希望它被懒惰地获取。 基本上,在for循环行上调用absoluteRatingVal()时会发生错误。文章和评分中的所有内容都是懒惰获取。

Article.java

@Entity
@Table(name = "articles")
public class Article {
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "id")
   private int id;

   @Column(name = "title")
   private String title;

   @ManyToOne(fetch = FetchType.LAZY)
   @JoinColumn(name = "created_by")
   private User user;

   @OneToMany(cascade = CascadeType.ALL, mappedBy = "article", fetch = FetchType.LAZY)
   private Set<Rating> rating = new HashSet<>();

public Double getAbsoluteRatingVal() {

    double rating = 0;
    Set<Rating> ratings = getRating();
    for (Rating r : ratings) {
        if (Days.daysBetween(new DateTime(r.getDate().getTime()), new DateTime(new Date().getTime()))
                .getDays() < 301)
            if (r.getGenuine() != null)
                rating++;
            else if (r.getOpinion() != null)
                rating++;
    }

    if (ratings.size() > 0)
        return rating;

    return null;
}
}

NewsDao.java带有引发此错误的1个方法示例。

@Repository("newsDao")
@Transactional
@Component("newsDao")
public class NewsDao {
    @Autowired
    private SessionFactory sessionFactory;
    private Transaction tx;

    public Session session() {
        return sessionFactory.openSession();
    }

    @Transactional(propagation=Propagation.REQUIRED, readOnly=true, noRollbackFor=Exception.class)
    public List<Article> searchArticlesByRating(String query) {
    Session session = session();
    try {
        CriteriaBuilder builder = session.getCriteriaBuilder();
        CriteriaQuery<Article> crit = builder.createQuery(Article.class);
        Root<Article> root = crit.from(Article.class);
        crit.select(root).where(builder.like(root.get("title"), "%" + query + "%"));
        Query<Article> q = session.createQuery(crit);

        List<Article> result = q.list();
        session.close();

        System.err.println(result);         

        Rating fake = new Rating();
        fake.setDate(new Date());
        fake.setFake(new User());
        for (Article a : result) {
            if (a.getAbsoluteRatingVal() == null) 
                a.getRating().add(fake);
        }

        Collections.sort(result,
                Comparator.comparing(Article::getAbsoluteRatingVal).thenComparing(new Comparator<Article>() {
                    public int compare(Article a1, Article a2) {
                        if (a1.getRating() != null && a2.getRating() != null)
                            return a2.getRating().size() - a1.getRating().size();
                        return 0;
                    }
                }));

        for (Article a : result) {
            if (a.getAbsoluteRatingVal() != null && a.getAbsoluteRatingVal().intValue() == 0) 
                a.getRating().remove(fake);
        }

        return result;
    } catch (Exception e) {
        e.printStackTrace();

        session.close();
        return null;
    }
}

Rating.java

@Entity
@Table(name = "ratings")
public class Rating {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "article")
    private Article article;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "voted_genuine")
    private User genuine;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "voted_fake")
    private User fake;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "voted_opinion")
    private User opinion;
 }

编辑

在featured.jsp中,我收到以下错误消息:org.hibernate.LazyInitializationException:无法初始化代理-当我从我理解的用户那里调用访问OneToOne关系的article.user.isSubscribed()时,没有会话,因为他无法不会被获取。

featured.jsp

<c:choose>
                            <c:when
                                test='${article.user.isSubscribed() and article.user.subscription.type eq "silver" }'>
                                <a class="bold"
                                    href='${pageContext.request.contextPath}/u/${article.user.username}'><span
                                    class="silvername"> <c:out value="${article.user.name}"></c:out></span></a>
                            </c:when>
                            <c:when
                                test='${article.user.isSubscribed() and article.user.subscription.type eq "gold" }'>
                                <a class="bold"
                                    href='${pageContext.request.contextPath}/u/${article.user.username}'><span
                                    class="goldname"> <c:out value="${article.user.name}"></c:out></span></a>
                            </c:when>
                            <c:when
                                test='${article.user.isSubscribed() and article.user.subscription.type eq "premium" }'>
                                <a class="bold"
                                    href='${pageContext.request.contextPath}/u/${article.user.username}'><span
                                    class="premiumname"> <c:out
                                            value="${article.user.name}"></c:out></span></a>
                            </c:when>
                            <c:otherwise>
                                <a class="bold"
                                    href='${pageContext.request.contextPath}/u/${article.user.username}'><span>
                                        <c:out value="${article.user.name}"></c:out>
                                </span></a>
                            </c:otherwise>
                        </c:choose>

我希望应用程序以延迟获取的方式运行

1 个答案:

答案 0 :(得分:1)

在从session.close()返回之前,即在调用NewsDao#searchArticlesByRating(String)之后立即致电Article#getAbsoluteRatingVal()

@Transactional(...)
public List<Article> searchArticlesByRating(String query) {
    Session session = session();
    try {
        // business logic here

        session.close();   

        return result;

    } catch (Exception e) {
    }
}