S2JDBC テーブルを利用した独自仕様のid採番メソッド

AS400DB2では、通常ではトランザクションが扱えないようです。ただし、ジャーナル処理を設定すれば扱えるようになるみたいです。*1

で、今回の案件

  • ジャーナルは作成しない
  • IDはテーブルを使って採番

という方針があり、それと関連してFOR UPDATEについてあれこれ調べたりしてました。

DB2で「SELECT ... FOR UPDATE」のロックを検証 - 130単位
S2JDBC DB2DialectでのforUpdate()を調べてみた - 130単位

さて、Javaには「synchronized」という修飾子があるそうです。これをメソッドの宣言に記述すれば、排他処理が行えるとのこと。

Java スレッド排他制御 synchronizedメソッド‐ニコニコ動画(ββ)
http://www.nicovideo.jp/watch/sm2346912

というわけで、S2JDBCのサービスにid採番用のメソッドを書いてみます。

  • 採番用テーブルのカラムはkeyとvalueのみ
  • エンティティを作成してSQL自動生成で記述
  • 各サービスから扱えるようにAbstractServiceに定義
  • 最初の採番時、対象キーのレコードが無くても動作可
  • valueカラムの現在値=次に採番される値

こんな感じの仕様です。

public abstract class AbstractService<ENTITY> extends S2AbstractService<ENTITY> {

    public synchronized int generateId(String key) {
        int id;

        IdGenerator idGen = jdbcManager
            .from(IdGenerator.class)
            .where("key = ?", key)
            .getSingleResult();

        if (idGen == null) {
            id = 1;

            idGen = new IdGenerator();
            idGen.key = key;
            idGen.value = 2;
            jdbcManager.insert(idGen).execute();
        }
        else {
            id = idGen.value;

            idGen.value = id + 1;
            jdbcManager.update(idGen).execute();
        }
        return id;
    }
}

で、synchronizedが実際に効くのかどうか試してみましたが、いまいちわかりませんでした。

  1. トランザクションは無しに設定
  2. メソッドの採番中にユーザーAのみ分岐されるThread#sleep()を仕込む
  3. ユーザーAにて採番実行
  4. ユーザーBにて採番実行

こんな手順でやってみたのですが、synchronizedがない状態でも3の時点で止まってくれました。おそらく検証方法がまずいのか、理解が足りないかのどちらかかと思われますが…。考えてもわからないので、ひとまず一区切りとしたいと思います。

原文地址:https://www.cnblogs.com/aggavara/p/2708720.html