Các thư viện UUID tạo ra các UUID 32 ký tự.
Tôi muốn tạo UUID chỉ 8 ký tự, có được không?
Các thư viện UUID tạo ra các UUID 32 ký tự.
Tôi muốn tạo UUID chỉ 8 ký tự, có được không?
Câu trả lời:
Không thể thực hiện được vì UUID là một số 16 byte cho mỗi định nghĩa. Nhưng tất nhiên, bạn có thể tạo chuỗi duy nhất dài 8 ký tự (xem các câu trả lời khác).
Ngoài ra, hãy cẩn thận với việc tạo các UUID dài hơn và nhập chuỗi con của chúng, vì một số phần của ID có thể chứa các byte cố định (ví dụ: đây là trường hợp với các UUID MAC, DCE và MD5).
Bạn có thể thử RandomStringUtils
lớp từ apache.commons :
import org.apache.commons.lang3.RandomStringUtils;
final int SHORT_ID_LENGTH = 8;
// all possible unicode characters
String shortId = RandomStringUtils.random(SHORT_ID_LENGTH);
Xin lưu ý rằng nó sẽ chứa tất cả các ký tự có thể có, không phải là URL hoặc không thân thiện với con người.
Vì vậy, hãy kiểm tra các phương pháp khác:
// HEX: 0-9, a-f. For example: 6587fddb, c0f182c1
shortId = RandomStringUtils.random(8, "0123456789abcdef");
// a-z, A-Z. For example: eRkgbzeF, MFcWSksx
shortId = RandomStringUtils.randomAlphabetic(8);
// 0-9. For example: 76091014, 03771122
shortId = RandomStringUtils.randomNumeric(8);
// a-z, A-Z, 0-9. For example: WRMcpIk7, s57JwCVA
shortId = RandomStringUtils.randomAlphanumeric(8);
Như những người khác đã nói xác suất xung đột id với id nhỏ hơn có thể đáng kể. Kiểm tra cách vấn đề sinh nhật áp dụng cho trường hợp của bạn. Bạn có thể tìm thấy lời giải thích hay về cách tính xấp xỉ trong câu trả lời này .
org.apache.commons.lang3.RandomStringUtils
không được dùng nữa nên tốt hơn bạn nên sử dụng org.apache.commons.text.RandomStringGenerator
trong commons.apache.org/proper/commons-text
RandomStringGenerator
, vì nó là mã hoàn toàn khác.
RandomStringUtils
KHÔNG bị phản đối. Nó được thiết kế để sử dụng đơn giản. Bạn có thể cung cấp nguồn thông tin không RandomStringUtils
được dùng nữa không? Tôi có thể cung cấp tài liệu về phiên bản mới nhất của nó RandomStringUtils
để làm bằng chứng rằng nó không còn được dùng nữa: commons.apache.org/proper/commons-lang/javadocs/api-3.9/org/…
Thứ nhất: Ngay cả các ID duy nhất được tạo bởi java UUID.randomUUID hoặc .net GUID cũng không phải là duy nhất 100%. Đặc biệt UUID.randomUUID là "chỉ" một giá trị ngẫu nhiên 128 bit (an toàn). Vì vậy, nếu bạn giảm nó xuống 64 bit, 32 bit, 16 bit (hoặc thậm chí 1 bit) thì nó sẽ trở nên ít độc đáo hơn.
Vì vậy, nó ít nhất là một quyết định dựa trên rủi ro, uuid của bạn phải là bao lâu.
Thứ hai: Tôi giả sử rằng khi bạn nói về "chỉ 8 ký tự", bạn có nghĩa là một Chuỗi 8 ký tự có thể in bình thường.
Nếu bạn muốn một chuỗi duy nhất có độ dài 8 ký tự có thể in được, bạn có thể sử dụng mã hóa base64. Điều này có nghĩa là 6 bit cho mỗi ký tự, vì vậy bạn nhận được tổng cộng 48 bit (có thể không phải là duy nhất - nhưng có thể nó là ok cho ứng dụng của bạn)
Vì vậy, cách rất đơn giản: tạo một mảng ngẫu nhiên 6 byte
SecureRandom rand;
// ...
byte[] randomBytes = new byte[16];
rand.nextBytes(randomBytes);
Và sau đó chuyển đổi nó thành Chuỗi Base64, ví dụ bằng cách org.apache.commons.codec.binary.Base64
BTW: nó phụ thuộc vào ứng dụng của bạn nếu có cách tốt hơn để tạo "uuid" sau đó ngẫu nhiên. (Nếu bạn chỉ tạo UUID một lần mỗi giây, thì bạn nên thêm dấu thời gian) (Nhân tiện: nếu bạn kết hợp (xor) hai giá trị ngẫu nhiên, kết quả luôn ít nhất là ngẫu nhiên nhất ngẫu nhiên của cả hai).
Như @Cephalopod đã nêu là không thể nhưng bạn có thể rút ngắn UUID còn 22 ký tự
public static String encodeUUIDBase64(UUID uuid) {
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
return StringUtils.trimTrailingCharacter(BaseEncoding.base64Url().encode(bb.array()), '=');
}
Đây là một cách tương tự mà tôi đang sử dụng ở đây để tạo mã lỗi duy nhất, dựa trên câu trả lời Anton Purin, nhưng dựa trên câu trả lời thích hợp hơn org.apache.commons.text.RandomStringGenerator
thay vì (một lần, không nữa) không được chấp nhận org.apache.commons.lang3.RandomStringUtils
:
@Singleton
@Component
public class ErrorCodeGenerator implements Supplier<String> {
private RandomStringGenerator errorCodeGenerator;
public ErrorCodeGenerator() {
errorCodeGenerator = new RandomStringGenerator.Builder()
.withinRange('0', 'z')
.filteredBy(t -> t >= '0' && t <= '9', t -> t >= 'A' && t <= 'Z', t -> t >= 'a' && t <= 'z')
.build();
}
@Override
public String get() {
return errorCodeGenerator.generate(8);
}
}
Tất cả các lời khuyên về va chạm vẫn được áp dụng, vui lòng lưu ý chúng.
RandomStringUtils
KHÔNG bị phản đối. Nó được thiết kế để sử dụng đơn giản. Bạn có thể cung cấp nguồn thông tin không RandomStringUtils
được dùng nữa không? Tôi có thể cung cấp tài liệu về phiên bản mới nhất của nó RandomStringUtils
để làm bằng chứng rằng nó không còn được dùng nữa: commons.apache.org/proper/commons-lang/javadocs/api-3.9/org/…
commons.lang
không liên quan chặt chẽ đến ngôn ngữ, commons.text
được tạo ra với một mục đích.
RandomStringUtils
nó không bị phản đối và theo các tài liệu tham khảo do bạn cung cấp, có lý do chính đáng để giữ nó không bị phản đối, vì nó dễ sử dụng hơn nhiều so RandomStringGenerator
với các trường hợp sử dụng đơn giản. Có lẽ bạn có thể cập nhật câu trả lời của bạn? Nếu / khi nào RandomStringUtils
hoặc chức năng của nó cho các trường hợp sử dụng đơn giản sẽ được chuyển đến commons.text
, thì bạn có thể cập nhật lại câu trả lời của mình, nhưng hiện tại câu trả lời đang gây hiểu lầm.
commons.lang
sang commons.text
, không có lý do gì để bất kỳ ai sử dụng cái trước chứ không phải cái sau ngoài việc sử dụng nó ở một nơi khác. Đơn giản ở đây là khá chủ quan, tôi thấy câu trả lời của tôi vẫn còn rất đơn giản và tôi sẽ không bao giờ thay đổi nó cho một cái gì đó yêu cầu phải nhập Commons Lang.
Còn cái này thì sao? Trên thực tế, mã này trả về tối đa 13 ký tự, nhưng nó ngắn hơn UUID.
import java.nio.ByteBuffer;
import java.util.UUID;
/**
* Generate short UUID (13 characters)
*
* @return short UUID
*/
public static String shortUUID() {
UUID uuid = UUID.randomUUID();
long l = ByteBuffer.wrap(uuid.toString().getBytes()).getLong();
return Long.toString(l, Character.MAX_RADIX);
}
getLong()
chỉ đọc 8 byte đầu tiên của bộ đệm. UUID sẽ có ít nhất 36 byte. Tôi có thiếu một cái gì đó không vì với tôi điều này sẽ không bao giờ hiệu quả.
Long.toString(uuid.getLessSignificantBits(), Character.MAX_RADIX)
là tốt hơn.
Trên thực tế, tôi muốn mã nhận dạng duy nhất ngắn hơn dựa trên dấu thời gian, do đó đã thử chương trình bên dưới.
Nó có thể đoán được với các nanosecond + ( endians.length * endians.length )
kết hợp.
public class TimStampShorterUUID {
private static final Character [] endians =
{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
};
private static ThreadLocal<Character> threadLocal = new ThreadLocal<Character>();
private static AtomicLong iterator = new AtomicLong(-1);
public static String generateShorterTxnId() {
// Keep this as secure random when we want more secure, in distributed systems
int firstLetter = ThreadLocalRandom.current().nextInt(0, (endians.length));
//Sometimes your randomness and timestamp will be same value,
//when multiple threads are trying at the same nano second
//time hence to differentiate it, utilize the threads requesting
//for this value, the possible unique thread numbers == endians.length
Character secondLetter = threadLocal.get();
if (secondLetter == null) {
synchronized (threadLocal) {
if (secondLetter == null) {
threadLocal.set(endians[(int) (iterator.incrementAndGet() % endians.length)]);
}
}
secondLetter = threadLocal.get();
}
return "" + endians[firstLetter] + secondLetter + System.nanoTime();
}
public static void main(String[] args) {
Map<String, String> uniqueKeysTestMap = new ConcurrentHashMap<>();
Thread t1 = new Thread() {
@Override
public void run() {
while(true) {
String time = generateShorterTxnId();
String result = uniqueKeysTestMap.put(time, "");
if(result != null) {
System.out.println("failed! - " + time);
}
}
}
};
Thread t2 = new Thread() {
@Override
public void run() {
while(true) {
String time = generateShorterTxnId();
String result = uniqueKeysTestMap.put(time, "");
if(result != null) {
System.out.println("failed! - " + time);
}
}
}
};
Thread t3 = new Thread() {
@Override
public void run() {
while(true) {
String time = generateShorterTxnId();
String result = uniqueKeysTestMap.put(time, "");
if(result != null) {
System.out.println("failed! - " + time);
}
}
}
};
Thread t4 = new Thread() {
@Override
public void run() {
while(true) {
String time = generateShorterTxnId();
String result = uniqueKeysTestMap.put(time, "");
if(result != null) {
System.out.println("failed! - " + time);
}
}
}
};
Thread t5 = new Thread() {
@Override
public void run() {
while(true) {
String time = generateShorterTxnId();
String result = uniqueKeysTestMap.put(time, "");
if(result != null) {
System.out.println("failed! - " + time);
}
}
}
};
Thread t6 = new Thread() {
@Override
public void run() {
while(true) {
String time = generateShorterTxnId();
String result = uniqueKeysTestMap.put(time, "");
if(result != null) {
System.out.println("failed! - " + time);
}
}
}
};
Thread t7 = new Thread() {
@Override
public void run() {
while(true) {
String time = generateShorterTxnId();
String result = uniqueKeysTestMap.put(time, "");
if(result != null) {
System.out.println("failed! - " + time);
}
}
}
};
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
t7.start();
}
}
CẬP NHẬT : Mã này sẽ hoạt động trên JVM đơn lẻ, nhưng chúng ta nên suy nghĩ về JVM phân tán, do đó tôi đang nghĩ đến hai giải pháp một với DB và một giải pháp khác không có DB.
với DB
Tên công ty (tên viết tắt 3 ký tự) ---- Random_Number ---- Key cụ thể redis COUNTER
(3 ký tự ) -------------------------- ---------------------- (2 ký tự) ---------------- (11 ký tự)
không có DB
IPADDRESS ---- THREAD_NUMBER ---- INCR_NUMBER ---- epoch mili giây
(5 ký tự) ----------------- (2char) --------- -------------- (2 ký tự) ----------------- (6 ký tự)
sẽ cập nhật cho bạn sau khi mã hóa hoàn tất.
Không phải UUID, nhưng điều này phù hợp với tôi:
UUID.randomUUID().toString().replace("-","").substring(0,8)
Tôi không nghĩ rằng điều đó là có thể nhưng bạn có một cách giải quyết tốt.
new Random(System.currentTimeMillis()).nextInt(99999999);
này sẽ tạo ID ngẫu nhiên dài tối đa 8 ký tự.tạo id chữ và số:
char[] chars = "abcdefghijklmnopqrstuvwxyzABSDEFGHIJKLMNOPQRSTUVWXYZ1234567890".toCharArray();
Random r = new Random(System.currentTimeMillis());
char[] id = new char[8];
for (int i = 0; i < 8; i++) {
id[i] = chars[r.nextInt(chars.length)];
}
return new String(id);