我有三个实体Employee,Person和EmailAdress,如下所示:
@Entity
public class Employee {
private Person person;
//Other data members
@ManyToOne(fetch=FetchType.LAZY, cascade = CascadeType.MERGE)
@JoinColumn(name="person_id")
public Partner getPerson() {
return person;
}
//Other getter and setters
}
@Entity
public class Person {
private Set<EmailAddress> emails;
//Other data members
@OneToMany(fetch=FetchType.LAZY, mappedBy="person", cascade=CascadeType.ALL)
public Set<EmailAddress> getEmails() {
return emails;
}
public void setEmails(Set<EmailAddress> emails) {
this.emails = emails;
for(EmailAddress email : this.emails) {
email.setPerson(this);
}
}
//Other getter and setters
}
@Entity
public class EmailAddress {
private Person person;
private String email;
private String emailType;
//getter and setter
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="partner_id")
public Partner getPerson() {
return person;
}
}
EmployeeDAO,对Employee实体执行保存,更新和删除操作。
@Repository("employeeDAO")
@Transactional
public class EmployeeDAO {
public Employee saveOrUpdate(Employee emp) {
try {
return (Employee) sessionFactory.getCurrentSession().merge(emp);
} catch(Exception excp) {
//Handle exception
}
return null;
}
//Other methods
}
EmployeeDAO中的saveOrUpdate()将Employee实体保存到DB没有任何问题,但是当我使用相同的saveOrUpdate()来更新Employee时,它会因LazyInitializationException而失败。以下是EmployeeDAOTest:
//Test class
public class EmployeeDAOTest extends AbstractTestNGSpringContextTests {
@Autowired
private EmployeeDAO employeeDAO;
private Employee createDummyEmployee() {
// Create dummy employee initialized with Person and EmailAddress
return employee;
}
@Test
public void testSaveOrUpdate() {
Employee emp = createDummyEmployee();
//Test Save/Insert
Employee savedEmp = employeeDAO.saveOrUpdate(emp);
Assert.assertNotNull(savedEmp); //Works fine. Employee gets saved correctly
//Test Update
savedEmp.getPerson().setName("Updated Name");
Employee updatedEmp = employeeDAO.saveOrUpdate(savedEmp);
Assert.assertNotNull(updatedEmp); // Fails... because of "org.hibernate.LazyInitializationException: could not initialize proxy - no Session"
}
}
在此处发布此问题之前,我做了一些谷歌搜索。并且发现有两种方法可以解决它:
不要使用LAZY初始化,即lazy = false。但这种方法 有其自身的含义。并且因为它不能使用这种方法 绩效问题。
使用@PersistenceContext(type = PersistenceContextType.EXTENDED)。 这解决了这个问题,但我认为,Spring采用这种方法 不管理EntityManager / TransactionManager,我必须管理 这些我自己。春天有没有办法管理 使用这种方法的EntityManager / TransactionManager让我没有 我必须自己管理。
或者有没有更好的方法来解决这个问题?
答案 0 :(得分:0)
在测试方法中,会创建两个单独的会话,当尝试执行更新时,由于lazyInitializatin而导致getPerson失败....
您应该使用@Transactional
注释您的方法,这将在整个测试方法中保持相同的持久化上下文。
import rg.springframework.transaction.annotation.Transactional
...
@Test
@Transactional
public void testSaveOrUpdate() {
同样,在您的实际业务代码中,每当您在方法内多次访问DAO时,此方法应注释为Transactional以维护上下文。当然,副作用是,如果其中一个DAO操作失败,那么整个方法逻辑将会失败,但这可能是解除武装的行为。