1

我有三个实体 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;
    }
}

以及对Employee实体执行保存、更新、删除操作的EmployeeDAO。

@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"
    }
}

在在这里发布这个问题之前,我做了一点谷歌搜索。并发现有两种方法可以解决它:

  1. 不要使用 LAZY 初始化,即lazy=false。但这种方法有其自身的含义。并且由于其性能问题而不能使用这种方法。

  2. 使用@PersistenceContext(type = PersistenceContextType.EXTENDED)。这解决了问题,但我认为,使用这种方法 Spring 不管理 EntityManager/TransactionManager,我必须自己管理这些。有没有什么办法可以用这种方法来管理 EntityManager/TransactionManager,这样我就不必自己管理它了。

或者有没有更好的方法来解决这个问题?

4

1 回答 1

0

在您的测试方法中创建了两个单独的会话,并且在尝试进行更新时 getPerson 由于lazyInitializatin而失败...。

您应该注释您的方法,@Transactional该方法将在整个测试方法中保持相同的持久上下文。

import rg.springframework.transaction.annotation.Transactional
...
    @Test
    @Transactional
    public void testSaveOrUpdate() {

同样,在你的真实业务代码中,每当你在方法内多次访问 DAO 时,都应该将此方法注解为 Transactional 以维护上下文。当然,副作用是,如果其中一个 DAO 操作失败,则整个方法逻辑将失败,但这可能是所要求的行为。

于 2015-05-30T12:04:04.300 回答