9

I am generating a OrderId which should consist of yyMMddhhmmssMs and this orderId represents primarykey field for the Orders table .

The way i was generating Order Id is below :

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);
        }
    }
}

But when i load tested my Application using JMeter with 100 users with a ramp up of 2 seconds most of them were throwing Duplicate as shown below

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)

How is it possible to generating UniqueId based on current time so that it never fails no matter how many concurrent users are present .

10 Answers10

11

This is happening because of speed of for loop which is faster than your time :).As loop iterates in time of less than miliseconds and generates values.You can only call it when you want to insert single value to database and don't iterate for values.

Other than that you can use UUID for this purpose (for alphanumeric value).

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);
}

OUTPUT

141016030003103
141016030003103
141016030003103
141016030003103
141016030003103
141016030003103
141016030003103
141016030003103
141016030003103
//.....and more
akash
  • 22,664
  • 11
  • 59
  • 87
7

This code will help you generate any number of unique IDs using current time stamp. Generated ID is of type long - 64 bits. Least Significant 17 bits are used when request to generate a new unique ID is received in the same millisecond of time as the previous request. Its identified as Sequence in the code below. That allows the code to generate 65536 unique IDs per millisecond.

/**
 * 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;
    }
}
HIREN011
  • 549
  • 1
  • 7
  • 7
2

Use this:

int unique_id= (int) ((new Date().getTime() / 1000L) % Integer.MAX_VALUE); 
Prashanth
  • 993
  • 8
  • 18
0

Add a unique string to each order ID, like the user's email (if it's unique in your database) or the user's id from your database. This makes the order ID truly unique

String unique = timestamp + unique_user_field

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());
    }

}

You can use getTime method of date class. It returns the number of milliseconds since January 1, 1970, 00:00:00 GMT represented by this date.

kohane15
  • 809
  • 12
  • 16
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.
Neyomal
  • 1,589
  • 1
  • 12
  • 14
0

You can use new Date().getTime().toString(36); which gives a string something like 'u2mcggc1'

Anees Hameed
  • 5,916
  • 1
  • 39
  • 43
0

I think this will help to generate a unique timestamp with 20 characters.

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;
    }
}
nmkyuppie
  • 1,456
  • 1
  • 14
  • 30
0

As per me it is very difficult to get unique String based on date and time, Since loop speed is very fast, high chances are you get duplicate strings.

But here I have a small code with a twist to give a unique String every time even in loop.

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;

}

The above simple method works 100% correct any number of times.

Attaullah
  • 3,856
  • 3
  • 48
  • 63
0

In your formatter you are using Ms which doesn't add the milliseconds. Instead, you may want to use SSS.

hfazai
  • 1
  • 1