Kemungkinan tabrakan menggunakan bit paling signifikan dari UUID di Jawa

235

Jika saya menggunakan Long uuid = UUID.randomUUID().getMostSignificantBits()seberapa besar kemungkinan akan terjadi tabrakan. Ini memotong bit paling tidak signifikan, jadi ada kemungkinan Anda mengalami tabrakan, kan?

dlinsin
sumber

Jawaban:

213

Menurut dokumentasi , metode statis UUID.randomUUID()menghasilkan UUID tipe 4.

Ini berarti bahwa enam bit digunakan untuk beberapa jenis informasi dan 122 bit sisanya ditugaskan secara acak.

Enam bit non-acak didistribusikan dengan empat di bagian paling signifikan dari UUID dan dua di bagian paling tidak signifikan. Jadi, bagian terpenting dari UUID Anda berisi 60 bit keacakan, yang berarti Anda rata-rata perlu menghasilkan 2 ^ 30 UUID untuk mendapatkan tabrakan (dibandingkan dengan 2 ^ 61 untuk UUID lengkap).

Jadi saya akan mengatakan bahwa Anda agak aman. Namun, perlu diketahui bahwa ini sama sekali tidak benar untuk jenis UUID lainnya, seperti yang dikatakan Carl Seleborg.

Kebetulan, Anda akan sedikit lebih baik dengan menggunakan setengah paling tidak signifikan dari UUID (atau hanya menghasilkan panjang acak menggunakan SecureRandom).

Rasmus Faber
sumber
3
Saya tidak yakin ini sepenuhnya benar - melihat implementasinya, jelas bahwa informasi versi / varian tidak disimpan dalam bit yang paling signifikan, melainkan di suatu tempat di tengah.
Tom
2
@RasmusFaber Komentar oleh Tom benar: Jawaban di sini tidak benar tentang enam bit yang paling signifikan adalah tipe informasi. Memang ada enam bit data non-acak tetapi empat bit mengidentifikasi Versi 4 dan dua bit lainnya dicadangkan. Empat dan dua bit terletak di posisi yang berbeda di dekat bagian tengah dari nilai 128-bit. Lihat artikel Wikipedia .
Basil Bourque
10

Anda lebih baik hanya menghasilkan nilai acak panjang, maka semua bit acak. Di Jawa 6, Acak baru () menggunakan System.nanoTime () plus penghitung sebagai seed.

Ada berbagai tingkat keunikan.

Jika Anda memerlukan keunikan di banyak mesin, Anda bisa memiliki tabel basis data pusat untuk mengalokasikan id unik, atau bahkan batch id unik.

Jika Anda hanya perlu memiliki keunikan dalam satu aplikasi, Anda hanya dapat memiliki penghitung (atau penghitung yang dimulai dari currentTimeMillis () * 1000 atau nanoTime () tergantung pada kebutuhan Anda)

Peter Lawrey
sumber
7

Gunakan Waktu YYYYDDDD(Tahun + Hari Tahun) sebagai awalan. Ini mengurangi fragmentasi database dalam tabel dan indeks. Metode ini kembali byte[40]. Saya menggunakannya di lingkungan hibrid di mana Active Directory SID ( varbinary(85)) adalah kunci untuk pengguna LDAP dan ID yang dibuat secara otomatis aplikasi digunakan untuk Pengguna non-LDAP. Juga sejumlah besar transaksi per hari dalam tabel transaksional (Industri Perbankan) tidak dapat menggunakan Intjenis standar untuk Kunci

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();
}
Dr Bob
sumber
3
Mengapa tidak menggunakan UUID V1 standar saja?
ShadowChaser