[英]lazyinitializationexception with Hibernate
我在項目中使用數據庫中的實體的延遲初始化。 作為 JPA 實現,我使用 Hibernate。 但是當我需要在自定義 JSP 上獲取實體集合時,我得到了一個延遲初始化異常,因為 Hibernate session 已經關閉。 請告訴我是否可以在不使用特殊請求的情況下阻止此異常,如https://thorben-janssen.com/hibernate-tips-initialize-lazy-relationships-within-query/中所述。 這是我的一些代碼:
@Entity
public class Statistic extends EntityAbstract {
private static final long serialVersionUID = -6372957177860305322L;
@Temporal(TemporalType.TIMESTAMP)
private Date date;
private boolean correct;
@ManyToOne(fetch = FetchType.LAZY, cascade = {MERGE, PERSIST, REFRESH, DETACH})
@JoinColumn(name = "questionId", nullable = false)
private Question question;
@ManyToOne(fetch = FetchType.LAZY, cascade = {MERGE, PERSIST, REFRESH, DETACH})
@JoinColumn(name = "userId", nullable = false)
private User user;
public Statistic() {
}
public Statistic(Date date, boolean correct, Question question, User user) {
this.date = date;
this.correct = correct;
this.question = question;
this.user = user;
}
getter... setter...
}
@Entity
public class Question extends EntityAbstract {
private static final long serialVersionUID = -2751224412459986012L;
private String description;
@ManyToOne(fetch = FetchType.LAZY, cascade = {MERGE, PERSIST, REFRESH, DETACH})
@JoinColumn(name = "testId", nullable = false)
private Test test;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "question")
@OnDelete(action = OnDeleteAction.CASCADE)
private Set<Answer> answers;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "question")
@OnDelete(action = OnDeleteAction.CASCADE)
private Set<Literature> literature;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "question")
@OnDelete(action = OnDeleteAction.CASCADE)
private Set<Statistic> statistics;
public Question() {
}
public Question(String description, Test test) {
this.description = description;
this.test = test;
}
getter... setter...
}
@Entity
public class Literature extends EntityAbstract {
private static final long serialVersionUID = 218407080623072886L;
private String description;
@ManyToOne(fetch = FetchType.LAZY, cascade = {MERGE, PERSIST, REFRESH, DETACH})
@JoinColumn(name = "questionId", nullable = false)
private Question question;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "literature")
@OnDelete(action = OnDeleteAction.CASCADE)
private Set<Link> links;
public Literature() {
}
public Literature(String description, Question question) {
this.description = description;
this.question = question;
}
getter... setter...
}
@Entity
public class Link extends EntityAbstract {
private static final long serialVersionUID = 6494218299043499655L;
private String link;
@ManyToOne(fetch = FetchType.LAZY, cascade = {MERGE, PERSIST, REFRESH, DETACH})
@JoinColumn(name = "literatureId", nullable = false)
private Literature literature;
public Link() {
}
public Link(String link, Literature literature) {
this.link = link;
this.literature = literature;
}
getter... setter...
}
And I need to get a collection of questions from statistics and further along the chain. I use this service:
@Repository
@Transactional
public interface CrudRepository<T extends EntityAbstract> {
SessionFactory getBeanToBeAutowired();
// create
@SuppressWarnings("unchecked")
default T add(T entity){
return (T) getBeanToBeAutowired().getCurrentSession().merge(entity);
}
// read
@SuppressWarnings("unchecked")
default T getById(Class<T> entityClass, long id){
return (T)getBeanToBeAutowired().getCurrentSession().find(entityClass, id);
}
// update
@SuppressWarnings("unchecked")
default T update(T entity){
return (T) getBeanToBeAutowired().getCurrentSession().merge(entity);
}
// delete
default void delete(T entity){
getBeanToBeAutowired().getCurrentSession().remove(entity);
}
@SuppressWarnings("unchecked")
default List<T> getAll(Class<T> t){
return (List<T>)getBeanToBeAutowired()
.getCurrentSession()
.createQuery("FROM " + t.getSimpleName())
.list();
}
}
public interface StatisticRepository extends CrudRepository<Statistic> {
}
public interface StatisticService extends StatisticRepository {
Statistic getById(long id);
List<Statistic> getAll();
}
@Service("statisticService")
public class StatisticServiceImpl implements StatisticService {
private SessionFactory sessionFactory;
@Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Override
public SessionFactory getBeanToBeAutowired() {
return sessionFactory;
}
@Override
public Statistic getById(long id) {
return getById(Statistic.class, id);
}
@Override
public List<Statistic> getAll() {
return getAll(Statistic.class);
}
}
我解決了我的問題如下(使用這篇文章https://thorben-janssen.com/hibernate-tip-entitygraph-multiple- ):
@NamedEntityGraph(
name = "graph.statistic",
attributeNodes = @NamedAttributeNode(value = "question", subgraph = "questionGraph"),
subgraphs = {
@NamedSubgraph(name = "questionGraph",
attributeNodes = @NamedAttributeNode(value = "literature", subgraph = "literatureGraph")),
@NamedSubgraph(name = "literatureGraph",
attributeNodes = @NamedAttributeNode(value = "links"))}
)
@Entity
public class Statistic extends EntityAbstract {
private static final long serialVersionUID = -6372957177860305322L;
@Temporal(TemporalType.TIMESTAMP)
private Date date;
private boolean correct;
@ManyToOne(fetch = FetchType.LAZY, cascade = {MERGE, PERSIST, REFRESH, DETACH})
@JoinColumn(name = "questionId", nullable = false)
private Question question;
@ManyToOne(fetch = FetchType.LAZY, cascade = {MERGE, PERSIST, REFRESH, DETACH})
@JoinColumn(name = "userId", nullable = false)
private User user;
public Statistic() {
}
public Statistic(Date date, boolean correct, Question question, User user) {
this.date = date;
this.correct = correct;
this.question = question;
this.user = user;
}
getters... and setters.....
}
@Service("statisticService")
public class StatisticServiceImpl implements StatisticService {
...
@Override
@Transactional
public List<Statistic> getUserStatisticByUserIdAndDate(long id, Date startDate, Date endDate) {
Session session = sessionFactory.openSession();
session.beginTransaction();
RootGraph<?> graph = session.getEntityGraph("graph.statistic");
List<Statistic> statistics = session
.createQuery("FROM Statistic WHERE user.id = :id AND date between :startDate AND :endDate", Statistic.class)
.setParameter("id", id)
.setParameter("startDate", startDate)
.setParameter("endDate", endDate)
.setHint("javax.persistence.fetchgraph", graph)
.getResultList();
session.getTransaction().commit();
session.close();
return statistics;
}
實體圖存在一些問題。 IMO 最緊迫的問題是,您使用相同的 java model 公開所有 state,盡管並非所有內容都可用。 您始終必須跟蹤 object 的來源,這也是一種痛苦。
我可以建議您查看Blaze-Persistence Entity-Views ,這是一個更合適的解決方案: https://blazebit.com/blog/2016/getting-started-with-blaze-persistence-entity-views.html
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.