同時実行・排他制御
排他制御の種類
データベース操作 データベースへの更新時に
ファイル操作 同一ファイルへの同時書き込み・読み書き時に
ブラウザからのリクエスト送信 送信ボタンの二度押しによる同一リクエストの二重送信時に
●楽観的ロックの処理方式
他のトランザクションが同時に同じデータを更新する可能性が少ない場合に採用
★サンプル(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);
}
}
●悲観的ロックの処理方式
他のトランザクションが同時に同じデータを更新する可能性が高い場合に採用
●デッドロックの回避