11

次のコードを想像してください。

foo() {
     Connection conn = ...;
}

foo()アノテーションを持つメソッドから呼び出されました@Transactional。現在の JDBC 接続を取得するにはどうすればよいですか? foo()Bean 内にあることに注意してください(@Autowiredフィールドを持つことができます) が、foo()パラメーターを持つことはできません (そのため、どこかから接続を渡すことはできません)。

[編集]データ ソースまたは接続が必要な jOOQ を使用しています。私の問題: どのトランザクション マネージャーが構成されているかわかりません。それは何でもかまいません。Java EE、DataSource ベース、JNDI 経由でデータ ソースを取得するもの。私のコードはアプリケーションではなく、ライブラリです。他の人が私の皿に載せたものを飲み込む必要があります。同様に、Hibernate セッション ファクトリを要求することもできません。これは、私を使用しているアプリケーションが Hibernate を使用していない可能性があるためです。

しかし、Spring Hibernate 統合などの他のコードは、何らかの方法でトランザクション マネージャーから現在の接続を取得できることを知っています。つまり、Hibernate は Spring のトランザクション マネージャーをサポートしていないため、グルー コードは Spring API を Hibernate が期待するものに適合させる必要があります。同じことをする必要がありますが、それがどのように機能するかわかりませんでした。

[編集 2]アクティブなトランザクションがあることはわかっています (つまり、Spring には接続インスタンスがどこかにあるか、少なくともそれを作成できるトランザクション マネージャーがあります) が、私のメソッドは @Transactional ではありません。パラメータとして受け取るコンストラクタを呼び出す必要がありjava.sql.Connectionます。私は何をすべきか?

4

6 に答える 6

14

おそらく、 APIDataSourceUtils.getConnection(dataSource)ごとに、データソースの現在の接続を返す必要があります。

更新: コメントとのソースコードに基づいてorg.springframework.transaction.support.TransactionSynchronizationManager:

私が言ったように、接続を取得するための鍵はデータソース名です。これが取得できない場合、ソースコードを見てこれを試すことが1つの方法です:

TransactionSynchronizationManager.getResourceMap()現在のスレッドでデータソースのマップを ConnectionHolder に返します。トランザクションに関与するリソースが 1 つだけであると仮定するとmap.values().get(0)、最初の ConnectionHolder を取得するために a を実行でき、そこから呼び出して接続を取得できます。.getConnection()

したがって、基本的に次のように呼び出します。

TransactionSynchronizationManager.getResourceMap().values().get(0).getConnection()

おそらくもっと良い方法があるはずです:-)

于 2012-08-02T14:46:52.027 に答える
9

(コメント スレッドに基づいて完全に書き直されました。なぜ私の元の回答が Hibernate に焦点を当てていたのかはわかりません。それ以外は、現在取り組んでいるものです)

トランザクション マネージャーは、データ ソースに対して完全に直交しています。一部のトランザクション マネージャーは、データ ソースと直接対話し、一部は中間層 (Hibernate など) を介して対話し、一部はコンテナーによって提供されるサービス (JTA など) を介して対話します。

メソッドを としてマークする@Transactionalと、Spring が Bean をロードするときにプロキシが生成され、Bean を使用したい他のクラスにそのプロキシが渡されることを意味します。プロキシのメソッドが呼び出されると、(プロキシ) はトランザクション マネージャに未処理のトランザクションを与えるか、新しいトランザクションを作成するように要求します。次に、実際の Bean メソッドを呼び出します。Bean メソッドが戻ると、プロキシはトランザクション マネージャーと再び対話し、「コミットできます」または「ロールバックする必要があります」と伝えます。このプロセスにはひねりがあります。たとえば、トランザクション メソッドは別のトランザクション メソッドを呼び出して、同じトランザクションを共有できます。

トランザクション マネージャはと対話しますが、 を所有DataSourceません。取引管理者に接続を求めることはできません。代わりに、接続を返すフレーム固有のオブジェクト ( Hibernate など) を挿入する必要があります。別の方法として、静的なトランザクション対応ユーティリティ クラスを使用することもできますが、これらも特定のフレームワークに関連付けられています。DataSourceSessionFactory

于 2012-08-02T15:08:05.317 に答える
7

Plain Jdbcを使用していると仮定します。次のことを行う必要があります。

BaseDao {
    @Autowired
    private DataSource dataSource;

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public Connection getConnection() {
        // ....use dataSource to create connection
        return DataSourceUtils.getConnection(dataSource);
    }
}

FooDao extends BaseDao {
    // your foo() method
    void foo() {
       Connection conn = getConnection();
       //....
    }
}
于 2012-08-02T14:29:30.180 に答える
5

これらすべてについて少しいらいらさせられるのは、Spring のドキュメントの大部分が、舞台裏の醜さを隠すマーケティング用語で書かれていることです。

明確な言葉で:

データ ソースは、要求が常に一意のスレッドによって処理されるという (ほぼ有効な) 仮定に基づいて、スレッド ローカル コンテキストに格納されます。

したがって、Spring がかなり複雑な方法で行うことは、現在の実行スレッドにローカルにデータを保存することです。これは簡単なことですが、Spring ドキュメント全体で十分に繰り返されていることは明らかではありません。Spring は基本的に、すべてのインターフェースとメソッド定義を介してプルすることを避けるために、あなたのものを「グローバルコンテキスト」に入れます。最初は少し魔法に見えますが、実際にはただのメイクです。

したがって、データを取得するために静的な DataSourceUtils メソッドを呼び出すことになります。

于 2012-08-07T09:35:23.347 に答える
3

JDBC で Spring トランザクションを使用している場合は、 を構成しJdbcTemplate、 を使用して現在のトランザクションにアクセスしJdbcTemplate.execute(ConnectionCallback)ます。これは、Spring によって構成された接続にアクセスする標準的な方法です。

于 2012-08-02T14:28:10.523 に答える