2011年2月16日水曜日

Kuina-Daoで行ロック、テーブルロック

Kuina-DaoはS2ファミリーでJavaEE5のO/Rマッピング標準です。
JPA上で利用可能なDAOフレームワークで、インタフェースを定義する
だけで動的な問い合わせを生成してくれます。
SQLファイルを利用した問い合わせもできます。
http://kuina.seasar.org/ja/


今回はKuina-Daoで行ロック、テーブルロックはどのようにやるかのメモです。


行ロック
■javax.persistence.EntitiyManagerを使用する場合
TestEntitiy entity = testDao.find(pkey);
EntityManager em = SingletonS2Container.getComponent(EntityManager.class);
em.lock(entity, LockModeType.WRITE); //またはem.lock(entity, LockModeType.READ);
em.flush();

■org.seasar.kuina.dao.GenericDaoを継承したDaoを使用する場合
TestEntity entity = testDao.find(1);
testDao.writeLock(entity); //またはtestDao.readLock(entity);

LockModeType.READはreadLock、LockModeType.WRITEはwriteLockに対応しています。
LockModeTypeとしてLockModeType.WRITEを指定すると、エンティティの状態変更がない場合でもバージョン列は強制的に更新されます。
バージョン列の更新はflushまたはコミットのタイミング。


テーブルロック
テーブルロックはざっと見たところ、Entityを使用してはできなさそうなので、
SQLファイルを利用した方法しかなさそうです。

■Daoインターフェース
public interface  LockTableDao {
    void deleteLockTable();
}

■SQL(LockTableDao_deleteLockTable.sql)
LOCK TABLE appparam IN EXCLUSIVE MODE;

■実行
lockTableDao.deleteLockTable();


Kuina-Daoはメソッドの名前や引数・戻り値から実行すべき操作を判断するので、
戻り値をvoidにする場合は(insert|update|delete|remove)が先頭に付けないと駄目ですね。
http://kuina.seasar.org/ja/user_guide/dao.html#メソッド



Kuina-Daoはあまり人気ないようですが、使いやすくていいですね。
でも複雑な問い合わせはSQLにならざるをえない。。

S2Dao後継のDomaそろそろさわってみようかな。
AnnotationProcessingTool(apt)を利用したJava6(JDBC4.0)対応のO/Rマッパーとその開発支援ツール。
http://doma.seasar.org/
Seasar2への依存なしってのがいいですね!

2011年2月3日木曜日

java synchronized 排他の相互関係まとめ

synchronizedの排他関係について気になったので整理しました。

staticメソッドのsynchronized
Classオブジェクトのロックを取得します。

class HogeClass {
  synchronized static public void hogeMethod() {
     // 処理
  }
}

上記は以下のsynchronizedブロックと同様になります。

static public void hogeMethod() {
  synchronized(Class.forName("HogeClass")) {
    // 処理
  }
}


以下のようなsynchronizedがついてるメソッドとついていないメソッドが混在するクラスの場合。

class HogeClass {
  synchronized static public void methodA() {
     // 処理
  }
  
  synchronized static public void methodB() {
     // 処理
  }
  
  static public void methodC() {
     // 処理
  }
}

methodA自身、methodB自身、methodAとmethodBは互いに排他的に実行されますが、
methodAとmethodC、methodBとmethodCは排他的に実行されません。
staticなのでJVM上で排他制御されます。



インスタンスメソッドのsynchronized
インスタンスオブジェクトのロックを取得します。

synchronized public void hogeMethod() {
     // 処理
}

上記は以下のsynchronizedブロックと同様になります。

public void hogeMethod() {
  synchronized(this) {
    // 処理
  }
}


以下のようなsynchronizedがついてるメソッドとついていないメソッドが
混在する場合はどうなるでしょう。

class HogeClass {
  synchronized public void methodA() {
     // 処理
  }
  
  synchronized public void methodB() {
     // 処理
  }
  
  public void methodC() {
     // 処理
  }
}

methodA自身、methodB自身、methodAとmethodBは同じインスタンス内で互いに排他的に実行されますが、
methodAとmethodC、methodBとmethodCは排他的に実行されません。
この排他関係はstaticの場合と同様ですが、インスタンスメソッドなので
いちインスタンスに対してで排他制御されますね。

また、synchronizedメソッド内からsynchronizedメソッドを呼び出すことは可能です。
オブジェクトのロックを取得しているので当然ですね。
(もちろんstaticの場合も同様)
class HogeClass {
  synchronized public void methodA() {
     methodB();
  }
  
  synchronized public void methodB() {
     // 処理
  }
  
}



あまりないとは思いますが、JVM上でスレッド間をまたいでインスタンスメソッドの
排他制御を行いたい場合は、以下のような方法があります。
class HogeClass {
  private static Object lock = new Object();
  
  public void methodA() {
     synchronized (lock) {
      // 処理
     } 
  }
  
  public void methodB() {
    synchronized (lock) {
      // 処理
     }
  }
  
}


排他制御は、相互作用を理解して誤動作やデッドロック等が起きないように
必要最低限に限定して使用するのがよいですね。