Slick入門
Upcoming SlideShare
Loading in...5
×
 

Slick入門

on

  • 841 views

 

Statistics

Views

Total Views
841
Views on SlideShare
799
Embed Views
42

Actions

Likes
5
Downloads
5
Comments
0

3 Embeds 42

https://twitter.com 24
http://www.slideee.com 14
http://s.deeeki.com 4

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Slick入門 Slick入門 Presentation Transcript

  • 1 Slick入門 Takako Shimamoto BizReach, Inc.
  • 2 アジェンダ • Scalaの代表的なORM • Slickの基本的なお話 – スキーマ定義 – クエリ • SQLを直接書く方法 – Plain SQL – その他の選択肢 • Play2 + Slickで使うには – 設定 – コネクションまわり • プロジェクトでの留意点
  • 3 Scalaで使えるORM • Slick(旧ScalaQuery) – タイプセーフなDSLや、SQLも記述可能 – 極力Scalaのコレクションと同じように扱えるよう設計され ている • Squeryl – SQLは使用せず、DSLでクエリを記述する – コンセプトは、できるだけシンプルに val query = from(table) (t => where(t.id === id) select(t))
  • 4 Scalaで使えるORM • Anorm – SQLを直接書くスタイル – 手動でORマッピングを行う • Scala ActiveRecord – Squerylをベースに、モデル定義やよく使う機能をRailsの ActiveRecordに似せている(CoC、DRY) SQL("select * from User") .as( int("id") ~ str("name") map { case id~name => Person(id, name) } *)
  • 5 他にも、Activate、ScalikeJDBC、SORM など・・・ 本日はTypesafe社お墨付きの Slickについてお話します
  • 6 Slickのきほん
  • 7 タイプセーフなクエリ • Slickは以下のように、クエリをタイプセーフに記述で きることが1つの特徴 • このクエリを書くためには、スキーマ定義が必要 val id = 1L val user: Option[UsersRow] = Users.filter(_.id is id.bind).firstOption select * from USERS x1 where x1.ID = ? SQLのイメージ
  • 8 スキーマ定義 • でも、手動で書くのは面倒ですよね // マッピングするケースクラス case class UserRow(id: Long, name: String) // テーブルのスキーマ定義 class User(tag: Tag) extends Table[UserRow](tag, "USER") { def * = (id, name) <> (UserRow.tupled, UserRow.unapply) val id: Column[Long] = column[Long]("ID", O.PrimaryKey) val name: Column[String] = column[String]("NAME") } // クエリに使用 lazy val User = new TableQuery(tag => new User(tag))
  • 9 実はジェネレータがあるんですよ
  • 10 コードジェネレータ • sbtのタスクとして実行 • 生成するファイル – Tables.scala • 生成されるもの – テーブル定義 – マッピングするケースクラス – TableQuery • クエリで使用 – 全テーブルのDDL – GetResult(ResultSetからケースクラスに変換) • Plain SQLで使用
  • 11 コードジェネレータ • ジェネレータはカスタマイズ可能 – SourceCodeGeneratorを拡張する形 – ドキュメントがないので拡張ポイントがわかりにくい – slick.model.codegenパッケージ配下を見るとよい • BizReachではカスタマイズして使っている – 基本的なCRUD機能 – シールドクラスとカラムのマッピング – 楽観的排他による更新機能
  • 12 これでクエリが書けます
  • 13 基本的なCRUD // 全件取得 val users: Seq[UserRow] = User.list // 登録 val res: Int = User insert UserRow(1, "なまえ") // 更新 val res: Int = User.filter(_.id is id.bind).update( UserRow(1, "なまえ変更")) // 削除 val res: Int = User.filter(_.id is id.bind).delete
  • 14 基本的なCRUD // 全件取得 val users: Seq[UserRow] = User.list // 登録 val res: Int = User insert UserRow(1, "なまえ") // 更新 val res: Int = User.filter(_.id is id.bind).update( UserRow(1, "なまえ変更")) // 削除 val res: Int = User.filter(_.id is id.bind).delete bindを呼ぶと バインド変数になる
  • 15 バインド変数になるbind • bindなし • bindあり val name = "ta'kako" User.filter(_.name is name).firstOption ・・・ from USER x1 where x1.NAME = 'ta''kako' SQLのイメージ User.filter(_.name is name.bind).firstOption ・・・ from USER x1 where x1.NAME = ? SQLのイメージ
  • 16 ケースクラスにマッピング • <>を使えば、mapで絞り込んだ項目を別のケースク ラスにマッピングできる // このケースクラスにマッピング case class Test(id: Long, name: String) val res: List[Test] = User.map { t => t.id -> t.name <> (Test.tupled, Test.unapply) }.list
  • 17 他にもいろいろ • ソート、グルーピング、ページング など • 内部結合、外部結合も可能 • slick-referenceをGitHubに公開中 https://github.com/bizreach/slick-reference
  • 18 タイプセーフなクエリで書けない ときは?
  • 19 Plain SQL • SQLを文字列リテラルで書く • 局所的に使うには便利 • ただ、複雑なSQLの代替として使うには厳しい – リファクタリングがやりにくい – 動的なSQLを組み立てるためには文字列処理が必要 sql"""SELECT ID + 1 FROM ISSUE_ID WHERE USER_NAME = $owner FOR UPDATE """.as[Int].firstOption
  • 20 その他の選択肢 • mirage-scala – Seasar2の2WaySQLの機能を単独のライブラリとして利 用できるようにしたもの – Slickと組み合わせて使用することも可能 val books: List[Book] = sqlManager.getResultList[Book]( Sql(""" SELECT BOOK_ID, BOOK_NAME, AUTHOR, PRICE FROM BOOK /*IF author!=null*/ WHERE AUTHOR = /*author*/'test' /*END*/ """), Map("author"->"Takako Shimamoto")) パラメータはMapではなくケース クラスで与えることも可能 条件分岐やパラメータをSQLのコメント で記述するのでコピペしてそのままDB に流して動作確認できる 外部ファイル化することも可能
  • 21 Play2でSlickを使うには
  • 22 play-slick • Play2でSlickを使う上で、面倒なことをいろいろやっ てくれるプラグイン – Play2の設定から自動的にSlickの Database.forDataSourceを呼び出してくれる – Slickのセッション管理を自動的にやってくれる • withSessionやwithTransactionを呼び出してくれる – Play2のリクエストとSlickのセッションの両方を持ち合わ せたDBSessionRequestが使える SlickがPlay2に組み込まれるのと同時に このプラグインも統合される予定
  • 23 何が変わるの? • コントローラでPlay2のActionの代わりに、play-slick のDBActionを使う • トランザクションを開始する場合は DBAction.transactionを使う def list = DBAction { implicit rs => // IDの昇順にすべてのユーザ情報を取得 val users = Users.sortBy(t => t.id).list // 一覧画面を表示 Ok(views.html.user.list(users)) }
  • 24 コネクションプール • Slickはコネクションプールの実装を持っていない • Play2と組み合わせて使うならBoneCP • ただし、有名なリーク問題が未だにある – https://bugs.launchpad.net/bonecp/+bug/999114 • 対処方法は – BoneCPのバージョンを固定 – maxConnectionAgeを0にする • 現在は、HikariCPをお試し中
  • 25 プロジェクトで使う上で注意 することは?
  • 26 留意事項 • アグレッシブな機能追加/削除 – Scala全体の傾向(Slickも例外ではない) – 特にメジャーアップにはマイグレーションが必要 – 常にキャッチアップして対応していく必要がある • マニュアルがあまり豊富でない – 本家サイトには書いてないが、できることが色々ある – 慣れるまでに多少の時間が必要 – 充実させようとしている動きはある – BizReachで公開しているリファレンスをぜひ活用を
  • 27 留意事項 • 結合は発行されるSQLに注意 – 単一テーブルなら、①fiterで絞り込む、②mapで取得項目 を決める、③listやfirstOptionで実行、という流れ – 結合は、メソッドチェーンとfor式で発行するSQLが異なる // select ・・・ from (select * from A) s1 inner join (select * from B) s2 on ・・・ A.innerJoin(B).on(・・・) // select ・・・ from A s1, B s2 where (s1.column = s2.column) and ・・ for { t1 <- A t2 <- B if ・・・ } yield ・・・
  • 28 留意事項 • Play2のEvolutionsは実践には厳しい – 1.sql、2.sql・・・の管理はプログラマがやる – ミスした場合、エボリューション用のテーブルを元に戻すと いう操作を手動でやらないといけない – ある程度の規模になるとメンテが困難
  • 29 Slickの今後
  • 30 次期バージョン2.1 • 使いやすさの向上 – APIの改善 – ドキュメントの充実 • Play2.4からデフォルトのO/Rマッパ(予定) • Direct Embedding – ケースクラスにアノテーションを付与 • スキーマ定義が不要になる – 暗黙の型変換の代わりに、マクロを使用 • 実装するコード量が減る – 現在は実験的な機能として提供 • 今後に期待