Entity+MySQL では予約語に注意

Hibernate EntityManagerをMySQLで実行した報告の追伸。発生したSQL文法エラーはすべて予約語の問題。テストケースを修正して解消しました。

前回は、Hibernate EntitymanagerのテストケースをMySQL4.0で実行して結果を報告しました。その後、MySQL4.1/5.0でも同様にやってみましたが、エラーの状況は変わらず。

「SQL文法エラーが多い」ことを報告してましたが、SQLを抽出して、解決してみます。今日は、その報告です。

エラーを吐くSQLの抽出

テスト実行時、こんな感じに設定すれば、SQLだけが全部ログに吐き出されます。

./test/log4j.properties

 log4j.appender.file=org.apache.log4j.FileAppender
 log4j.appender.file.File=hibernate.log
 log4j.appender.file.layout=org.apache.log4j.PatternLayout
 log4j.appender.file.layout.ConversionPattern\
   =%d{ABSOLUTE} %5p %c{1}:%L - %m%n
 log4j.rootLogger=warn, file
 log4j.logger.org.hibernate.SQL=debug

テスト実行後のログを追ってみると、文法エラーになっているのは、次の4つ。

 create table Race_Competitor (
  Race_id integer not null,
  competitors_id integer not null,
  index integer not null,
  primary key (Race_id, index)
  ,unique (competitors_id) )
 create table Mail (
  id bigint not null,
  from varchar(255),
  primary key (id))
 create table Lock (
  id integer not null auto_increment,
  name varchar(255),
  version integer,
  primary key (id))
 create table Workload (
  id integer not null auto_increment,
  name varchar(255),
  load integer,
  primary key (id))

テストケースの修正

一見なんのヘンテツもないSQLに見えますが、index、from、Lock、loadが予約語ですね。なんていじわるなテストケース(怒。

予約語は使わないように、各クラスをかきかえてみました。修正するファイルは、次の7つ。

  org.hibernate.ejb.test.emops.Race
  org.hibernate.ejb.test.lock.Lock
  org.hibernate.ejb.test.lock.LockTest
  org.hibernate.ejb.test.emops.Mail
  org.hibernate.ejb.test.ops.Workload
  org.hibernate.ejb.test.ops.GetLoadTest
  org.hibernate.ejb.test.ops.mergeNewTest

修正方法は、プロパティ名を変えるか、アノテーションで違うカラム名にマップするかどちらか。

例えばLockの場合は、クラス名をかえてしまうか、

  @Entity
  @Table(name="Lock_")
  public class Lock {
      :
  }

とかにすればOKです。
ここまで修正すると、SQLSyntaxエラーは消えて、テストカバレージは95.70%になります。MySQLは予約語に敏感なデータベースである。Entityクラスの命名には気を使わねば。という特徴が分かりました。これだけでも大きな収穫でした。

あとはシーケンスの問題

CascadeTestあたりで「シーケンスに対応していない」というエラーを吐いてしまいます。MySQLには、シーケンスオブジェクトの概念が存在しないので、どうしようもないのか。

これはEntityManagerではなくHibernate Coreの問題のようですが、Cascadeが使えないとなるとちょっと実用できないのかもしれません。

しかし、Hibernate Coreの内部では、シーケンスオブジェクトをテーブルを使ってエミュレートする機能があります(org.hibernate.idとorg.hibernate.dialectパッケージ)。

コレと、Cascadeの機能をうまく結びつける方法はないのでしょうか。これからもう少し、Hibernate Coreを掘り下げてみたいと思います。


コメント

コメントしてください

closed.