Khả năng va chạm khi sử dụng hầu hết các bit quan trọng của UUID trong Java


235

Nếu tôi đang sử dụng thì Long uuid = UUID.randomUUID().getMostSignificantBits()có khả năng xảy ra va chạm. Nó cắt các bit ít quan trọng nhất, vì vậy có khả năng bạn gặp phải một vụ va chạm, phải không?

Câu trả lời:


213

Theo tài liệu , phương thức tĩnh UUID.randomUUID()tạo ra UUID loại 4.

Điều này có nghĩa là sáu bit được sử dụng cho một số thông tin loại và 122 bit còn lại được gán ngẫu nhiên.

Sáu bit không ngẫu nhiên được phân phối với bốn trong nửa đáng kể nhất của UUID và hai trong nửa ít quan trọng nhất. Vì vậy, một nửa đáng kể nhất trong UUID của bạn chứa 60 bit ngẫu nhiên, có nghĩa là trung bình bạn cần tạo 2 ^ 30 UUID để có được xung đột (so với 2 ^ 61 cho UUID đầy đủ).

Vì vậy, tôi sẽ nói rằng bạn khá an toàn. Tuy nhiên, lưu ý rằng điều này hoàn toàn không đúng với các loại UUID khác, như Carl Seleborg đề cập.

Ngẫu nhiên, bạn sẽ khá hơn một chút bằng cách sử dụng một nửa UUID ít quan trọng nhất (hoặc chỉ tạo ra một thời gian dài ngẫu nhiên bằng SecureRandom).


3
Tôi không chắc chắn điều này là hoàn toàn chính xác - nhìn vào quá trình thực hiện, rõ ràng thông tin về phiên bản / biến thể không được lưu trữ trong các bit quan trọng nhất, mà là ở đâu đó ở giữa.
Tom

2
@RasmusFaber Nhận xét của Tom là chính xác: Câu trả lời ở đây không chính xác về sáu bit quan trọng nhất là thông tin loại. Thực tế có sáu bit dữ liệu không ngẫu nhiên nhưng bốn bit xác định Phiên bản 4 và hai bit khác được bảo lưu. Bốn và hai bit được đặt ở các vị trí khác nhau gần giữa giá trị 128 bit. Xem bài viết Wikipedia .
Basil Bourque



10

Bạn tốt hơn hết là chỉ tạo ra một giá trị dài ngẫu nhiên, sau đó tất cả các bit là ngẫu nhiên. Trong Java 6, Random () mới sử dụng System.nanoTime () cộng với bộ đếm làm hạt giống.

Có nhiều cấp độ khác nhau.

Nếu bạn cần sự độc đáo trên nhiều máy, bạn có thể có một bảng cơ sở dữ liệu trung tâm để phân bổ các id duy nhất hoặc thậm chí các lô id duy nhất.

Nếu bạn chỉ cần có tính duy nhất trong một ứng dụng, bạn có thể chỉ cần một bộ đếm (hoặc bộ đếm bắt đầu từ currentTimeMillis () * 1000 hoặc nanoTime () tùy theo yêu cầu của bạn)


7

Sử dụng Thời gian YYYYDDDD(Năm + Ngày trong năm) làm tiền tố. Điều này làm giảm sự phân mảnh cơ sở dữ liệu trong các bảng và chỉ mục. Phương thức này trả về byte[40]. Tôi đã sử dụng nó trong môi trường kết hợp trong đó Active Directory SID ( varbinary(85)) là khóa cho người dùng LDAP và ID tự động tạo ứng dụng được sử dụng cho người dùng không phải LDAP. Ngoài ra, số lượng lớn giao dịch mỗi ngày trong các bảng giao dịch (Ngành ngân hàng) không thể sử dụng các Intloại tiêu chuẩn cho Khóa

private static final DecimalFormat timeFormat4 = new DecimalFormat("0000;0000");

public static byte[] getSidWithCalendar() {
    Calendar cal = Calendar.getInstance();
    String val = String.valueOf(cal.get(Calendar.YEAR));
    val += timeFormat4.format(cal.get(Calendar.DAY_OF_YEAR));
    val += UUID.randomUUID().toString().replaceAll("-", "");
    return val.getBytes();
}

3
Tại sao không sử dụng UUID V1 tiêu chuẩn thay thế?
ShadowChaser
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.