0

Swing ベースのデスクトップ アプリケーションで JPA を使用しています。これは私のコードがどのように見えるかです:

public Object methodA() {

  EntityManager em = emf.createEntityManager();
  em.getTransaction().begin();
  boolean hasError = false;

  try {
       SwingUtilities.invokeLater(new Runnable() {
           public void run() {
              // JPA operation does not work here 
              // because transaction has been committed!
           }
       });
       ...
       return xXx;
  } catch (Exception ex) {
       hasError = true;
       em.getTransaction().rollback();
  } finally {
       em.close();
       if (!hasError) {
          em.getTransaction().commit();
       }
  }
  return null;    
}

try - catch - finallyトランザクションを必要とするすべてのメソッドにこれを使用しています。を持つメソッドを除いて、期待どおりに機能していSwingUtilities.invokeLater()ます。

finally新しいスレッドのすべてのコードが実行される前に到達します。したがって、 内SwingUtilities.invokeLater()に JPA 操作がある場合、トランザクションがコミットされているため失敗します。

try - catch - finally内部のコードを含むすべてのコードが実行された後にのみトランザクションがコミットされることを確認するために従うことができる一般的なユースケースはありSwingUtilities.invokeLater()ますか?

4

1 に答える 1

1

アプローチを再考する必要があります。まず第一に、SwingUtilities.invokeLater()JPA 操作を実行するための最良の選択ではありません。このユーティリティ メソッドの主な目的は、UI の更新です。コードに関しては、JPA 操作用に別のスレッドを実装します。このスレッドは、トランザクション ステータスのリスナーを受け取ります。トランザクションが完了したら、UI を更新します。

/**
 * Transaction callback.
 */
public interface TransactionListener {
    void onTransactionFinished(boolean hasError);
}

/**
 * Worker Thread which takes data and performs JPA operations.
 */
public class JPATask implements Runnable {
    private final Object dataToPersist;
    private final TransactionListener transactionListener;

    public JPATask(Object dataToPersist,
            TransactionListener transactionListener) {
        this.dataToPersist = dataToPersist;
        this.transactionListener = transactionListener;
    }

    private EntityManager getEntityManager() {/* code is omited */}

    @Override
    public void run() {
        EntityManager em = getEntityManager();
        try {
            em.getTransaction().begin();
            // perform JPA actions here
            em.getTransaction().commit();
            transactionListener.onTransactionFinished(false);
        } catch (Exception ex) {
            em.getTransaction().rollback();
            transactionListener.onTransactionFinished(true);
        }
    }
}

/**
 * Finally you method. Now it looks like this.
 */
public Object methodA() {
    JPATask jpaTask = new JPATask(<data to persist>, new TransactionListener() {
        @Override
        public void onTransactionFinished(boolean hasError) {
            // Update UI. It's time to use SwingUtilities.invokeLater() 
        }
    }).start();     
}
于 2013-05-06T18:24:19.230 に答える