データベースのテーブルを Javaで作る

Java

※本エントリは、ORMがどうでJavaEEがこうで、という事情に詳しくない一般的なプログラマに向けて書かれているため、全体的に平たい表現が用いられている。

create table文を書くのではなく、Javaプログラムとしてテーブル定義を行う方法。
下記のようなテーブルを例に説明する。

create table user_info (
  id integer auto_increment primary key, -- 自動発番の整数プライマリキー列
  name varchar(255) NOT NULL, -- 文字列, NULLを許容しない
  birthday date,       -- 日付
  created_at datetime NOT NULL, -- 日時, NULLを許容しない
);

このテーブルを create table文の代わりに Javaのクラスとして表現するとこうなる。

@Entity
@Table(name="user_info")
public class UserInfo {
  @Column(name="id") @Id @GeneratedValue public int id;
  @Column(name="name",nullable=false) public String name;
  @Column(name="birthday") public Date birthday;
  @Column(name="created_at",nullable=false) public Timestamp createdAt;
}

データベースのテーブル名や列名の命名ルールはプロジェクトによってまちまちである(日本語が使われていたりすることもある)が、Javaでテーブルを定義する時は一般的な Javaの命名ルール(下記)に従っておき、実際のテーブル名や列名は各アノテーション(後述)のname属性で指定する。

クラス名の命名ルール:
単語ごとに先頭を大文字にする。アンダーバーは省く。上の例では user_info → UserInfo

メンバ変数名の命名ルール:
最初の単語は全て小文字、2番目以降の単語は先頭を大文字にする。アンダーバーは省く。上の例では created_at → createdAt

@Tableや@Idなど、@つきでソースコード内に記入されるものをアノテーションという(Java1.5から導入された比較的新しい機能)。アノテーションはクラスやメンバ変数、メソッドなどに付加情報を与えるのに使う(プログラムの実行自体に直接影響はしない)。
ここで使っているアノテーションは、クラスとテーブルを対応づけるための情報をソースに記述する目的のものである。代表的な物を下記に挙げる。

@Entityアノテーション
このクラスのオブジェクトはデータベースに保存されたり、データベースから読み込まれたりしますよ、という意味。

@Tableアノテーション
このクラスはデータベースのこのテーブルに対応していますよ、という意味(name=で実際のテーブル名を指定する)

@Columnアノテーション
このメンバ変数は、テーブルのこの列に対応していますよ、という意味(name=で実際の列名を指定する)。nullable=falseをつけると NOT NULLの意味になる。VARCHAR(20)のような長さの指定は length=で付ける。対象DBのネイティブなSQL表現でカラム定義を指定したい場合は columnDedinitionを使用する。
例)@Column(name="START_DATE", columnDefinition="DATE DEFAULT CURRENT_DATE")

@Idアノテーション
この列はプライマリキー(単一または複合プライマリキーの一部)ですよ、という意味。複合プライマリキーを用いる場合は当該フィールドに @Idアノテーションを付けるほかに、複合キーをあらわすクラスを別に作成し、@IdClassアノテーションで指定する。

@GeneratedValueアノテーション
この列はINSERTの時に自動生成(オートナンバーのような)される列ですよ、という意味。

Javaの基本型(int, double, booleanなど)で定義されたフィールドは NULLを表現できないので、NOT NULL制約を課していない列には基本型ではなくクラスを使う。(Integer, Double, Boolean)

こうして作成したクラスを使って、データベースに対して create table文を自動で発行することが出来る。MySQLデータベース上にテーブルを作成するサンプルプログラムを下記に示す(HibernateのSchemaUpdate APIを使用している)。

String hostname = "localhost";  // データベースのホスト名
String database = "test";   // データベース名
String username = "root";   // ユーザー名
String password = "secret";   // パスワード

AnnotationConfiguration cfg = new AnnotationConfiguration();
cfg.addAnnotatedClass(UserInfo.class);  // 作成したいテーブル数分だけ呼び出す
cfg.setProperty("hibernate.dialect",
   "org.hibernate.dialect.MySQL5InnoDBDialect");
cfg.setProperty("hibernate.connection.driver_class",
   "com.mysql.jdbc.Driver");
cfg.setProperty("hibernate.connection.url",
   "jdbc:mysql://" + hostname + '/' + database);
cfg.setProperty("hibernate.connection.username", username);
cfg.setProperty("hibernate.connection.password", password);
new SchemaUpdate(cfg).execute(true, true);

上記プログラムをコンパイル・実行するにあたって必要なライブラリは下記の通り。

mysql-connector-java-*-bin.jar - MySQLのJDBCドライバ
hibernate3.jar - Hibernate本体
dom4j-*.jar - Hibernate内部から利用
hibernate-annotations.jar - Hibernate Annotations用
hibernate-commons-annotations.jar - Hibernate Annotations用
ejb3-persistence.jar - @Entityなどの各アノテーション
slf4j-api-*.jar - ログ出力用
slf4j-jcl-*.jar - ログ出力用
commons-logging-*.jar - ログ出力用

なお Hibernateの SchemaUpdateは、

  • データベース上にテーブルが存在しない場合 create tableする
  • テーブルは存在するが列が足りない場合 alter tableで列を追加する
という処理を自動でしてくれるが、列が削除された場合や列の型や制約が変更された場合までは対応してくれないので、そのような変更をした場合はdrop tableでテーブルをいったん削除するなどの必要がある。

おまけ:PostgreSQLの場合

cfg.setProperty("hibernate.dialect",
  "org.hibernate.dialect.PostgreSQLDialect");
cfg.setProperty("hibernate.connection.driver_class",
  "org.postgresql.Driver");
cfg.setProperty("hibernate.connection.url",
  "jdbc:postgresql://" + hostname + '/' + database);

なお PostgreSQLの場合、@GeneratedValueアノテーションに何もオプションをつけないと、自動発番用に hibernate_sequenceというシーケンスが作られてしまった。これだと Hibernate専用になってしまい汎用性が無くなるので、strategy=GenerationType.IDENTITY オプションをつけて PostgreSQLネイティブの serial型を自動発番に用いるようにすると良い。

同じカテゴリの記事

ScalikeJDBCを Springで使う 2013年12月25日
Commons Codecを使わずにBase64エンコードをする 2010年8月9日
JRubyをJava組み込みで使うときの日本語文字化けについて 2010年7月14日
GWT DevMode doesn't find jndi.properties 2010年7月10日
GWTアプリケーションのバックエンドにSpring Frameworkを利用する 2010年7月9日

お勧めカテゴリ

英語でアニメ観ようず
なじみ深い日本製アニメの英語版DVDで、字幕と音声から英語を学びましょうという趣旨のシリーズ記事です。
ScalaのようでJavaだけど少しScalaなJSON API
Scalaと Spring Frameworkを使って REST的なJSON APIを実装してみましょう。
ドクジリアン柔術少女 すから☆ぱいそん
代表 嶋田大貴のブログです。写真は神仏に見せ金をはたらく罰当たりの図