2017-08-08 16 views
1

テーブル内の行を更新するための複数のスレッドを持つスケジューラがあります。私は "for update skip locked"を使用しようとしていますが、何らかの理由で、次のunclaimed行を見つけるのではなく、すべてのスレッドが同じものを選択して更新します。 私は、 "id"と "counter"カラムを持つテーブル "counter"を持っています。Spring JDBCを使用したPostgres "SKIP LOCKED"

CounterRepository.javaが

@Repository 
public class CounterRepository { 
    private final JdbcTemplate jdbc; 

    public CounterRepository(JdbcTemplate jdbc) {this.jdbc = jdbc;} 

    @Transactional 
    void update() { 
     Integer id = jdbc.queryForObject("SELECT id FROM counter ORDER BY counter LIMIT 1 FOR UPDATE SKIP LOCKED;", Integer.class); 
     Integer counter = jdbc.queryForObject("SELECT counter FROM counter WHERE id = ?", Integer.class, id); 
     jdbc.update("UPDATE counter set counter = ? WHERE id = ?", 5 - counter, id); 
    } 
} 

DbAsyncUpdateApplication.java

@EnableAsync 
@EnableScheduling 
@SpringBootApplication 
public class DbAsyncUpdateApplication { 

    @Bean(name = "threadPoolTaskExecutor") 
    public ScheduledExecutorService taskScheduler() throws InterruptedException { 
     return Executors.newScheduledThreadPool(5); 
    } 

    public static void main(String[] args) { 
     SpringApplication.run(DbAsyncUpdateApplication.class, args); 
    } 
} 

Scheduler.java

@Service 
public class Scheduler { 
    private final CounterRepository repository; 

    public Scheduler(CounterRepository repository) {this.repository = repository;} 

    @Scheduled(fixedRate = 1000) 
    public void start() { 
     repository.update(); 
    } 
} 
+0

どのトランザクションレベルを使用していますか?ロジックが動作するためには、行の読み込みロックが必要です。 – Voo

+0

@Vooデフォルトの読み込み済み –

+0

これはなぜうまくいかないのか分かります。 – Voo

答えて

0

デフォルトの分離レベルで正常に動作する必要がありますあなたが書いたSQL。 問題は、初期データまたは「カウンタ」を更新するために使用されたロジックを使用している可能性があります。

「カウンタ」の更新に関するロジックを確認するたびに、counter5 - counterに設定します。これは、値が固定値の2つの値の間でトグルし続けることを意味します。例えば。指定されたidの最初のcounterが0だった場合、プログラムは5と0の間の値をトグルし続けます。これは意図した通りです。その場合、1つの可能性(この例ではデータ)は、他のすべての行がcounter値> 5 およびであるということです.JVMは一度に1つのスレッドしか実行しません。この方法では、更新される行は常に最小のカウンタを持ち、他のスレッドはこの行がロックされている間に別の行を選択しようとしませんでした。これはまれですが、理論的には可能です。メッセージにスレッドが入るたびにログ

  1. をし、複数のスレッドが実際にある最初のデータを確認すると同時に
  2. でメソッドを入力しているかどうかを確認するupdate()方法を残して -

    私がお勧めしたいですこのデータをもとにカウンタの更新ロジックが正常に機能することを確認してください(データもここに投稿してください)

関連する問題