无法修复延迟初始化角色集合失败:无法初始化代理 - 无会话
Can't fix failed to lazily initialize a collection of role: could not initialize proxy - no Session
当我在 jsp forEach 调用和控制器 class.[= 中尝试访问我的 classes 的延迟获取属性时,我得到 org.hibernate.LazyInitializationException 14=]
我阅读了所有以前的答案并尝试了它们,我在我的服务中添加了 @Transactional 和使用它的 dao classes 方法只是为了确定,我尝试添加 Hibernate.initialize(),没有用,后来有一个过滤器,但它使我的性能比急切更差。当我将它更改为 eager fetch 时它会起作用,但我希望它因为性能而延迟获取。
基本上当在 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() 时没有会话,据我了解,用户是null 因为无法获取他。
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>
我希望应用程序 运行 使用延迟获取
在从 NewsDao#searchArticlesByRating(String)
返回之前立即调用 session.close()
,即在调用 Article#getAbsoluteRatingVal()
之后。
@Transactional(...)
public List<Article> searchArticlesByRating(String query) {
Session session = session();
try {
// business logic here
session.close();
return result;
} catch (Exception e) {
}
}
当我在 jsp forEach 调用和控制器 class.[= 中尝试访问我的 classes 的延迟获取属性时,我得到 org.hibernate.LazyInitializationException 14=]
我阅读了所有以前的答案并尝试了它们,我在我的服务中添加了 @Transactional 和使用它的 dao classes 方法只是为了确定,我尝试添加 Hibernate.initialize(),没有用,后来有一个过滤器,但它使我的性能比急切更差。当我将它更改为 eager fetch 时它会起作用,但我希望它因为性能而延迟获取。 基本上当在 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() 时没有会话,据我了解,用户是null 因为无法获取他。
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>
我希望应用程序 运行 使用延迟获取
在从 NewsDao#searchArticlesByRating(String)
返回之前立即调用 session.close()
,即在调用 Article#getAbsoluteRatingVal()
之后。
@Transactional(...)
public List<Article> searchArticlesByRating(String query) {
Session session = session();
try {
// business logic here
session.close();
return result;
} catch (Exception e) {
}
}