休止状態とバージョン管理に問題があります。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 スニペットが機能しないのはなぜですか?