How many files(0-15)

競馬の予想システムで一儲を企むおっさんのヨコシマな横顔

jbpm備忘録6 プロセスロック

Processインスタンスのロックについて調べた。

結論から言うと、org.jbpm.db.GraphSession.lockProcessInstaceは、JBPMのデータJBPM_PROCESSINSTANCEテーブルをselect for updateする実装だ。

lockProcessInstanceの実装は以下のようになっており、肝はsession.loadの部分のLockMode.UPGRADEだ。

    public void lockProcessInstance(long processInstanceId) {
        try {
            session.load(ProcessInstance.class, new Long(processInstanceId), LockMode.UPGRADE);
        }
        catch (HibernateException e) {
            handle(e);
            throw new JbpmPersistenceException("could not lock process instance "
            + processInstanceId, e);
        }
    }

LockModeの内容を見てみると以下のようになっている。 注目すべきは、UPGRADEの注釈に、using select ... for updateとあることだ。 for updateをサポートしていないDBだって同然あるので、実際にJBPM_PROCESS_INSTANCEをロックする際に使用されるSQLはDBによって違いが出てくるはずだ。

Instances represent a lock mode for a row of a relational database table. 
It is not intended that users spend much time worrying about locking 
since Hibernate usually obtains exactly the right lock level automatically. 
Some "advanced" users may wish to explicitly specify lock levels.

    public final class LockMode implements Serializable {
        private final int level;
        private final String name;
        private static final Map INSTANCES = new HashMap();

        private LockMode(int level, String name) {
            this.level=level;
            this.name=name;
        }

An upgrade lock. Objects loaded in this lock mode are materialized 
using an SQL select ... for update.
 
        public static final LockMode UPGRADE = new LockMode(10, "UPGRADE");

        中略...

        static {
            INSTANCES.put( NONE.name, NONE );
            INSTANCES.put( READ.name, READ );
            INSTANCES.put( UPGRADE.name, UPGRADE );
            INSTANCES.put( UPGRADE_NOWAIT.name, UPGRADE_NOWAIT );
            INSTANCES.put( WRITE.name, WRITE );
            INSTANCES.put( FORCE.name, FORCE );
        }

実際にどのようなSQLを発行しているかは、jboss-log4j.xmlのcategroy org.hibernateをDEBUGレベルにしてみればわかる。 ちなみにoracleの場合は、for updateによるロックを行っていた。

lockProcessInstanceがこのような実装なので、Thread間で同一のProcessInstanceの内容を参照、更新する場合においては、lockProcessInstanceをid指定で行った後に、ProcessInstanceの実体を取得することが望ましい。

何故なら、ProcessInstanceをロックのパラメータに指定する方のlockProcessInstanceを使っていたため、稀にlockProcessInstanceを行う前に取得したProcessInstanceが別のThreadに書き換えられlock時StaleObjectStateExceptionが発生するという現象に私はどっぷりと嵌り、随分と悩まされたからだ。

ProcessInstanceの取得と同時に、ロックできないのって厳しいなぁ、、