前提
cronで定期的に実行するバッチプログラムを作成しています。
Hogeテーブルに処理のキューを登録しておき、
バッチが起動するとHogeテーブルからステータス”待ち状態”のレコードを1件取得して特定の処理を実行します。
その処理の完了後、Hogeテーブルのステータスを”実行中”に更新します。
このバッチは多重起動されるものなので、ステータスを”待ち状態”から”実行中”に更新する間、
対象のレコードを他のプロセスから参照(select)させたくありません。
そのため、select ~ for updateを利用してロックをかけようと考え下記の実装で動作を試してみました。
問題
Eclipseのデバッグモードで起動し、ブレークポイント(下記参照)で止めた状態で
別途SQLクライアントを立ち上げそちらで"select * from hoge_queue;"を実行してみました。
予想ではロックされているため、selectが待ち状態になるはずでしたが、
実際はupdate文が実行される前のレコードが取得できてしまいました。
(プログラムをステップ実行し、commit後に再度selectすると、update後のレコードが正しく取得できました)
下記の実装はどこが間違っているのでしょうか?
解決方法をご存知の方がいらっしゃいましたら、ご指摘、アドバイスを頂きたいです。
どうぞよろしくお願い致します。
開発環境
Java 1.8.0_172
MyBatis 3.4.6
MariaDB 10.2.14(トランザクション分離レベルはデフォルトの"REPEATABLE-READ")
実装
ロジック
Java
1 2private static final String WAITING = "1"; 3private static final String PROCESSING = "2"; 4 5// ~~省略~~ 6 7try (SqlSession session = sessionFactory.openSession()) { 8 HogeMapper hogeMapper = session.getMapper(HogeMapper.class); 9 // 処理するレコードを取得 10 HogeQueue record = hogeMapper.findByStatusForUpdate(WAITING); 11 12 // (特定の処理) 13 14 // ステータスの更新 15 rec.setStatus(PROCESSING);//←★ここにブレークポイントを置いて確認★ 16 int updateCount = hogeMapper.updateStatus(record); 17 session.commit(); 18}
HogeMapper.java
Java
1@Mapper 2public interface HogeMapper{ 3 4 HogeQueue findByStatusForUpdate(char status); 5 6 int updateStatus(HogeQueue queue); 7} 8
HogeMapper.xml
xml
1<select id="findByStatusForUpdate" resultType="HogeQueue"> 2 select 3 id 4 ,input_file_name 5 ,status 6 ,create_user_id 7 ,create_date 8 ,update_user_id 9 ,update_date 10 from hoge_queue 11 where status = #{status} 12 order by id 13 limit 0, 1 14 for update 15</select> 16<update id="updateStatus"> 17 update hoge_queue 18 set status = #{status} 19 ,update_user_id = 'batch' 20 ,update_date = now() 21 where id = #{id} 22</update>

回答3件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/05/16 03:31