1

DAOの実装に問題があります。私のシナリオ:データベースに1つのエンティティを挿入し、このエンティティをデータベースから2回取得します。AssertSameとAssertEqualsの違いを理解しています。どちらの場合も同じエンティティが合格するはずだと思います。私の場合、AssertEqualsは成功しますが、AssertSameは失敗します。

私は長い間それと格闘してきました、そしてどんな助けでも大いに感謝されるでしょう。

私の質問は、これら2つのエンティティが同じであることを確認するために、どのような条件を満たす必要があるかということです。コードで何を変更する必要がありますか?

私は自分のクラスと設定ファイルの一部だけを貼り付けましたが、これは私の意見では不可欠です。

StudentEntityクラスには@Entityの注釈が付けられています。

次のjUnitテストを準備しました。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/dao-context.xml", "/hibernate-context.xml", "/core-context.xml" })
public class BidirectionalTest {

    @Autowired
    private UserService userService;

    @Test
    public void testBidirectionalRelation() {
        try {
            StudentEntity s = new StudentEntity();
            s.setLogin("Login");
            userService.registerUser(s);
            StudentEntity foundStudent1 = (StudentEntity) userService.findUserByLogin("Login");
            StudentEntity foundStudent2 = (StudentEntity) userService.findUserByLogin("Login");
            assertEquals(foundStudent1, foundStudent2);
            assertSame(foundStudent1, foundStudent2); // fail!
        } catch (ServiceException e) {
            e.printStackTrace();
        }
    }
}

私のサービス実装の一部:

@Transactional(propagation=Propagation.REQUIRED)
public class UserServiceImpl implements UserService{

private UserDao userDao;

public AbstractUserEntity findUserByLogin(String login) throws ServiceException {
    Long userId = getUserDao().findUserByLogin(login);
    if(userId == null) {
        return null;
    }
    return getUserDao().findUser(userId);
}

public Long registerUser(AbstractUserEntity user) throws ServiceException {
    Long duplicateUserId = getUserDao().findUserByLogin(user.getLogin());
    if (duplicateUserId!=null) {
        throw new ServiceException("Użytkownik już istnieje");
    }
    return getUserDao().insertUser(user);
}
}

私のdao実装の一部:

@Repository
public class HibernateUserDao implements UserDao {

private EntityManagerFactory emf;

public EntityManagerFactory getEmf() {
    return emf;
}

@PersistenceUnit
public void setEmf(EntityManagerFactory emf) {
    this.emf = emf;
}

@Override
public Long insertUser(AbstractUserEntity user) {
    EntityManager em = emf.createEntityManager();
    try {
        em.getTransaction().begin();
        em.persist(user);
        em.getTransaction().commit();
    } finally {
        if (em != null) em.close();
    }
    return user.getId();
}

@Override
public Long findUserByLogin(String login) {
    EntityManager em = emf.createEntityManager();
    Long result;
    try{
        result = (Long) em.createNamedQuery("findUserByLogin").setParameter("login", login).getSingleResult();          
    } catch(NoResultException nre) {
        return null;
    }
    return result;
}

}

私のpersistence.xmlの一部

<persistence-unit name="JpaPersistenceUnit" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <properties>
        <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.DefaultNamingStrategy" />
        <property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect" />
        <property name="hibernate.hbm2ddl.auto" value="create-drop" />
        <property name="show_sql" value="true" />
    </properties>
</persistence-unit>

私のcore-context.xmlの一部

<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="transactionManager" />

<!-- a PlatformTransactionManager is still required -->
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManager">
        <ref local="atomikosTM" />
    </property>
    <property name="userTransaction">
        <ref local="atomikosUTX" />
    </property>
</bean>

<bean id="atomikosTM" class="com.atomikos.icatch.jta.UserTransactionManager" />
<bean id="atomikosUTX" class="com.atomikos.icatch.jta.UserTransactionImp" />

編集:

あなたの答えのためのThx。これで、キャッシュが必要であることがわかりました。「JPAでは、オブジェクトIDはEntityManager間で維持されません。各EntityManagerは、独自の永続コンテキストと、オブジェクトの独自のトランザクション状態を維持します。」persistence.xmlを変更しましたが、それでもテストは失敗します。

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
         version="2.0">
<persistence-unit name="JpaPersistenceUnit" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <class>amg.training.spring.model.StudentEntity</class>
    <class>amg.training.spring.model.SubjectEntity</class>
    <class>amg.training.spring.model.TeacherEntity</class>
    <class>amg.training.spring.model.AbstractUserEntity</class>
    <class>amg.training.spring.model.TeacherDegree</class>
    <class>amg.training.spring.dao.AbstractEntity</class>
    <shared-cache-mode>ALL</shared-cache-mode>
    <properties>
        <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.DefaultNamingStrategy" />
        <property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect" />
        <property name="hibernate.hbm2ddl.auto" value="create-drop" />
        <property name="show_sql" value="true" />
        <property name="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider"/>
        <property name="hibernate.cache.use_second_level_cache" value="true"/>
        <property name="hibernate.cache.use_query_cache" value="true"/>
    </properties>
</persistence-unit>

4

3 に答える 3

1

同じオブジェクトを取得するには、休止状態のクエリキャッシュを使用する必要があります。データベースにアクセスするクエリはすべて、個別のオブジェクトを作成します。

クエリキャッシュの有効化については、以下を参照してください:http: //docs.jboss.org/hibernate/orm/3.3/reference/en/html/performance.html#performance-querycache

于 2012-05-03T12:50:37.023 に答える
0

その理由assertSameは、ドキュメントに従って、値ではなくオブジェクトを比較するためです。

assertSame(java.lang.Object expected、java.lang.Object actual)-2つのオブジェクトが同じオブジェクトを参照していることを表明します。

学生を取得するたびStudentEntityに、同じデータベースエントリを参照しますが、新しいオブジェクトが作成されます。結果をキャッシュしてみてください。

于 2012-05-03T13:03:49.283 に答える
0

ついにそれを機能させることができました。キャッシュの不足は問題ではなかったと思います。リソース(この場合はEntityManagerFactory)を同じスレッドにバインドする必要があります。.bindResource()メソッドのドキュメントへのリンク

@PersistenceUnit
private EntityManagerFactory emf;
private EntityManager em;

@Before
public void setUp() {
    em = emf.createEntityManager();
    TransactionSynchronizationManager.bindResource(emf, new EntityManagerHolder(em));
}

@After
public void tearDown() {
TransactionSynchronizationManager.unbindResource(emf);
EntityManagerFactoryUtils.closeEntityManager(em);
}
于 2012-05-04T22:50:39.380 に答える