7

スタンドアロンのJavaアプリケーションの一部として実行されるデータアクセスクラスがあります。現在動作しています。つまり、トランザクションマネージャーが定義されていますが、クラスをリファクタリングしてトランザクションのスコープを縮小したいのですが、実行するとorg.hibernate.HibernateException:スレッドにバインドされたHibernateセッションがなく、構成で許可されませんここで非トランザクションのものを作成します。これは、 @ Transactionalを移動すると認識されなくなることを意味します。

私の元のバージョンでは、リファクタリングされたメソッドがプライベートでしたが、場合によってはアノテーションが取得されないため、パブリックに変更することをお勧めします。

public class DoStuff {
    @Transactional
    public void originalMethod() {
        // do database stuff
        ...

        // do non-database stuff that is time consuming
        ...
    }
}

私がやりたいのは、次のようにリファクタリングすることです

public class DoStuff {
    public void originalMethod() {
        doDatabaseStuff()

        doNonDatabaseStuff()
    }

    @Transactional
    public void doDatabaseStuff() {
        ...
    }

    public void doNonDatabaseStuff() {
        ...
    }
}
4

2 に答える 2

8

編集:

リファクタリングが機能しない理由を理解するには、Springプロキシがどのように機能するかを理解する必要があります。

オブジェクト参照のメソッド呼び出しはプロキシの呼び出しであるため、プロキシはその特定のメソッド呼び出しに関連するすべてのインターセプター(アドバイス)に委任できます。ただし、呼び出しが最終的にターゲットオブジェクトに到達すると、それ自体で行う可能性のあるメソッド呼び出しは、プロキシではなく、この参照に対して呼び出されます。これには重要な意味があります。これは、自己呼び出しによって、メソッド呼び出しに関連するアドバイスが実行される機会が得られないことを意味します。

@TransactionalはSpringAOPを使用し、Springはプロキシを使用します。これは、別のクラスから@Transactionalメソッドを呼び出すと、Springがプロキシを使用するため、トランザクションアドバイスが適用されることを意味します。ただし、同じクラスからメソッドを呼び出す場合、Springはプロキシの代わりに「this」参照を使用するため、トランザクションのアドバイスは適用されません。

元の回答:

これが同様のシナリオで私のために働いたものです。

public class DoStuff implement ApplicationContextAware {    
private ApplicationContext CONTEXT;
public void setApplicationContext(ApplicationContext context) throws BeansException {
    CONTEXT = context;
}

    public void originalMethod() {           
        getSpringProxy().doDatabaseStuff()              
        doNonDatabaseStuff()       
    }

    private DoStuff getSpringProxy() {
        return context.getBean(this.getClass());     
    } 
    @Transactional       
    public void doDatabaseStuff() {           
        ...       
    }          

    public void doNonDatabaseStuff() {           
        ...       
    }   
} 

説明:

  1. クラスApplicationContextAwareを作成して、コンテキストへの参照があるようにします
  2. トランザクションメソッドを呼び出す必要がある場合は、コンテキストから実際のスプリングプロキシをフェッチします
  3. このプロキシを使用してメソッドを呼び出し、@Transactionalが実際に適用されるようにします。
于 2012-08-23T13:30:51.723 に答える
0

あなたのアプローチはうまくいくはずです。この問題はSpringプロキシに関連していると思います。

インターフェイスについて質問した理由は、Springがトランザクション動作を適用するデフォルトの方法であるJDK動的プロキシに関連しています。

クラスの実際の定義が次の場合:

public class DoStuff implements Doable {
  public void originalMethod() {

  }
}

public interface Doable {
  public void originalMethod();
}

これが実際に構造体である場合、新しい構造体に移動すると、Springは新しいdoDatabaseStuffメソッドをプロキシできません。

これを修正するためのオプション:

  • 新しいメソッドをインターフェースに追加して、Springがそれらをプロキシできるようにします
  • CGLIBベースのプロキシの使用に移行します(これらはインターフェイスに依存しません)
于 2012-08-23T19:08:07.827 に答える