[英]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.