【发布时间】:2020-07-17 20:37:31
【问题描述】:
我在项目中使用延迟初始化数据库中的实体。作为 JPA 实现,我使用 Hibernate。但是当我需要在自定义 JSP 上获取实体集合时,我会收到一个延迟初始化异常,因为 Hibernate 会话已经关闭。请告诉我是否可以在不诉诸特殊请求的情况下阻止此异常,如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);
}
}
【问题讨论】:
-
您需要在查询中或在打开的事务中获取所需的数据。当您呈现 JSP 模板时,已经太晚了,事务已经关闭。您可以在您的服务方法上添加
@Transactional,并获取所需的集合。 -
Guillaume F. 谢谢,现在考虑)