同時実行・排他制御

排他制御の種類

データベース操作 データベースへの更新時に

ファイル操作 同一ファイルへの同時書き込み・読み書き時に

ブラウザからのリクエスト送信 送信ボタンの二度押しによる同一リクエストの二重送信時に

●楽観的ロックの処理方式

他のトランザクションが同時に同じデータを更新する可能性が少ない場合に採用

★サンプル(Spring + iBATIS)

楽観ロック

public class SequenceDao extends SqlMapClientDaoSupport {

public int getValue(String name) {

// SELECT value FROM t_sequence WHERE name = #name#

return (Integer) getSqlMapClientTemplate()

.queryForObject("Sequence.getValue", name);

}

public boolean compareAndSet(String name, int value, int expect) {

Map<String, Object> parameters = new HashMap<String, Object>();

parameters.put("name", name);

parameters.put("value", value);

parameters.put("expect", expect);

// UPDATE t_sequence SET value = #value#

// WHERE name = #name# AND value = #expect#

int updateCount =

getSqlMapClientTemplate()

.update("Sequence.compareAndSet", parameters);

return updateCount == 1;

}

}

public class SequenceService {

@Transactional(propagation = Propagation.NOT_SUPPORTED)

public synchronized void increment(String sequenceName) {

for (;;) {

int value = dao.getValue(sequenceName);

if (dao.compareAndSet(sequenceName, value + 1, value)) {

break;

}

}

}

}

悲観ロック

public class SequenceDao extends SqlMapClientDaoSupport {

public int getValueForUpdate(String name) {

// SELECT value FROM t_sequence WHERE name = #name# FOR UPDATE

return (Integer) getSqlMapClientTemplate()

.queryForObject("Sequence.getValueForUpdate", name);

}

public void set(String name, int value) {

Map<String, Object> parameters = new HashMap<String, Object>();

parameters.put("name", name);

parameters.put("value", value);

// UPDATE t_sequence SET value = #value# WHERE name = #name#

getSqlMapClientTemplate().update("Sequence.set", parameters);

}

}

public class SequenceService {

@Transactional(propagation = Propagation.REQUIRED)

public synchronized void increment(String sequenceName) {

int value = dao.getValueForUpdate(sequenceName);

dao.set(sequenceName, value + 1);

}

}

●悲観的ロックの処理方式

他のトランザクションが同時に同じデータを更新する可能性が高い場合に採用

●デッドロックの回避