0

休止状態で何らかのアクションを実行するたびに、アプリケーションに次のコードがあります。

Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
session.save(obj); //or delete, update etc.
session.getTransaction().commit();
session.close();

もちろん、これは良い習慣ではありません。休止状態にアクセスし、このような状況にならないようにする最良の方法は何ですか? 同じ仕事をする静的メソッドを含む「Util」クラスを使用する必要がありますか? 多分シングルトンの方が良いですか?また、データベースへのアクセス中に GUI がフリーズしないように、このコードをスレッドまたは SwingWorker でラップする必要があります。

4

3 に答える 3

0

はい、そのコードはかなり悪いです。

  1. データベースにアクセスするたびにトランザクションを開きます。これは非効率的であり、おそらく正しくありません (通常、アクションのグループ全体がアトミックである必要があります。たとえば、

    public void buy(String accountId) {
        Account account = load(accountId);
        account.balance -= 100;
        save(account);
    }
    

    読み込みと保存がそれぞれのトランザクションで行われ、悪意のあるユーザーが同時に 2 つのアイテムを購入した場合、次のことが発生する可能性があります。

    • スレッド 1 は残高 (=1000) を読み取ります
    • スレッド 2 は残高 (=1000) を読み取ります
    • スレッド 1 は残高 (=900) を書き込みます
    • スレッド 2 は残高 (=900) を書き込みます

    そのため、ユーザーは 2 回購入しましたが、支払いは 1 回だけでした ;-)

  2. save() が例外をスローした場合、トランザクションは終了しません。実際、トランザクションは、保持しているすべてのロックを含め、無期限に開いたままになります...

このような複雑さは、ほとんどの人が、たとえばSpringEJBを使用して四角い車輪を再発明するのではなく、宣言的にトランザクションを区別する理由です。

于 2012-09-10T01:39:50.927 に答える
0

Hibernate サイトからこの記事を読むことを強くお勧めします。

この記事は、Hibernate でセッションとトランザクションを使用する最善の方法を考えている人にとって必読です。

基本的に、最適な設計パターンは、選択したトランザクション管理戦略 (jdbc、jta) とトランザクションの適用モード (プログラム/宣言型) によって異なります。

メリットンによって既に指摘されているように、コード内の各メソッドのトランザクションを開いたり閉じたりすることは (アトミック操作を形成するために順次動作するいくつかのメソッドがあると仮定して) アンチパターンです。これについても、記事で詳しく説明しています。

于 2012-09-10T10:55:00.230 に答える
0

解決するには、accountIdに基づいてrenentranlockを取得することだと思います

@Service
public class AccountService {
    private Map<String, ReentrantLock> locks = new HashMap<Long, ReentrantLock>();

    private void unlock(String id) {
        ReentrantLock lock = locks.get(id);
        if (lock != null && lock.isLocked()) {
            lock.unlock();
        }
    }

    private void lock(String id) {
        ReentrantLock lock;
        synchronized (locks) {
            lock = locks.get(id);
            if (lock == null) {
                lock = new ReentrantLock();
                locks.put(id, lock);
            }
        }
        lock.lock();
    }

public void buy(String accountId) {
    this.lock(accountId);
    try{
       Account account = load(accountId);
       account.balance -= 100;
       save(account);
    }finally{
      this.unlock(accountId);
    }
   }
}

この機能がアプリケーション全体で必要な場合は、サービスよりもアスペクトを記述するのが賢明かもしれません。

于 2012-09-10T05:52:59.947 に答える