MySQL41 と PHP の間で文字化けをスマートに防ぐ(クライアントがSJIS以外の時)

$encod$#INGu = ‘ujis’; // ‘utf8’, ‘cp932’ ..
$con->query(‘SET NAMES ‘.$encoding);

などとすると、いちいち送受信時に mb_convert_encoding() とかしてやる必要は皆無になる。
通信時

IP アドレスを格納するのに最適なカラム型

MySQL4.x で IP アドレスを保存するには、int にして、関数で変換して利用してやると文字列よりも加工がしやすい。

mysql> SELECT INET_ATON(“209.207.224.40”);
       -> 3520061480

mysql> SELECT INET_NTOA(3520061480);
       -> “209.207.224.40”

ネットマスクは例えば次のようにチェックできる。

mysql> select INET_ATON(“192.168.0.255”) & INET_ATON(“192.168.0.0”) = INET_ATON(“192.168.0.0”);
       -> 1
 
mysql> select INET_ATON(“192.167.255.1”) & INET_ATON(“192.168.0.0”) = INET_ATON(“192.168.0.0”);
       -> 0

Java + MySQL41 で文字化け対策

Java, MySQL 間の通信を MySQL の文字コードにあわせてやる必要がある。
具体的には, JDBC での接続時に characterEncoding=utf8 など MySQL の
文字コードを指定したクエリをつけてやる。

jdbc:mysql:localhost:3306/foo?useUnicode=true&characterEncoding=utf8

Tomcat なら server.xml などの設定ファイルの 該当 JDBC 接続の Resource で
設定すればよい。

UPDATE で同じ条件の任意数のレコードだけ更新したい

– ORDER BY と LIMIT を使えばよい。UPDATE にもあるとは知らなかった..迂闊。
<http://dev.mysql.com/doc/mysql/ja/update.html>
– MySQL リファレンスマニュアル :: 6.4.4 UPDATE 構文

 UPDATE [LOW_PRIORITY] [IGNORE] tbl_name
    SET col_name1=expr1 [, col_name2=expr2 …]
    [WHERE where_definition]
    [ORDER BY …]
    [LIMIT row_count]

最初こういうことをやって、同じテーブルに対して更新と参照を同時にやるなと怒られた。

UPDATE footable SET name = ‘foo’ WHERE id = (SELECT id FROM footable
  WHERE gender = 1)

最後に挿入したレコードの一意な ID を取得する

– LAST_INSERT_ID() を使うとよい。

INSERT INTO user_list (id,name) values (555, “foo”);
SELECT LAST_INSERT_ID();
 +——————+
 | LAST_INSERT_ID() |
 +——————+
 | 555 |
 +——————+

という感じ。コネクション単位で保持しているので、同時アクセスがあっても干渉しない。ただし、取得する ID は AUTO_INCREMENT でなければならない。
http://dev.mysql.com/doc/mysql/ja/getting-unique-id.html
– MySQL リファレンスマニュアル :: 11.1.12.3 最後に挿入したレコードの一意な ID はどのように取得するのか

Bug Pattern というか今日のミス

– 事前に気づいたけど相当焦ったもの。

SELECT * FROM foo WHERE …;

な、ただレコードの有無を調べる(要素は取り出さない)クエリのパフォーマンスを意識して SQL クエリのみ書き換えたときに、うっかり次のようにしまった。

SELECT COUNT(*) FROM foo WHERE …;

常に 1 レコード返るようになり、レコード数 0 のときも毎回処理が行われることに… リリース前に自分で気づいたけれど反省。

MySQL で ENUM を使うべきではない

– ENUM 型のカラムには、リストにない任意の文字列をエラーなしで指定できてしまうため、不具合の温床になりうる。例えば次のテーブルを考える。

CREATE TABLE `foo` ( `number` ENUM(‘zero’,’one’,’two’) NOT NULL DEFAULT ‘zero’);

これに zero, one, two 以外の値が入ることは望ましくないが、リストにない文字列をいれることで空文字が入ってしまう。

mysql> INSERT INTO `foo` VALUES (‘six’);
Query OK, 1 row affected, 1 warning (0.03 sec)
 
mysql> select * from foo;
 +——–+
 | number
 +——–+
 |
 +——–+
1 row in set (0.02 sec)

これは typo でも発生してしまうため、TINYINT などを使って、マジックナンバーは各言語の const 変数でラップしたほうがエラーを捕捉できていいかなと。