如何基于当前日期生成唯一标识符

9
我将生成一个OrderId,它应该由yyMMddhhmmssMs组成,该OrderId代表订单表的主键字段。
我生成OrderId的方法如下:
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateTime {

    public static String getCurrentDateTimeMS() {
        Date dNow = new Date();
        SimpleDateFormat ft = new SimpleDateFormat("yyMMddhhmmssMs");
        String datetime = ft.format(dNow);
        return datetime;
    }

    public static void main(String args[]) throws InterruptedException {
        for (int i = 0; i < 50; i++) {
            String orderid = DateTime.getCurrentDateTimeMS();
            System.out.println(orderid);
        }
    }
}

但是当我使用JMeter测试我的应用程序时,使用100个用户并以2秒的速度逐步增加负载时,大多数用户出现了重复的情况,如下所示:

java.sql.BatchUpdateException: Duplicate entry '1410160239241024' for key 'PRIMARY'
        at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1269)
        at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:955)
        at com.services.OrdersInsertService.getData(OrdersInsertService.java:86)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:601)

如何基于当前时间生成唯一标识符,以便无论有多少并发用户都不会失败。


https://dev59.com/HWox5IYBdhLWcg3weUGe - Criban
10个回答

11
这是因为 for 循环的速度比你的时间更快 :). 当循环在少于毫秒的时间内迭代并生成值时,您只能在需要向数据库插入单个值且不迭代值时才能调用它。
除此之外,您可以使用UUID来实现此目的(对于字母数字值)。
for (int i = 0; i < 50; i++) {
        Date dNow = new Date();
        SimpleDateFormat ft = new SimpleDateFormat("yyMMddhhmmssMs");
        String datetime = ft.format(dNow);
        System.out.println(datetime);
}

输出

141016030003103
141016030003103
141016030003103
141016030003103
141016030003103
141016030003103
141016030003103
141016030003103
141016030003103
//.....and more

8

以下代码可以帮助您使用当前时间戳生成任意数量的唯一ID。生成的ID是长整型 - 64位。当在与上一个请求相同的毫秒内收到生成新唯一ID的请求时,最低有效的17位将被使用。在下面的代码中,它被标识为序列。这使得该代码每毫秒可以生成65536个唯一的ID。

/**
 * Unique id is composed of:
 * current time stamp - 47 bits (millisecond precision w/a custom epoch gives as 69 years)
 * sequence number - 17 bits - rolls over every 65536 with protection to avoid rollover in the same ms
 **/

public class UniqueIdGenerator {
    private static final long twepoch = 1288834974657L;
    private static final long sequenceBits = 17;
    private static final long sequenceMax = 65536;
    private static volatile long lastTimestamp = -1L;
    private static volatile long sequence = 0L;

    public static void main(String[] args) {
        Set<Long> uniqueIds = new HashSet<Long>();
        long now = System.currentTimeMillis();
        for(int i=0; i < 100000; i++)
        {
            uniqueIds.add(generateLongId());
        }
        System.out.println("Number of Unique IDs generated: " + uniqueIds.size() + " in " + (System.currentTimeMillis() - now) + " milliseconds");
    }

    private static synchronized Long generateLongId() {
        long timestamp = System.currentTimeMillis();
        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) % sequenceMax;
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0;
        }
        lastTimestamp = timestamp;
        Long id = ((timestamp - twepoch) << sequenceBits) | sequence;
        return id;
    }

    private static long tilNextMillis(long lastTimestamp) {
        long timestamp = System.currentTimeMillis();
        while (timestamp <= lastTimestamp) {
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }
}

2
使用这个:
int unique_id= (int) ((new Date().getTime() / 1000L) % Integer.MAX_VALUE); 

0
I used a simple logical approach which combines current date and time.  That way it is absolutely unique in any given time.

public String  setUniqueID(){
    DateFormat dateFormat = new SimpleDateFormat("yyddmm");
    Date date = new Date();
    String dt=String.valueOf(dateFormat.format(date));
    Calendar cal = Calendar.getInstance();
    SimpleDateFormat time = new SimpleDateFormat("HHmm");
    String tm= String.valueOf(time.format(new Date()));//time in 24 hour format
    String id= dt+tm;
    System.out.println(id);
    return id;   
}

This returns a unique id.

当有两个并发线程运行此函数时,这可能会失败。 - Francis Zabala

0

您可以使用new Date().getTime().toString(36);,它会返回一个类似于'u2mcggc1'的字符串。


0

为每个订单ID添加一个唯一的字符串,比如用户的电子邮件(如果在您的数据库中是唯一的)或用户在您的数据库中的ID。这样可以让订单ID变得真正唯一。

唯一字符串 = 时间戳 + 唯一用户字段


0
public class Test {

    public static void main(String[] args) {
        Date d = new Date();
        // it will return a unique value based on time
        System.out.println(d.getTime());
    }

}

你可以使用日期类的 getTime 方法。它返回自1970年1月1日00:00:00 GMT以来以毫秒为单位表示的时间戳。

0
在你的格式化器中,你正在使用Ms,它不会添加毫秒。相反,你可能想要使用SSS

0

我认为这将有助于生成一个具有20个字符的唯一时间戳。

public class DateTimeService {

    @Autowired
    private Clock clock;
    private LocalDateTime current;

    @PostConstruct
    public void init() {
        current = LocalDateTime.now(clock);
    }

    public synchronized LocalDateTime getUniqueTimestamp() {
        LocalDateTime now = LocalDateTime.now(clock);
        if (current.isEqual(now) || current.isAfter(now)) {
            current = current.plus(1, ChronoUnit.MICROS);
        } else {
            current = now;
        }
        return current;
    }
}

0

根据我的经验,基于日期和时间获取唯一字符串非常困难, 由于循环速度非常快,很有可能会得到重复的字符串。

但是这里我有一个小代码,有一个巧妙的方法每次都能在循环中产生一个唯一的字符串。

public static synchronized String getUniqueStringEveryTime()
{
    
        Date dNow = new Date();
        SimpleDateFormat ft = new SimpleDateFormat("yyyyMMddHHmmssSS");
        String datetime = ft.format(dNow);
        try
        {
            Thread.sleep(1);
        }catch(Exception e)
        {
            
        }
        return datetime;

}

以上简单的方法每次都能百分之百地正确运行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接