Javaでグローバルに一意の識別子を生成する
-
08-07-2019 - |
質問
概要:永続的なJava Webアプリケーションを開発しています。重複を防ぐために、永続化するすべてのリソースにグローバルに一意の識別子があることを確認する必要があります。
ファインプリント:
- RDBMSを使用していないため、派手なシーケンスジェネレーター(Oracleが提供するものなど)がありません
- 高速で、できればすべてメモリ内に保存したい-ファイルを開いて値を増やす必要はない
- スレッドセーフである必要があります(IDを生成するのに必要なJVMは一度に1つだけになると予想しています)
- JVMのインスタンス間で一貫性が必要です。サーバーがシャットダウンして起動した場合、IDジェネレーターは、以前のインスタンス化で生成したIDと同じIDを再生成するべきではありません(または少なくとも、本当に、本当にスリムである必要があります-何百万ものリソースが存在すると予想されます)
- EJBのユニークIDパターンの記事の例を見てきました。それらは私には機能しません(ミリ秒ごとに複数のリソースを保持するため、System.currentTimeMillis()だけに頼るのではなく)。
- 私は thisで提案された回答を見ました質問。それらについての私の懸念は、時間の経過とともに重複IDを取得する可能性があることです。 javaを使用する提案に興味があります。 UUID の場合は.util.UUID ですが、重複する可能性があります限りなく小さくする必要があります。
- JDK6を使用しています
解決
UUIDが<!> quot;十分<< >> quot;であることを確認してください。 340,282,366,920,938,463,463,374,607,431,770,000,000 UUIDが利用可能です。
http://www.wilybeagle.com/guid_store/guid_explain.htm
<!> quot;これらの数値を概観すると、met石に衝突する年間リスクは170億回に1回であると推定されます。つまり、確率は約0.00000000006(6 <!>#215; 10 <!>#8722; 11)、1年で数十兆個のUUIDを作成し、1つの複製を作成する確率に相当します。つまり、次の100年間にわたって毎秒10億UUIDを生成した後にのみ、1つの複製が作成される可能性は約50%になります。地球上のすべての人が6億のUUIDを所有している場合、1回の重複の可能性は約50%です。<!> quot;
他のヒント
public class UniqueID {
private static long startTime = System.currentTimeMillis();
private static long id;
public static synchronized String getUniqueID() {
return "id." + startTime + "." + id++;
}
}
PCごとに一意である必要がある場合:(System.currentTimeMillis() << 4) | (staticCounter++ & 15)
などを使用できます。
これにより、1ミリ秒あたり16を生成できます。さらに必要な場合は、5シフトし、31でシフトします...
複数のPCで一意にする必要がある場合は、プライマリネットワークカードのMACアドレスも結合する必要があります。
編集:明確にする
private static int staticCounter=0;
private final int nBits=4;
public long getUnique() {
return (currentTimeMillis() << nBits) | (staticCounter++ & 2^nBits-1);
}
nBitsをmsごとに生成する必要がある最大数の平方根に変更します。
最終的にロールオーバーします。おそらく20年か、nBitsが4の何か。
メモリから、RMIリモートパッケージにはUUIDジェネレータが含まれています。調査する価値があるかどうかはわかりません。
それらを生成しなければならなかった場合、通常は現在の日時のMD5ハッシュサム、ユーザー名、コンピューターのIPアドレスを使用します。基本的には、コンピューター/人について知ることができるすべてのものを取得し、この情報のMD5ハッシュを生成するという考え方です。
これは非常にうまく機能し、信じられないほど高速です(MessageDigestを初めて初期化した後)。
このようにしない理由
String id = Long.toString(System.currentTimeMillis()) +
(new Random()).nextInt(1000) +
(new Random()).nextInt(1000);
java UUIDが参照するより短くて高速な実装を使用する場合:
javadocの実装の選択と制限を参照してください。
使用方法の単体テストは次のとおりです。