0

@Transactionalの境界をできるだけ短くする必要があることを理解しています。コードは次のとおりです。

Springの依存性注入を通じてuserDAOオブジェクトを使用しています:

private static ApplicationContext context ;
private UserDAO userDAO;

public TransactionsTest() {
    userDAO = (UserDAO) context.getBean("userDAO");
} 

データの挿入/更新にuserDAOを使用しようとしているクラスtestSaveUserAccounts()から呼び出しています。TransactionsTest

ケース1:

@Transactional
public void testSaveUserAccounts() {
    UserAccounts userAccounts = new UserAccounts();
    userAccounts.setCommunityId(10L);
    userDAO.saveObject(userAccounts);
}

// This method is inside UserDAO
        public void saveObject(Object object) {
        entityManager.merge(object);
    }

ケース2:

@Transactional
public void testSaveUserAccounts() {
    UserAccounts userAccounts = new UserAccounts(); 
    userAccounts.setCommunityId(10L);
    userDAO.saveObject(userAccounts);
}

// This method is inside UserDAO
    @Transactional(propagation=Propagation.REQUIRED)
    public void saveObject(Object object) {
        entityManager.merge(object);
    }

春のコンテキスト:

    <tx:annotation-driven transaction-manager="transactionManager" />

        <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
            <property name="entityManagerFactory" ref="entityManagerFactory" />
        </bean>

        <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

        <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
            <property name="dataSource" ref="dataSourceLocal" />
            <property name="jpaVendorAdapter">
                <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
            </property>
            <property name="persistenceUnitName" value="spring-jpa" />
      </bean>

UserDAO:

@Repository
public class UserDAO extends BaseDAO {

    @Transactional(propagation=Propagation.REQUIRED)
    public void saveObject(Object object) {
        entityManager.merge(object);
    }

}

BaseDAO:

public abstract class BaseDAO {

    protected EntityManager entityManager;
    protected HashMap<String,Long>  eventIdMap = new HashMap<String,Long>();


    @PersistenceContext
    public void setEntityManager(EntityManager entityManager) {
        this. entityManager = entityManager;
    }


    public <T> T getById(final Class<T> clazz, final Serializable id) {
        T object = clazz.cast(entityManager.find(clazz, id));
        return object;
    }


    @Transactional
    public Object save(Object ob) {
        Object object = entityManager.merge(ob);
        return object;
    }


    @Transactional
    public void persist(Object ob) {
        entityManager.persist(ob);
    }


    @SuppressWarnings("unchecked")
    public <T>  ArrayList<T> getAll(final Class<T> clazz) {
        String hqlQuery = "from "+ clazz.getSimpleName();
        ArrayList<T> list  = (ArrayList<T>)entityManager.createQuery(hqlQuery).getResultList();
        return list;
    }

}

私はいくつかのトランザクション境界、、などを実験してきREQUIREDましREQUIRES_NEWSUPPORTSが、ケース1(メソッド1のトランザクション境界内にあるmethod2が呼び出された場合)がデータをマージしない理由を自信を持って理解できませんでしたが、これはケースで解決されます2.2。

トランザクション境界内で関数の呼び出しをすでにマークしているのに、内部メソッドでも@Transactionalを指定する必要があるのはなぜですか?

4

2 に答える 2

1

トランザクションテストクラスはSpringBeanではないため、ケース1は機能しません。Springは、メソッドに@Transactionalが含まれていることを検出する必要があり、SpringがBeanをSpringBeanファクトリに登録するときに検出します。

また、同じBean内でプロキシベースのAOP呼び出しを行っている場合、AspectJロードタイムウィービングまたはAspectJコンパイルタイムウィービングを使用しない限り、トランザクションアスペクトによってキャッチされないことに注意してください。

また、Daoに@Transactionalを配置することは、トランザクションの境界がサービスレイヤーで最も適切にマークされるため、実際には良い考えではありません。その理由は、特定のサービスメソッドが複数のDaoと対話する必要があり、Daoを分析して伝播動作を確認するのではなく、それらのDaoのアクションをサービスレイヤーによって開始されるtxの一部にする必要があるためです。

テストクラスの完全なコードを投稿できますか?

于 2012-06-25T21:24:39.203 に答える
0

@Transactionalはローカルでは何もしません。別のサービスから呼び出された場合にのみ、効果があります。つまり、トランザクションアノテーションが何かを行うには、現在のコンテキストを離れる必要があります。したがって、メソッド1の呼び出しはどちらの場合も同じです。ケース2は、メソッド2が別のサービスから呼び出された場合にのみ何も実行しません。

于 2012-06-25T18:52:26.363 に答える