5

JBoss 7、Hibernate をデフォルトの JPA 実装として、JSF を Web フロントエンドとして使用する Seam 3 サンドボックス アプリケーションがあります。

SQL UPDATE がデフォルトで飲み込まれてしまうという問題があります。

会話スコープのステートフル EJB は、拡張スコープの EntityManager と 1 つのエンティティ、コンテナー管理トランザクションを維持します (新規が必要)

  1. EntityManager が注入される
  2. EJB は EM を使用してエンティティをロードし、それをフィールドに保持します。
  3. JSF アプリケーションは EJB とそのエンティティにアクセスし、文字列フィールドを変更します
  4. JSF アプリケーションが EJB の「Save」メソッドを呼び出す
  5. save() で、エンティティフィールドが変更されたかどうかを確認します->適切に変更されました
  6. save() が終了した後、コンテナーはトランザクションをコミットします。
  7. 問題: DB に対して SQL 更新が実行されません。

save() を次のように拡張すると:

a) entityManager.contains(entity) UPDATE が期待どおりに実行される (結果は「true」)

また

b) entityManager.persist(entity) UPDATE が期待どおりに実行される

Q: 私が理解している限りでは、a) または b) のいずれの仕様も必要とされるべきではありません。なぜなら、エンティティはプロセス全体を通して管理されたままであるからです。a) が節約に影響する理由がわかりません。b) は保存に効果があるとイメージできますが、必須ではないはずです。

どんな説明でも大歓迎です。

これが私のEJBです:

@Named
@ConversationScoped
@Stateful
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class LanguageBean {

    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager em;
    @Inject
    private UserTransaction transaction;

    private Language value;

    @Inject
    Conversation conversation;

    public LanguageBean() {
        super();
    }

    @Begin
    public void selectLanguage(Long anId) {
        conversation.setTimeout(10 * 60 * 1000);
        if (anId != null) {
            value = em.find(Language.class, anId);
        }
    }

    @BeforeCompletion
    public void transactionComplete(){
        System.out.println("transactionComplete");
    }

    public Language getValue() {
        return value;
    }

    @Produces
    @Named
    @ConversationScoped
    public Language getLanguage() {
        return getValue();
    }

    public void setValue(Language aValue) {
        value = aValue;
    }

    @End
    public String save() {
//      displays the changed attribute:
        System.out.println("save code: "+value.getCode());

//      why is either this required:
//      boolean tempContains = em.contains(value);
//      System.out.println("managed: "+tempContains);

//      or: why is persist required:
        em.persist(value);
        return "languages?faces-redirect=true";
    }

    @End
    public String cancel() throws SystemException {
        transaction.setRollbackOnly();
        return "languages?faces-redirect=true";
    }

}
4

2 に答える 2

1

私の経験は主に seam-2 に関するものですが、ここでも同様に適用できるはずです。

会話と JPA セッションは継ぎ目で分離されています。単純な理由は、会話が終了してもエンティティーが保存されない可能性があるためです。

たとえば、長時間実行されている会話でキャンセル アクションを実行すると、会話が終了します (会話を維持する理由がなくなるため)。

あなたの例でキャンセル時にロールバックを行っていることを考えると、@ user1187037 で提案されているようにフラッシュを呼び出す必要があることも論理的に思えます (理論的にはコミットですが、許可されていないと思います)。

会話の終了時にフラッシュするように設定できる構成があったと思いますが、間違っている可能性があります。

いずれにせよ、http://javalangblog.blogspot.co.uk/2010/04/flush-mode-conversation.htmlは解決策を示唆しているようです

それが役立つことを願っています。

編集:xmlを使用して、会話ごとにフラッシュモードを構成できます

<begin-conversation join="true" flush-mode="COMMIT" />

および注釈の使用

@Begin(flushMode=COMMIT)

ただし、会話は明示的に定義されていなくても @End できることに注意してください。ユーザーが会話の途中でエンティティに変更を加えた後、会話を放棄した場合、タイムアウト後に自動的に閉じられます。私の記憶が正しければ、これにより、上記の場合に変更がコミットされます。

参考文献:

http://docs.jboss.org/seam/3/persistence/3.0.0.Alpha1/reference/en-US/html_single/#d0e249 http://docs.jboss.org/seam/3/latest/api/ org/jboss/seam/persistence/FlushModeType.html

于 2012-10-17T23:08:23.560 に答える
0

@Removeでアノテーションが付けられたメソッドにアノテーションを追加してみてください@End

私の意見では、@End注釈はBeanの破壊にはなりません。そのため、永続コンテキストはsave()実行後もアクティブであり、そのコンテンツをデータベースにフラッシュすることはできません。

于 2012-03-16T10:39:56.547 に答える