ソーシャルサービス系のデータベースを構築する~ ユーザー情報編
ユーザー情報テーブルを作成してみよう
今回、どんなサービス、およびシステムでもありそうなユーザーマスタテーブルを設計/構築してみたいと思います ただ、テーブルを作る、登録しただけですと、ちょっとつまらないので今回は、ダイナミックカラムと、PASSWORD関数を利用してみようと思います
キングジム パスワードマネージャー ミルパス PW10 ブラック
- 出版社/メーカー: キングジム
- 発売日: 2012/10/05
- メディア: オフィス用品
- クリック: 40回
- この商品を含むブログ (9件) を見る
・・とその前に、今後いくつか作られるであろう、テーブルの共通ルールを記載していきたいと思います
テーブル共通項目
id 列
どのテーブルにもかならず、id列 (*1) を作成する
created_at
レコードが作成された日時を設定する、ただしプログラムからは、設定しない(defaultで制御する)
updated_at
レコードが更新された日時を設定する、ただしプログラムからは設定しない(defualtで制御する) ※今回の設計では、MariaDB10.1を利用しますので、ちょっと特殊なカラム設定を利用します
*1 IDリクワイアド アンチパターン IDリクワイアドは「すべてのテーブルに"id"という列名の無意味な連番の列を追加し、PRIMARY KEY制約を付与する」というパターンのこと。 の話がとある書籍から書いてあると思いますが、数百、場合によっては数千あるテーブルで、いちいち member_id だの、 customer_id だのと名前を変えられる場合を考えてみてください。データベース管理者の視点からみりゃ、地獄ですw
ここでは、すべてのテーブルにidというプライマリーキーを付与しますが、たとえば、userテーブルのidは、user_idだし、 customerテーブルのidは、customer_idです。暗黙的な意味づけで実装したほうが管理が楽です。
もちろん、id以外で一意性が必要な項目は、UNIQUE制約をつけます。UNIQUEをつけないで、id列以外の項目が重複して困ったという話がよくありますが、そもそも、それこそ設計不備だろwと考えております
users テーブル生成
共通項目を踏襲した上で、以下のテーブルを作成しました
テーブル定義
CREATE TABLE `users` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `login` varchar(200) NOT NULL, `passwd` varchar(200) NOT NULL, `mail` varchar(200) NOT NULL, `ext` blob, PRIMARY KEY (`id`), UNIQUE KEY `ix02_users` (`login`), KEY `ix01_users` (`mail`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 ;
login
ログインIDを設定します。ここに本来ユーザーが記入するコードが入ってきます(user01とか、pandaとか)
passwd
パスワードが入ります。といっても、平文(クリアテキスト)で入るわけではありません、PASSWORD 関数でハッシュ化した文字が入ります。
- 例、passをhash化したもの
SELECT PASSWORD('pass') ; +-------------------------------------------+ | PASSWORD('pass') | +-------------------------------------------+ | *196BDEDE2AE4F84CA44C47D54D78478C7E2BD7B7 | +-------------------------------------------+
※暗号化した文字は、複合化することはできません
これは、そのまま、メールアドレスのエリアですね。
ext
拡張フィールドです、これは以前、説明したのような使い方で、たとえば性別とか、年齢を今回は入れております
user テーブルへINSERT
では、さっそくUSER情報をインサートしてみましょう
SET @login = 'user1' ; SET @passwd = PASSWORD('user1pass') ; SET @mail = 'hit@hateblo.jp' ; SET @ext = COLUMN_CREATE( "age", 21, "sex", "man", "profile","ユーザー登録のテストです。よろしく" ) ; INSERT INTO users ( login, passwd, mail, ext ) VALUES ( @login, @passwd, @mail, @ext ) ; SET @login = 'user2' ; SET @passwd = PASSWORD('user2pass') ; SET @mail = 'user2@hateblo.jp' ; SET @ext = COLUMN_CREATE( "age", 21, "sex", "man", "profile","ユーザー2になります。皆様よろしくお願いします。", "hobby","映画観賞" ) ; INSERT INTO users ( login, passwd, mail, ext ) VALUES ( @login, @passwd, @mail, @ext ) ;
userテーブル登録結果確認
上記がレコード上、どのように登録されたか確認してみます
mysql> SELECT id,login,passwd,mail,COLUMN_JSON(ext) FROM users \G *************************** 1. row *************************** id: 1 login: user1 passwd: *F20B90D5A0CED3757C51AE04CD4700AB9879E467 mail: hit@hateblo.jp COLUMN_JSON(ext): {"age":21,"sex":"man","profile":"ユーザー登録のテストです。よろしく"} *************************** 2. row *************************** id: 2 login: user2 passwd: *A9C95B38C9A88ECAE9128FD396059335E97CAA6E mail: user2@hateblo.jp COLUMN_JSON(ext): {"age":21,"sex":"man","hobby":"映画観賞","profile":"ユーザー2になります。皆様よろしくお願いします。"}
意図したとおりに、データが登録されていることを確認できました。 extのカラムにつきましては、上記通り定義を変更せず、カラムの増減が行えますが、おそらくインデックス的には何も効かないので、あくまでも情報的なものだけを設定するほうがよいかと思います。 たとえば、今回の例ですと、ageという年齢カラムを設定しておりますが、今後、SQLで年齢が、30以上を検索が必要なサービスには向きません(汗 そういう場合は、ちゃんと、ageというカラムを作るべきだと思います
ユーザー情報を検索する
通常の検索はさておき、とりあえずログインするというのを前提にしたSQLはこんな感じになるのかな?と思います
SET @password='user1pass' ; SET @login='user1' ; SET @passwd=PASSWORD(@password) ; SELECT id as user_id, login, COLUMN_GET(ext,'sex' AS CHAR) AS sex, COLUMN_GET(ext,'age' AS CHAR) AS age FROM users WHERE login = @login AND passwd = @passwd ; +---------+-------+------+------+ | user_id | login | sex | age | +---------+-------+------+------+ | 1 | user1 | man | 21 | +---------+-------+------+------+
ポイントとしては、一度平文で送られてきたパスワードをPASSWORD関数で、エンコードした結果を、WHERE条件に加えているところですね。こうしておけば、万が一、パスワードが流出してもわからなくなるはずです
今回はここまでー。