How to ensure that the obtained id is unique in the case of concurrency?

problem description

when recording audit logs, you need to generate a primary key by querying the largest primary key through sql and then + 1 as the primary key, but there is a primary key conflict problem. Now try to generate the log primary key id before inserting it as follows:

related codes

// service
@Service
public class AuditLogServiceImlp implements IAuditLogService{
    public long nextId(String sysId){
        return AuditLogIdIncrease.getInstance().nextId(sysId);
    }
}

// id
public class AuditLogIdIncrease {

    private static AuditLogIdIncrease instance;

    private final int threadIdBits = 4;// 
    private final int maxRandomId = 9;// 

    private AuditLogIdIncrease() {
    }

    public static AuditLogIdIncrease getInstance() {
        if (instance == null) {
            instance = new AuditLogIdIncrease();
        }
        return instance;
    }

    /**
     * ID 
     * @param sysId
     * @return
     */
    public synchronized long nextId(int sysId) {
        return splice(sysId);
    }

    /**
     * id:+++
     * @param sysId
     * @return
     */
    private long splice(int sysId) {
        String strLong = getCurrentTime() + getCurrentThreadId() + getRandomNum() + sysId;
        return Long.parseLong(strLong);
    }

    /**
     * 
     * @return
     */
    private long getCurrentTime() {
        return System.currentTimeMillis();
    }

    /**
     * 
     * @return
     */
    private String getCurrentThreadId() {
        String strCurrentThreadId = String.format("%0" + threadIdBits + "d", Thread.currentThread().getId());
        if (strCurrentThreadId.length() > threadIdBits) {
            strCurrentThreadId = strCurrentThreadId.substring(0, threadIdBits);
        }
        return strCurrentThreadId;
    }

    /**
     * 
     * @return
     */
    private int getRandomNum() {
        return new Random().nextInt(maxRandomId);
    }

    public static void main(String[] args) {

    }
}

sources of topics and their own ideas

  1. make sure that AuditLogIdIncrease is a singleton
  2. AuditLogIdIncrease.nextId () is thread-safe

what result do you expect?

does this approach satisfy the unique (mainly singleton and thread-safe) design of getting id in concurrent situations? I wonder if it can be achieved through the Atomic class?

Dec.22,2021

your singleton pattern implementation is lazy mode. It is not completely thread safe. If multiple threads can enter if (instance = = null) and instance is null, then multiple threads will execute instance = new AuditLogIdIncrease ()
if there is no limit on the length and type of primary key field, you can consider using uuid as the primary key. Whether you use the uuid generation method UUID.randomUUID (). ToString () provided by java.util.UUID or the selectkey of mybatis to query uuid from the database first, it is very convenient to use it as the primary key

MySQL Query : SELECT * FROM `codeshelper`.`v9_news` WHERE status=99 AND catid='6' ORDER BY rand() LIMIT 5
MySQL Error : Disk full (/tmp/#sql-temptable-64f5-1b39c64-2ba12.MAI); waiting for someone to free some space... (errno: 28 "No space left on device")
MySQL Errno : 1021
Message : Disk full (/tmp/#sql-temptable-64f5-1b39c64-2ba12.MAI); waiting for someone to free some space... (errno: 28 "No space left on device")
Need Help?