0

インスタンス化後にオブジェクトをデータベースからオブジェクト キャッシュにロードするサービス Bean があります。DAO オブジェクト メソッドを呼び出すサービス メソッドに @Transactional というラベルを付けると、「HibernateException: 現在のスレッドのセッションが見つかりません」というエラーが発生します。ただし、DAO クラスに @Transactional というラベルを付けると、そのようなエラーは発生せず、正常に動作します。

問題は、サービス オブジェクト内の同じメソッドから複数の DAO 呼び出しを行うことができず、それを 1 つのトランザクションにすることができないことです。これを引き起こす原因について何か考えはありますか?

Spring 3.1 と Hibernate 4 を使用しています。

DAO の例:

@Repository
public class HibernateObjectDao implements ObjectDao {

    SessionFactory sessionFactory;

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public List<Object> getObjects() {
        return sessionFactory.getCurrentSession()
            .createQuery("from Object").list();
    }
}

サービス Bean の例:

@Service
public class MyServiceBean implements AbstractMyServiceBean
{


    @Resource
    private ObjectDao objectDao;

    private HashMap<String,Object> objectCache;


    public MyServiceBean() {
        this.objectCache = new HashMap<String,Object>();
    }


    @Autowired
    public void setObjectDao(ObjectDao objectDao) {
        this.objectDao = objectDao;
    }


    @Transactional
    public void initialize() {
        loadObjectCache();
    }

    public void loadObjectCache() {
        objectCache.put("stuff",this.objectDao.getObjects())
    }
}

ApplicationContext.xml の抜粋:

<bean id="objectDao" class="com.example.persistence.HibernateObjectDao">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<bean id="myServiceBean"
    class="com.example.service.MyServiceBean" 
    init-method="initialize">
    <property name="objectDao" ref="objectDao" />
</bean>
4

2 に答える 2

3

メソッドは、注入された Bean のインスタンスを使用して Bean の外部から呼び出された場合、実際には実際の Bean インスタンスのトランザクション プロキシです。

Spring は、トランザクション プロキシではなく、Bean インスタンスで直接初期化メソッドを呼び出すため、メソッドはトランザクションで呼び出されません。

注入された MyServiceBean を使用してそのinitialize()メソッドを呼び出す別の Bean に初期化メソッドを配置します。

于 2012-06-13T17:31:15.400 に答える
0

問題は、Spring 呼び出しの初期化時に Bean の周りにトランザクション プロキシがないことです。Bean は初期化されるまで使用する準備ができていないという哲学があるため、これは意図的なものです。

いくつかの解決策:

  • 初期化時のデータ処理のこの特殊なケースでは、 TransactionTemplateまたは session.beginTransaction()を介して手動のトランザクション処理を行います。JPA/Hibernate を使用する場合は、次のようなコードを使用して EntityManager を Transaction Synchronizer に追加します。

    EntityManager em = entityManagerFactory.createEntityManager();
    TransactionSynchronizationManager.bindResource(entityManagerFactory, new EntityManagerHolder(em));
    
  • アプリケーション内のすべての初期化タイプのイベントに対して別の Bean を作成し、それが他の Bean を呼び出せるようにします。その時までに、他のすべての Bean の準備が整い、Spring はそれらの周りにトランザクション プロキシを配置します。注: 特定の Bean が 2 回初期化されるため、この Bean から init-method として設定されたメソッドを呼び出さないでください。これは常に正常であるとは限りません :) この目的のために別のメソッドを作成します。

  • ApplicationListenerを使用します。これにより、コールバックを登録し、コンテキストの初期化が完了したことを示す兆候としてContextRefreshedEventを処理できます。

于 2012-06-13T21:05:19.963 に答える