1

I am inserting into database with batchupdate. I need to generate actual 10 digits of id out of which first six digits will remain same i.e. a yyMMdd I am trying to append four unique digits to this block of yyMMdd pattern as per local date. the problem is, it generates lots of duplicate as the FOR loop is running ahead of time in ms.

Expected Pattern : 210609xxxx where 210609 is taken from yyMMdd pattern of LocalDate in java and xxxx needs to be unique for even if FOR loop calls this method multiple times per millisecond.

public Long getUniquedeltaId() {    
final Long LIMIT = 10000L;
    final Long deltaId = Long.parseLong(Long.toString(Long.parseLong((java.time.LocalDate.now()
    .format(DateTimeFormatter
    .ofPattern("yyMMdd")))))
    .concat(Long.toString(System.currentTimeMillis() % LIMIT)));
    System.out.println("deltaId"+deltaId);
return deltaId;

I tried using System.nanoTime() but its returning only one uniqueId.

Prasad_Joshi
  • 642
  • 3
  • 13
  • 34
  • This may help: https://stackoverflow.com/a/31656679/11455105 – Amal K Jun 09 '21 at 11:35
  • 2
    With only 4 digits freely assignable per day, you almost certainly won't be able to give away random IDs and avoid collisions, that's simply much to little. You need to actually use incremental IDs (or some other form of centrally managed ID provision) to get unique IDs this way. – Joachim Sauer Jun 09 '21 at 11:37
  • I suppose the lower case `m` in `yyMmdd` is a typo. – Ole V.V. Jun 09 '21 at 14:25

1 Answers1

2

If you need a plainly simple list of unique IDs at one point in time, you can use the following method:

package example;

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

public class Main {

    public static void main(String[] args) {
        final String prefix = "20210609";// hardcoded prefix for the example

        final List<String> uniqueIds = ThreadLocalRandom.current().ints(0, 10_000)// ints from 0 to 10000 (exclusive) -> every possible 4 digit number
                .distinct()// only distinct numbers
                .limit(1000L)// exactly 1000 (up to 10000 possible)
                .mapToObj(v -> String.format("%04d", v))// always 4 digits (format as string, lpad with 0s
                .map(v -> prefix + v)// add our prefix
                .collect(Collectors.toList());

        System.out.println(uniqueIds);
    }
}

If you need a component that provides you with one unique ID at a time, you can use this class:

package example;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

public class IdGenerator {

    private static final int LENGTH = 10_000;
    private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern("yyMMdd");// unlike SimpleDateFormat, this is thread-safe

    private final Object monitor;
    private final AtomicInteger offset;
    private final AtomicBoolean generationInProgress;
    private volatile int[] ids;
    private volatile LocalDate lastGeneratedDate;

    public IdGenerator() {
        this.monitor = new Object();
        this.offset = new AtomicInteger(0);
        this.generationInProgress = new AtomicBoolean(false);
        this.ids = new int[LENGTH];
        this.lastGeneratedDate = LocalDate.MIN;
    }

    public String nextId() throws InterruptedException {
        final LocalDate currentDate = LocalDate.now();

        while (this.lastGeneratedDate.isBefore(currentDate)) {
            if (this.generationInProgress.compareAndSet(false, true)) {
                this.ids = ThreadLocalRandom.current().ints(0, LENGTH)
                        .distinct()
                        .limit(LENGTH)
                        .toArray();

                this.offset.set(0);
                this.lastGeneratedDate = currentDate;

                this.generationInProgress.set(false);

                synchronized (this.monitor) {
                    this.monitor.notifyAll();
                }
            }

            while (this.generationInProgress.get()) {
                synchronized (this.monitor) {
                    this.monitor.wait();
                }
            }
        }

        final int myIndex = this.offset.getAndIncrement();
        if (myIndex >= this.ids.length) {
            throw new IllegalStateException("no more ids today");
        }

        return currentDate.format(DTF) + String.format("%04d", this.ids[myIndex]);
    }
}

Note that your pattern allows only 10000 unique IDs per day. You limit yourself to 4 digits per day (10^4 = 10000).

Felix
  • 2,256
  • 2
  • 15
  • 35