他の何とも被らない、一意なIDを作成したい場合・・・
もし自己流で実装するとなると、間違いなく重複するし安全じゃありません。
あと「これは一意なIDになるだろ」と思っていても、実はやってはいけないアンチパターンだったということもあります。(結果いちからやり直しになる)
そこで過去の自分への戒めも込めて、
一意なIDを生成するNGなやり方と本当に正しい方法をまとめてみました。
重複しないIDを生成するには、既存メソッドを使うのが一番です。
このページの目次
まず一意なID生成でやりがちなNG例について
まずは一意なIDを生成する上での絶対NGなコードについて
その代表例は現在の日時とか時刻を使うこと
一番安易にIDが作れるけど、絶対に使わない方がいいです。
(ただし重複してもいいなら日時を使う方が簡単)
例えばPHPの場合、こんな感じで日時からIDを生成できます(でも間違い)
▼ 間違ったコード例
1 2 3 4 |
$now = date_create(); $bad_uid = date_format( $now, 'Y-m-d-H-i-s-u' ); echo $bad_uid; /// => 2019-08-29-03-35-45-208746 |
この例だと
Y-m-d-H-i-s-u で日時をフォーマットしてます。
なのでマイクロ秒(例 :
654321 )とかまで含めることが可能
一見問題なさそうだけど、次の点がマズいですね。
- 時刻なので普通に重複する
例えばWebサービスだったら、たまたまアクセスタイミングが同じで重複する可能性アリ
- 時刻のずれでも重複する
あと端末間・国ごとの時差を考慮すると、もっと衝突する確率は高くなる
確かに1つの端末だったら重複しないIDが作れます。
でも複数のユーザーが使うアプリ・Webサービスだったら・・・こんな一意なIDの生成の仕方は絶対ありえないです。IDじゃないならアリかもしれないけど
一番確実なのはUUIDを使うこと
そもそも重複しないIDを作るための規格はすでに存在します。
それが UUID(Universally Unique Identifier)という識別子
これを使うのが一番重複しない確率が低いらしいです。
▼ 万能Wikipedia君による説明
UUID(Universally Unique Identifier)とは、ソフトウェア上でオブジェクトを一意に識別するための識別子である。UUIDは128ビットの数値だが、16進法による550e8400-e29b-41d4-a716-446655440000というような文字列による表現が使われることが多い。元来は分散システム上で統制なしに作成できる識別子として設計されており、したがって将来にわたって重複や偶然の一致が起こらないという前提で用いることができる[1]。マイクロソフトによるGUIDは、UUIDの実装の1つと見なせる[2]。
特別なことをしなくても、重複しないという "前提" で使える模様
「ん?前提?・・・前提ということは衝突する確率もあるの?」と思ってしまいますが、 "天文学的な確率" なのでまったく心配する必要とかありません。
ちなみに、なぜ重複しないかの説明 は次記事が分かりやすかったです。
▼ UUID(v4) がぶつかる可能性を考えなくていい理由
この記事で 鳩の巣原理 とか 誕生日のパラドックス とか使って説明されてます。
記事の最後だけ引用すると、ぶつかる確率はこうなるらしいです。
UUID(ver.4) は122ビットの乱数なので生成したUUIDが既存のものにぶつかるまでの回数の期待値は
2122/2 = 2305843009213693952回=2.3∗1018
230京回となります。これはぶつからない!
これはぶつからない!
というか 230京回 って多すぎて実感が湧かない!!
なので0.1秒に1回UUIDを生成したとして考えてみます。
そのペースで230京回生成し終わるまでにかかる時間は・・・
1 2 3 |
230(京回) * 0.1(秒) = 230000000000000000(秒) / 60 / 60 / 24 / 365 = 7394547325.10(年) = 約73.9(億年) |
宇宙の年齢が138億年と言われてるから、
なんと 宇宙の半分以上の時間 が過ぎてから重複するレベル
これなら UUID が重複しないと言われてるのも納得です。
重複しないIDを生成するには(Javaでのコード例)
それでUUIDの具体的な生成方法について
これは各言語ごとにUUIDクラスがサポートされてれば普通に生成できます。
たとえば Java の場合、UUIDを生成するコードは次の通り
▼ UUIDを生成するコード
1 2 3 4 5 6 7 8 9 |
import java.util.*; public class Main { public static void main(String[] args) throws Exception { // Your code here! System.out.println(UUID.randomUUID().toString()); } } |
▼ このJavaコードの出力結果
1 |
797cc11e-3f3b-4e07-81fd-6ba50fcafa4f |
こういうUUIDクラスは Java の他には Kotlin にもあるし、
iPhoneアプリ開発で使われる Swift とか Objective-C でも使えます。
なのでサーバーと連携するアプリとか作るときに便利かも
ちなみにPHPで UUID を生成するには
あと蛇足なんですが、
残念ながらPHPだと UUID を生成する標準クラスはないみたいです。
でも次の記事で詳解されてたライブラリを使えば生成可能
▼ phpでUUIDを作成する
UUIDのバージョン1~4に対応してるなかなか高性能なライブラリ
実用的に使うならバージョン4を使っておけば問題ないと思います。
一意なIDを作るなら UUID を使おう
とりあえず、一意なIDなら UUID を使っとけば問題なさそう
Java、Kotlin、 Swift、Objective-C とかなら標準でサポートされるし、
PHP・JavaScriptとかでもライブラリを導入すれば簡単に使えます。
以上、一意で重複しないIDの作り方についてでした。