Java'da bir UUID'nin en önemli bitlerini kullanarak çarpışma olasılığı


235

Eğer Long uuid = UUID.randomUUID().getMostSignificantBits()bir çarpışma yaşama ihtimalini kullanıyorsam . En az önemli bitleri keser, bu yüzden bir çarpışmaya girme olasılığı vardır, değil mi?

Yanıtlar:


213

Belgelere göre , statik yöntem UUID.randomUUID()tip 4 UUID üretir.

Bu, bazı tip bilgileri için altı bit kullanıldığı ve kalan 122 bitin rastgele atandığı anlamına gelir.

Altı rasgele olmayan bit, UUID'nin en önemli yarısında dört ve en az önemli yarısında iki ile dağıtılır. Yani UUID'nizin en önemli yarısı 60 bit rasgelelik içerir, bu da bir çarpışma için ortalama 2 ^ 30 UUID üretmeniz gerektiği anlamına gelir (tam UUID için 2 ^ 61 ile karşılaştırıldığında).

Bu yüzden oldukça güvenli olduğunu söyleyebilirim. Bununla birlikte, bunun Carl Seleborg'un belirttiği gibi, diğer UUID türleri için kesinlikle doğru olmadığını unutmayın.

Bu arada, UUID'nin en az önemli yarısını kullanarak (veya sadece SecureRandom kullanarak rastgele bir uzun üreterek) biraz daha iyi durumda olursunuz.


3
Bunun tamamen doğru olduğundan emin değilim - uygulamaya bakarak, sürüm / varyant bilgisinin en önemli bitlerde değil, ortada bir yerde saklandığı açıktır.
Tom

2
@RasmusFaber Tom'un yorumu doğrudur: Buradaki cevap , tip bilgisi olan en önemli altı bit için yanlıştır . Aslında altı bit rastgele olmayan veri vardır, ancak dört bit Sürüm 4'ü tanımlar ve diğer iki bit ayrılır. Dört ve iki bit, 128 bit değerinin ortasına yakın farklı konumlarda bulunur. Bkz Wikipedia makalesi .
Basil Bourque



10

Sadece rastgele uzun bir değer üretmek daha iyidir, o zaman tüm bitler rastgele. Java 6'da yeni Random (), System.nanoTime () artı sayacı tohum olarak kullanır.

Farklı düzeylerde benzersizlik vardır.

Birçok makinede benzersizliğe ihtiyacınız varsa, benzersiz kimlikleri veya hatta benzersiz kimlikleri gruplamak için merkezi bir veritabanı tablonuz olabilir.

Tek bir uygulamada benzersiz olmanız gerekiyorsa, bir sayacınız (veya gereksinimlerinize bağlı olarak currentTimeMillis () * 1000 veya nanoTime () ile başlayan bir sayacınız olabilir)


7

YYYYDDDDÖnek olarak Zamanı (Yıl + Yılın Günü) kullanın . Bu, tablolarda ve dizinlerde veritabanı parçalanmasını azaltır. Bu yöntem geri döner byte[40]. Active Directory SID'nin ( varbinary(85)) LDAP kullanıcıları için anahtar olduğu ve LDAP kullanıcıları için otomatik olarak oluşturulan bir uygulamanın kullanıldığı karma bir ortamda kullandım. Ayrıca, işlem tablolarında (Bankacılık Endüstrisi) günlük çok sayıda işlem IntAnahtarlar için standart türleri kullanamaz

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
Bunun yerine neden standart bir V1 UUID kullanmıyorsunuz?
ShadowChaser
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.