Slick 2.0を使ってみる#1 セットアップ
Slick 2.0リリース
2014年1月に、Slickの2.0がリリースされました。 2.0ではRDB以外のサポートも強化され、DBスキーマのリバースエンジニアリング機能も可能になっています。
Slickとは
Slickとは、元々ScalaQueryと呼ばれていたもので、TypeSafe社の開発しているORMです。 Scalaのコレクションを使用するかのごとく、データストアの操作が可能です。 また、Playframework2.3(2014/Q1予定)からはAnormに代わりSlickが標準のDBライブラリとなる予定です。 参考:以前のSlick記事
環境構築
今回使用した動作環境は以下のとおりです。sbtはインストールしておきましょう。
- OS : MacOS X 10.9.1
- sbt : 0.13.1
プロジェクトのテンプレート作成のためgiter8を使用するので、Homebrewでインストールしておいてください。
% brew install giter8
今回Slick2.0で使用するためのRDBとして、MySQLを使用します。 そして適当なデータベースをcreate database文で作成しておいてください。
プロジェクトのセットアップ
giter8を使ってsbtプロジェクトのひな形を作成します。
% g8 pmandera/basic-scala-project
次に、build.sbtに依存ライブラリを追記します。MySQLのJDBCドライバ、slick、slf4jを追加しましょう。
・ ・ libraryDependencies ++= Seq( "org.specs2" %% "specs2" % "2.3.7" % "test", "mysql" % "mysql-connector-java" % "5.1.28", "com.typesafe.slick" %% "slick" % "2.0.0", "org.slf4j" % "slf4j-nop" % "1.6.4" ) ・ ・
src/main/scalaディレクトリにHelloWorld.scalaがあります。これを使ってもいいですし、自分でscalaファイルを追加してもかまいません。 Slickの動作確認をするための次のようなクラスを記述しましょう。
package com.example.slicksample import scala.slick.jdbc._ import scala.slick.driver.MySQLDriver.simple._ object Main extends App { Database.forURL("jdbc:mysql://localhost/<DB名>?user=<ユーザー名>&password=<パスワード>", driver = "com.mysql.jdbc.Driver") withSession { implicit session => //DBアクセスコードはここへ記述 } }
Database.forURLでユーザー名やパスワード、ドライバクラスを設定し、ブロック内でDBへアクセスするコードを記述します。 これは以前のSlickとほとんど変わりありません。(implicit部分が違うだけ) とりあえずここまでできたらsbtでrunコマンドを実行してみましょう。 とくに問題なく処理が終了すれば、準備完了です。
> run [success] Total time: 5 s, completed 2014/02/14 14:38:01
テーブルを作成する
DBに接続することができたので、今後利用するためのテーブルを用意しましょう。 SlickではTableクラスからDDLを実行することも可能です。 まずはMainオブジェクト内に、下記のようなTableクラスを用意します。
package com.example.slicksample import scala.slick.ast.BaseTypedType import scala.slick.jdbc._ import scala.slick.driver.MySQLDriver.simple._ import scala.slick.lifted.Tag import java.sql.Timestamp object Main extends App { class Book(tag: Tag) extends Table[(Int, String)](tag, "book") { def id = column[Int]("id", O.PrimaryKey) def title = column[String]("title") def * = (id, title) } class Sales(tag: Tag) extends Table[(Int, Int, Int, Option[Timestamp])](tag, "sales") { def id = column[Int]("id", O.PrimaryKey) def bookId = column[Int]("bookId") def num = column[Int]("num") def date = column[Option[Timestamp]]("date") def * = (id, bookId, num, date) def book = foreignKey("sales_ibfk_1", bookId, TableQuery[Book])(_.id) } val books = TableQuery[Book] val sales = TableQuery[Sales] ・ ・
BookとSalesがそれぞれMySQLの「book」「sales」テーブルと対応します。 Tableクラスの定義方法はSlick2.0で変更された部分です。 以前はTableクラスはobjectとして定義していましたが、2.0はclassとして定義します。 また、Tagクラスをコンストラクタ引数として受け取るように定義します。
ではDDLを実行しましょう。下記例では、一度book,salesテーブルを削除してから改めて作成しています。
Database.forURL("jdbc:mysql://localhost/<DB名>?user=<ユーザー名>&password=<パスワード>", driver = "com.mysql.jdbc.Driver") withSession { implicit session => try { (sales.ddl ++ books.ddl).drop } catch { case e:Exception => println("table not found") } (books.ddl ++ sales.ddl).create ・ ・
プログラムを実行したらmysqlのコマンドラインツールで確認してみましょう。 PKや外部キーも含めて、テーブルが作成されています。
% mysql -u<ユーザー名> -p mysql> use <DB名> mysql> show tables; +-----------------+ | Tables_in_mydb | +-----------------+ | book | | sales | +-----------------+ 3 rows in set (0.00 sec) mysql> desc book; +-------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | title | varchar(254) | NO | | NULL | | +-------+--------------+------+-----+---------+-------+ 2 rows in set (0.01 sec) mysql> desc sales; +--------+-----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+-----------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | bookId | int(11) | NO | MUL | NULL | | | num | int(11) | NO | | NULL | | | date | timestamp | YES | | NULL | | +--------+-----------+------+-----+---------+-------+ 4 rows in set (0.01 sec)
テーブルが作成できました。次回はテーブルに対していろいろと操作してみます。