2

休止状態とバージョン管理に問題があります。Hibernate 3.6.7-Final を使用しています。これは私の DAO クラスのコード スニペットです (@Transactional アノテーションを使用する Spring Bean によって呼び出されるため、それ自体はトランザクションではありませんが、StaleObjectStateException を強制するためにフラッシュが使用されます)。

@Override
public void save(User user) {
    boolean saved = false;
    while (!saved) {
        try {
            sessionFactory.getCurrentSession().saveOrUpdate(user);
            sessionFactory.getCurrentSession().flush();
            saved = true;
        } catch (StaleObjectStateException exc) {
            sessionFactory.getCurrentSession().refresh(user);
        }
    }
}

バージョンは、次のようにマッピングされた長い値です。

<version name="version" access="field" column="version" type="long" unsaved-value="null" />

問題は、ユーザーが保存されず、コードが永遠にループすることです。少しデバッグしたところ、hibernate には ActionQueue の概念があり、内部には別のコレクションに挿入、更新などがあることがわかりました。上記のコードのすべてのループで、更新コレクションは 1 ずつ大きくなります。「古い」コレクションであるそのコレクションのインデックス 0 で常に更新を実行しようとするため失敗し、その時点で失敗し、実行されません。更新されたバージョンで更新を実行してみてください。これを機能させる方法はありますか?

おそらく私がやりたいことについての背景があるので、より賢い人がより良い解決策を提案できるかもしれません.バージョン管理がなく、ユーザーが無効なログインカウントを含む列を持っているとします. このカウントは、失敗するたびに 1 ずつ増加し、ログインが成功するとリセットされます。(これを使用して、アカウントへのブルート フォースを防ぐために、x 回失敗した後にユーザーがログインできるようになるまでのタイムアウトを導入しますが、これはここでは関係ありません。) ここで、攻撃者が攻撃を使用するとします。サーバー上の複数のスレッドから同じユーザーアカウントにアクセスできます.2つのスレッドが失敗回数、たとえば2でユーザーを読み取ると、スレッド1がそれを3に更新して保存し、次にスレッド2がそれを3に更新して保存します-失敗した試行が 1 回失われましたが、これはバグです。

したがって、これを修正するために、バージョン管理列を導入したいと思いました。この場合、上記のスレッド 2 によって例外がスローされるという他の目的には役立たず、その場合、操作が再試行されます (潜在的に、しかし高度にありそうにない、ループ内) - 基本的に、これはユーザーを保存するシリアライゼーションを導入しますが、楽観的ロックに基づいています。これは、前述のとおり、機能しません。

誰でもこれで私を助けることができますか? これは始めるのに良い考えですか?多分もっと良い方法がありますか?Hibernate スニペットが機能しないのはなぜですか?

4

1 に答える 1

0

更新を実行するには、おそらく新しいセッションが必要です。原則として、例外が発生した後にセッションを使用しないでください。

詳細については、このスレッドを読むことができます。TL; DR:休止状態によってスローされた例外は回復できません。ロールバックし、セッションを閉じて、最初からやり直す必要があります。

于 2013-01-07T00:54:58.163 に答える