1

以下に示すように、Employee、Person、および EmailAdress の 3 つのエンティティがあります。

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

この質問をここに投稿する前に、少しグーグルで調べました。そして、それを修正するには2つの方法があることがわかりました:

  1. LAZY 初期化、つまり lazy=false を使用しないでください。しかし、このアプローチには独自の意味があります。また、パフォーマンスの問題があるため、このアプローチは使用できません。

  2. @PersistenceContext(type = PersistenceContextType.EXTENDED) を使用します。これで問題は解決しますが、このアプローチでは、Spring は EntityManager/TransactionManager を管理せず、これらを自分で管理する必要があると思います。自分で管理する必要がないように、このアプローチで EntityManager/TransactionManager を春に管理する方法はありますか。

または、この問題を解決するためのより良い方法はありますか?

4

1 に答える 1

0

テスト メソッド内で 2 つの個別のセッションが作成され、更新を実行しようとすると getPerson が lazyInitializatin.... のために失敗します。

@Transactionalテストメソッド全体で同じ永続コンテキストを維持するメソッドに注釈を付ける必要があります。

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

同様に、実際のビジネス コードでは、メソッド内で DAO に複数回アクセスするときは常に、コンテキストを維持するために、このメソッドにトランザクションとして注釈を付ける必要があります。もちろん、DAO 操作の 1 つが失敗すると、メソッド ロジック全体が失敗するという副作用がありますが、それはおそらく要求された動作です。

于 2015-05-30T12:04:04.300 に答える