- PR -

hibernate + PostgreSQLのリードロック動作について

1
投稿者投稿内容
MasaGon
会議室デビュー日: 2005/10/11
投稿数: 2
投稿日時: 2005-10-11 14:31
初めて投稿させていただきますMasaGonと申します。
DB初心者ですので、初歩的な質問かもしれませんが、よろしくお願いします。

hibernate3 + PostgreSQLのリードロックの動作についてお伺いします。
下記のようなDAOを用いて、Servletから、「当該idをもつレコードが存在しなければinsert、存在すれば無視」という処理を行いたいのですが、どうやらこの処理はスレッドセーフで無いようで、obj == null の処理中(commit前)に、別のスレッドによりobj == nullが呼び出されてしまい、同一キーに対して、saveが重複実行されてしまう事があるようです。

この場合、obj == null 時の動作ですから、トランザクション処理により、レコードに対してリードロックはかけられないという事なのでしょうか。この場合、悲観的ロックかつテーブル全体に対してロックをかけなければならないのでしょうか。

もし、そうだとすれば、意図した動作を実現させるにはどのような記述を行ったら良いでしょうか。お知恵を拝借できれば、幸いです。

コード:
public void insertUnlessExisting( Class theClass, Serializable id, Serializable record )
{
	Session session = null;
	Transaction transaction = null;
	try
	{
		session = getSession();
		transaction = session.beginTransaction();
		Serializable obj = (Serializable)session.get( theClass, id );
		if( obj == null )
		{
			session.save( record );
		}
		transaction.commit();
	}
	catch( HibernateException ex )
	{
		try
		{
			transaction.rollback();
		}
		catch( HibernateException ignore ){}
		throw new RuntimeException( ex.getMessage() );
	}
	finally
	{
		closeSession( session );
	}
}


あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2005-10-12 01:01
読み込みと書き込みが複数の操作に分かれているので無理です。
素直に(存在すれば)親エンティティやテーブルをロックしましょう。

Oracleなどでは、とりあえずsave()して、主キー制約違反の例外が
発生したら何もせずにトランザクションを継続する手もありますが、
PostgreSQLではエラー発生時にロールバック専用と扱われてしまう
ためこの手法は使えないことが多いと思います。

オススメは関連的に親となるエンティティのUPGRADEロックかと。
MasaGon
会議室デビュー日: 2005/10/11
投稿数: 2
投稿日時: 2005-10-12 14:27
あしゅさん、こんにちは。
早速の回答有難うございます。

やはり、無理ですか。今回の案件では親エンティティを作成していなかったのですが、その方向で検討してみます。

引用:
Oracleなどでは、とりあえずsave()して、主キー制約違反の例外が
発生したら何もせずにトランザクションを継続する手もありますが、
PostgreSQLではエラー発生時にロールバック専用と扱われてしまう
ためこの手法は使えないことが多いと思います。



ロールバック専用とはどういう事なのか、具体的に理解していないのですが、今回の処理の場合はロールバックを行っても結果は変わらないような気がします。この場合、ロールバックを行った上で、例外を無視する(上記ソースでRuntimeExceptionを投げるのをやめる)という方法で何か問題はありますか?(なんとなく気持ちは悪いですが...)
1

スキルアップ/キャリアアップ(JOB@IT)