2013年4月23日火曜日

MySQL 行の作成日と更新日を自動でつける

MySQLで日付型の列に行の作成日と更新日を自動で入れる方法を調査した。 以前使った、SQL Anywhereの場合だと「行の作成日と更新日を自動でつける」で書いたように行の作成日時、更新日時を列のデフォルト値とする構文があった。

MySQLでも同様のデフォルト値CURRENT_TIMESTAMPはあるようだがTimestamp型にのみ指定できるようである。 記法は以下2通りある。

DEFAULT CURRENT_TIMESTAMP
行が挿入された時刻
DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
行が挿入または更新された時刻

行が挿入された時刻をデフォルト値とする

DEFAULT CURRENT_TIMESTAMPを使う。

CREATE TABLE t1 (
  rid INTEGER,
  txt VARCHAR(20),
  ts1 TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
このようなテーブルに対して以下の行を挿入すると挿入時刻が自動で入る。
mysql> INSERT INTO t1 (rid,txt) VALUES(1,'aaa');
Query OK, 1 row affected (0.08 sec)

mysql> INSERT INTO t1 (rid,txt) VALUES(2,'bbb');
Query OK, 1 row affected (0.09 sec)

mysql> SELECT * FROM t1;
+------+------+---------------------+
| rid  | txt  | ts1                 |
+------+------+---------------------+
|    1 | aaa  | 2013-04-23 13:26:52 |
|    2 | bbb  | 2013-04-23 13:26:58 |
+------+------+---------------------+
2 rows in set (0.00 sec)

行の更新では変化しない。

mysql> UPDATE t1 SET txt='zzz' WHERE rid=1;
Query OK, 1 row affected (0.14 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> SELECT * FROM t1;
+------+------+---------------------+
| rid  | txt  | ts1                 |
+------+------+---------------------+
|    1 | zzz  | 2013-04-23 13:26:52 |
|    2 | bbb  | 2013-04-23 13:26:58 |
+------+------+---------------------+
2 rows in set (0.00 sec)

行が挿入または更新された時刻をデフォルト値とする

DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPを使う。
CREATE TABLE t2 (
  rid INTEGER,
  txt VARCHAR(20),
  ts1 TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
このようなテーブルに対して以下の行を挿入すると挿入時刻が自動で入る。
mysql>> INSERT INTO t2 (rid,txt) VALUES(1,'aaa');
Query OK, 1 row affected (0.11 sec)

mysql>> INSERT INTO t2 (rid,txt) VALUES(2,'bbb');
Query OK, 1 row affected (0.12 sec)

mysql>> SELECT * FROM t2;
+------+------+---------------------+
| rid  | txt  | ts1                 |
+------+------+---------------------+
|    1 | aaa  | 2013-04-23 13:27:09 |
|    2 | bbb  | 2013-04-23 13:27:12 |
+------+------+---------------------+
2 rows in set (0.00 sec)

行を更新すると自動で書き換わる。

mysql> UPDATE t2 SET txt='zzz' WHERE rid=1;
Query OK, 1 row affected (0.08 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> SELECT * FROM t2;
+------+------+---------------------+
| rid  | txt  | ts1                 |
+------+------+---------------------+
|    1 | zzz  | 2013-04-23 13:28:00 |
|    2 | bbb  | 2013-04-23 13:27:12 |
+------+------+---------------------+
2 rows in set (0.00 sec)

1つのテーブルにDEFAULT CURRENT_TIMESTAMPDEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPを両方定義しようとすると"Incorrect table definition"のエラーになってしまう。 両方同時に使えると作成時刻と更新時刻の両方が管理でき便利なのだが残念。 ただし、DDLとINSERTのSQLを少し工夫することで同等のことができるようだ。 その方法は「その2」のほうに書いてみた。

CREATE TABLE t3 (
  rid INTEGER,
  txt VARCHAR(20),
  ts1 TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  ts2 TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

詳しくはリファレンスに書いてある。

2013年4月4日木曜日

MySQLのwait_timeout

my.iniでwait_timeoutを設定してみたがshow variablesでみるとデフォルト値と変わっていないのだが @@GLOBAL.wait_timeoutのほうは設定値が反映されている。
mysql> show variables like 'wait_timeout';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout  | 28800 |
+---------------+-------+
1 row in set (0.00 sec)

mysql> SELECT @@GLOBAL.wait_timeout;
+-----------------------+
| @@GLOBAL.wait_timeout |
+-----------------------+
|                   600 |
+-----------------------+
1 row in set (0.00 sec)
どっちが正しいのだろうか?謎。

2013年4月3日水曜日

EclipseがCPUを占有してしまう

特に処理をしているわけでもないのに何かのタイミングでEclipse(3.7 SP2)がCPU 1つを100%占有するようになってしまう。 こうなるとEclipseを落としてやらないと元に戻らないのだが原因がわからず困っていた。

最近分かってきたのだが、どうやら入れているプラグインの一つ「プロパティエディタ」が怪しいようである。 EclipseのJVMのプロファイルをJava VisualVMでとってみると、このチケットと同じようにSynchtonizableDocument.getLockObject()メソッドはじめスタックトレースに出ているほかのメソッドが実行時間の上位に出てくる。

プロパティエディタは日本語で直接Javaのプロパティをかけるので手放せないのだが、残念なことに最近アップデートされていない。 このチケットの対応も今後無いだろうと思う。 代わりのプラグインが何かあるとよいのだが英語圏の人には不要なツールなので難しいだろう。

どうするか…

Android ParcelでString[]を読んだり書いたり

AndroidのJavaオブジェクトのシリアライズ機構ParcleにStringの配列を読み書きする方法。

メソッド名の対応からしてwriteStringArray()で書いたものをreadStringArray()で読み込むのだろうと思っていたが読むほうはcreateStringArray()になるようである。 以下のような感じになるらしい。

public class MyObj implements Parcelable {

  private String[] texts;

  // 読むほう
  public MyObj(Parcel in) {
    texts = in.createStringArray();
  }

  // 書くほう
  @Override
  public void writeToParcel(Parcel out, int flags) {
    out.writeStringArray(texts);
  }

  ...
}

readStringArray()でも読み込めるようだが、書き込んだ長さと同じ配列をあらかじめ準備して引数に指定するらしい。 長さが決まってない配列に使うのは面倒そうだし、nullは扱えなさそうである。 固定長の配列を連続読み込みするような場合には使えそうだが、それ以外はあまり出番が無いのではと思う。