当我尝试放置从对象中获取的字符串列表时,我已通过休眠从数据库加载,我收到此异常。
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
我用来加载列表的方法是在事务内。但是当我尝试将列表放入模型中时,我得到了上述异常。我从中得出,休眠甚至要求我在事务中也包含这行代码。但鉴于这不是数据库操作,为什么会这样呢?
@RequestMapping(value="{id}", method=RequestMethod.POST)
public String addComment(@PathVariable String id, Model model, String comment) {
personService.addComment(Long.parseLong(id), comment);
Person person = personService.getPersonById(Long.parseLong(id));
model.addAttribute(person);
List<String> comments = personService.getComments(id);
model.addAttribute(comments);
return "/Review";
}
服务对象。
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
public class PersonServiceImpl implements PersonService {
private Workaround personDAO;
public PersonServiceImpl() {
}
@Transactional(propagation=Propagation.REQUIRED, readOnly=false)
public void savePerson(Person person) {
personDAO.savePerson(person);
}
@Transactional(propagation=Propagation.REQUIRED, readOnly=false)
public Person getPersonById(long id) {
return personDAO.getPersonById(id);
}
@Autowired
public void setPersonDAO(Workaround personDAO) {
this.personDAO = personDAO;
}
@Transactional(propagation=Propagation.REQUIRED, readOnly=false)
public List<Person> getAllPeople() {
return personDAO.getAllPeople();
}
@Transactional(propagation=Propagation.REQUIRED, readOnly=false)
public void addComment(Long id, String comment) {
Person person = getPersonById(id);
person.addComment(comment);
savePerson(person);
}
@Transactional(propagation=Propagation.REQUIRED, readOnly=false)
public List<String> getComments(String id) {
return personDAO.getComments(Long.parseLong(id));
}
}
DAO
import java.util.List;
import javax.persistence.ElementCollection;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@Repository
public class PersonDAO implements Workaround {
private SessionFactory sessionFactory;
@Autowired
public PersonDAO(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
private Session currentSession() {
return sessionFactory.getCurrentSession();
}
public void addPerson(Person person) {
currentSession().save(person);
}
public Person getPersonById(long id) {
return (Person) currentSession().get(Person.class, id);
}
public void savePerson(Person person) {
currentSession().save(person);
}
public List<Person> getAllPeople() {
List<Person> people = currentSession().createQuery("from Person").list();
return people;
}
public List<String> getComments(long id) {
return getPersonById(id).getComments();
}
}
我对 Hibernate 比较陌生,但我会根据我对它的理解对此进行猜测。
默认情况下,
@OneToMany
集合是延迟加载的。 因此,当您加载 Person 对象时,将创建一个代理来代替您实际的 comments
列表。 这个列表不会被加载,直到你像你一样调用该列表的 getter (即 getComments()
),即使这样,我也不认为完整的列表会立即加载,更何况是一个接一个地加载(是的,多个数据库)调用),当您迭代列表或整个列表时,如果您调用 .size()。
但是,我认为这里的问题是您必须在加载父 (
Person
) 对象的同一会话中加载列表。 当您加载 Person
对象时,您将获得当前会话的引用,然后一旦您在该 Person 对象上调用 getComments()
,会话就会关闭。
我认为要将整个过程保留在一个会话中,您可以像在 DAO 类中一样手动打开和关闭会话。
public List<String> getComments(long id) {
Session session = sessionFactory.openSession();
List<String> comments = getPersonById(id).getComments();
sessionFactory.getCurrentSession().flush();
sessionFactory.getCurrentSession.close();
return comments;
}
将 FetchType 设置为 EAGER 可以解决问题,但根据我的阅读,通常不建议这样做,除非您总是需要使用 Person 对象加载注释。
将获取类型更改为
FetchType.EAGER
。
我认为问题在于你正在使用
currentSession()
尝试将其替换为
private Session currentSession() {
return sessionFactory.openSession();
}
因为异常表明没有任何打开的会话。
您应该检查
Person
类映射,也许 Comments
字段是使用 LAZY
属性映射的,因此它没有加载到 DAO 中。当您调用 getComments
方法时,Hibernate 尝试从数据库加载属性,但当时没有会话,因此出现异常。要解决此问题,请将映射属性更改为 EAGER
。