2

よろしければ、Spring のトランザクションについていくつか質問があります。このDAOクラスがあるとしましょう:

public class MyDAO {

    /**
    * verifies if a certain record in DB contains 'True' in a certain Column named publishFlag
    */
    @Transactional
    public bloolean isBeingPublished(Long recordID){
    ...
    }

    /**
    * sets the record's publishFlag column to true indicating that it's being published
    */
    @Transactional
    public boolean setBeingPublished(Long recordID){
    ...
    }

}

そしてそれを使用する次のクラス:

public class MyClass {

    @Autowired
    MyDAO dao;

    public void publishRecords(List<Long> ids){

        for(Long id : ids){
            if(!dao.isBeingPublished(id)){
                dao.setBeingPublished(id);
                //do something to publish the record
            }
        }

    }
}

私の質問は次のとおりです。

  • まず、!dao.isBeingPublished(id)anddao.setBeingPublished(id)は同じトランザクションで実行されますか、それとも別のトランザクションで実行されますか?

  • 2 番目の質問は同時実行性に関するものです。複数のMyClassインスタンスを作成でき、publishRecordメソッドへの同時呼び出しが発生する可能性があるため、2 つの同時呼び出し!dao.isBeingPublished(id)が両方とも同じ結果をもたらし、レコードが 2 回公開される可能性があります。 同期を作成することを検討しpublishRecordsますが、アプリケーションが複数のサーバーに展開されると、同期宣言が役に立たなくなる可能性があります。データベースは、それらのサーバーに展開されたアプリ間の唯一の共有リソースであるため、トランザクションに関する質問です。

私の問題の正確な解決策は何ですか?春のトランザクションの伝播について読んだところREQUIRES_NEW、現在実行中のトランザクションでも新しいトランザクションが作成されることがわかりましたが、それでも、それがどのように問題の解決策になるのかわかりません。

よろしくお願いいたします。

4

2 に答える 2

3

考慮する必要のあることはほとんどありません。DAOは単一エンティティの操作に焦点を合わせており、サービスは1つ以上のエンティティの操作に焦点を合わせているため、トランザクションはサービスレイヤーに配置する必要があります。これにより、トランザクションなしでDAOの操作を再利用できますが、サービスに決定を任せることができます。トランザクションの開始時と終了時

  1. これは単一のトランザクションではなく、2つの別個のトランザクションです。
  2. これは、現在の設計での同時実行の問題です。次の提案を参照してください。

インターフェース

public interface MyClass {
    public void publishRecords(List<Long> ids);
}

実装

@Service
@Transactional(readOnly = false)
class DefaultMyClass implements MyClass  {

    @Autowired
    MyDAO dao;

    // single transaction
    @Override
    public void publishRecords(List<Long> ids) {
        for(Long id : ids){
            if(!dao.isBeingPublished(id)){
                dao.setBeingPublished(id);
                //do something to publish the record
            }
        }
    }
}

DAO

class MyDAO {

    public bloolean isBeingPublished(Long recordID){
        // bigbang
    }

    public boolean setBeingPublished(Long recordID){
        // bigbang
    }
}

上記の設計を使用して、両方の問題が解決されています。

于 2012-04-20T14:47:52.943 に答える
1

まず、!dao.isBeingPublished(id)とdao.setBeingPublished(id)は、同じトランザクションで実行されますか、それとも別々のトランザクションで実行されますか?

スタックのさらに上に注釈が付けられたメソッドがない限り@Transactional、それらは別々のトランザクションで発生するため、競合状態になる可能性があります。

私があなたなら、データベースの行ロックを取得して公開操作を実行できたかどうかのブール値isBeingPublishedを返すsetBeingPublished単一のメソッドを使用して、を使用します。@Transactional publishIfPossible

于 2012-04-20T14:47:50.983 に答える