8

まず、アプリケーションには複数のJDBCデータソースがあるため、宣言型@Transactionalアプローチを使用できません。詳細に飽きたくありませんが、DAOメソッドに正しいデータソースが渡されてロジックが実行されると言えば十分です。 。すべてのJDBCデータソースは同じスキーマを持っており、ERPシステムのRESTサービスを公開しているため、それらは分離されています。

このレガシーシステムのために、私が制御できない長期間有効なロックされたレコードがたくさんあるので、ダーティリードが必要です。

JDBCを使用して、次のことを実行します。

private Customer getCustomer(DataSource ds, String id) {
    Customer c = null;
    PreparedStatement stmt = null;
    Connection con = null;
    try {
        con = ds.getConnection();
        con.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
        stmt = con.prepareStatement(SELECT_CUSTOMER);
        stmt.setString(1, id);
        ResultSet res = stmt.executeQuery();
        c = buildCustomer(res);
    } catch (SQLException ex) {
        // log errors
    } finally {
        // Close resources
    }
    return c;
}

さて、ボイラープレートがたくさんあります、私は知っています。JdbcTemplate春を使っているので試してみました。

JdbcTemplateを使用する

private Customer getCustomer(JdbcTemplate t, String id) {
    return t.queryForObject(SELECT_CUSTOMER, new CustomerRowMapper(), id);
}

はるかに優れていますが、デフォルトのトランザクション分離を使用しています。どういうわけかこれを変更する必要があります。だから私はを使用することを考えましたTransactionTemplate

private Customer getCustomer(final TransactionTemplate tt,
                             final JdbcTemplate t,
                             final String id) {
    return tt.execute(new TransactionCallback<Customer>() {
        @Override
        public Customer doInTransaction(TransactionStatus ts) {
            return t.queryForObject(SELECT_CUSTOMER, new CustomerRowMapper(), id);
        }
    });
}

しかし、ここでトランザクション分離を設定するにはどうすればよいですか?コールバックまたはこれを行うためのどこにもそれを見つけることができませんTransactionTemplate

Spring in Action、Third Editionを読んでいますが、トランザクションに関する章では引き続きアノテーション付きの宣言型トランザクションを使用していますが、前述のように、DAOがで決定する必要があるため、これを使用することはできません。提供された引数(私の場合は国コード)に基づいてデータソースが使用するランタイム。

どんな助けでも大歓迎です。

4

4 に答える 4

6

私は現在、DataSourceTransactionManager直接を使用してこれを解決しましたが、最初に望んでいたほどボイラープレートを節約していないようです。誤解しないでください。もっと簡単な方法があるに違いないと感じずにはいられませんが、よりクリーンです。読み取り用のトランザクションは必要ありません。分離を設定したいだけです。

private Customer getCustomer(final DataSourceTransactionManager txMan,
                             final JdbcTemplate t,
                             final String id) {
    DefaultTransactionDefinition def = new DefaultTransactionDefinition();
    def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);

    TransactionStatus status = txMan.getTransaction(def);
    Customer c = null;
    try {
        c = t.queryForObject(SELECT_CUSTOMER, new CustomerRowMapper(), id);
    } catch (Exception ex) {
        txMan.rollback(status);
        throw ex;
    }
    txMan.commit(status);
    return c;
}

もっと良い方法があるに違いないと本当に信じているので、しばらくの間、これには答えないままにします。

Spring 3.1.x ドキュメント - 第 11 章 - トランザクション管理を参照してください。

于 2012-07-27T05:41:37.827 に答える
4

ここでヘルプを使用して、TransactionTemplate適切に構成する必要があります。トランザクション テンプレートには、トランザクション構成も含まれています。実際にはTransactionTemplate拡張しDefaultTransactionDefinitionます。

したがって、構成のどこかにこのようなものが必要です。

<bean id="txTemplate" class=" org.springframework.transaction.support.TransactionTemplate">
  <property name="isolationLevelName" value="ISOLATION_READ_UNCOMMITTED"/>
  <property name="readOnly" value="true" />
  <property name="transactionManager" ref="transactionManager" />
</bean>

TransactionTemplate次に、この Bean をクラスに注入すると、以前に投稿/試したベースのコードを使用できるはずです。

ただし、コードをクリーンアップできるより良い解決策があるかもしれません。私が取り組んだプロジェクトの 1 つで、あなたと同じようなセットアップがありました (単一アプリの複数データベース)。このために、基本的に必要に応じてデータソースを切り替えるいくつかのスプリング コードを作成しました。詳細については、こちらをご覧ください

それがあなたのアプリケーションにとって非常に難しいかやり過ぎである場合はAbstractRoutingDataSource、ルックアップキー(あなたの場合は国コード)に基づいて使用する適切なデータソースを選択するSpringの を試して使用することもできます。

これら 2 つのソリューションのいずれかを使用することで、Spring の宣言型トランザクション管理アプローチの使用を開始できます (コードを大幅にクリーンアップする必要があります)。

于 2013-08-21T07:48:09.637 に答える