0

I need to implement a counter by prefix and get the current value. Therefore I created a table UPLOAD_ID:

 CREATE TABLE UPLOAD_ID
(
    COUNTER INT NOT NULL,
    UPLOAD_PREFIX VARCHAR(60) PRIMARY KEY
);

Using H2 and a Spring nativeQuery:

    @Query(nativeQuery = true, value = MYQUERY)
  override fun nextId(@Param("prefix") prefix: String): Long

with MYQUERY being

SELECT COUNTER FROM FINAL TABLE ( 
              USING (SELECT CAST(:prefix AS VARCHAR) AS UPLOAD_PREFIX FOR UPDATE) S FOR UPDATE
              ON T.UPLOAD_PREFIX = S.UPLOAD_PREFIX
              WHEN MATCHED
                THEN UPDATE
                    SET COUNTER = COUNTER + 1
              WHEN NOT MATCHED
                THEN INSERT (UPLOAD_PREFIX, COUNTER)
                    VALUES (S.UPLOAD_PREFIX, 1) );

I'm unable to lock the table to avoid "Unique index or primary key violation" in my test. In MSSQL I can add WITH (HOLDLOCK) T in MERGE INTO UPLOAD_ID WITH (HOLDLOCK) T to solve this issue.

The gist of my test looks like

     try { uploadIdRepo.deleteById(prefix) } catch (e: EmptyResultDataAccessException) { }

      val startCount = uploadIdRepo.findById(prefix).map { it.counter }.orElseGet { 0L }
      val workerPool = Executors.newFixedThreadPool(35)
      val nextValuesRequested = 100

      val res = (1..nextValuesRequested).toList().parallelStream().map { i ->
        workerPool.run {
          uploadIdRepo.nextId(prefix)
        }
      }.toList()

      res shouldHaveSize nextValuesRequested // result count
      res.toSet() shouldHaveSize nextValuesRequested // result spread
      res.max() shouldBeEqualComparingTo startCount + nextValuesRequested

Can I solve this with H2?

Stefan K.
  • 7,701
  • 6
  • 52
  • 64

0 Answers0