歌舞伎座.tech 1 lt - scalikejdbc async & skinny framework #kbkz_tech
DESCRIPTION
ScalikeJDBC Async と Skinny Framework のご紹介です。TRANSCRIPT
非同期 JDBC in Scala@seratchKazuhiro Sera
Really?
え、ホントに?
JDBC?
JDBC はブロックするって聞いてたんだけど?
Exactly
ええ、その通りです。
ミ ヽヽヽリリノノノノ
彡ミイ ‾‾'`‾ヾミ 彡ミi ) ;|ミ
彡ミ〉 _,,,,,,,,, i,i ,,,,,_イミ JDBC と言ったな、
rミi _-・- l-・-、v
{6〈`┬ 、_」_ イ あれは嘘だ。
ヾ| ( ,-ー-、) |
\ `- ⌒-´ノ 、 ' ’
/i\ __ノ - ∩_____ ’
/\_ _ノ\ ( イ___ヨ - パッ (_Y ヽノ )イ⌒ニ ,ノ
( )____/ `ー-ー´
ー-',..-'ー.-,ー!..ー,,-._ー.,-ー.,-ー-...,,____
l | i i ''i,,_
JDBC っぽい non-blocking
な DB アクセス in Scala@seratchKazuhiro Sera
ScalikeJDBC - Scala の DB アクセスライブラリ- “仕事で使っても詰まない”
- SQL 書ける、柔軟性、拡張性、スピーディなバグ対応・リリース、日本語- Slick、Squeryl ほど有名じゃないけど、結構イケる感じです
DSL で書いた例 import scalikejdbc._, SQLInterpolation._ val memberId = 123 val member = DB readOnly { implicit session => withSQL { select.from(Member as m) .where.eq(m.id, memberId).and.isNull(m.deletedAt) }.map(Member(m)).single.apply() }
生 SQL も書けるよ
import scalikejdbc._, SQLInterpolation._ val memberId = 123 val member = DB readOnly { implicit session => sql”””select id, name from member where id = ${memberId} and deleted_at is null””” .map(Member(m)).single.apply() }
Get things done- わかりやすくて、ハマりにくい- 独自のノウハウを探しまわる必要なし- 1 人目のちゃんと使える人の確保が容易(Scala の基本と SQL のみ)- Cookbook(日本語)販売中
Productive- ほぼタイプセーフな API を提供- sbt プラグインでソースコード自動生成- スロークエリ、Fluentd にも送れる- specs2、ScalaTest それぞれに
AutoRollback サポート
Main subject
で、そろそろ本題。
ScalikeJDBC-Async- ScalikeJDBC の API 互換だけど内部は
JDBC じゃない- Activate という他のライブラリに触発されて実装した(2013/7)- 国内外でのいくつか利用事例を認識していますが、一応まだアルファバージョン
How?- postgresql-async/mysql-async by @mauricio をラップした- Netty ベースの独自ドライバ- queue を持った ConnectionPool
- Transaction は Connection を占有して実現(begin/commit 自前で発行)
ほぼそのまま!
import scalikejdbc._, SQLInterpolation._, async._ val memberId = 123 val member = AsyncDB withPool { implicit session => withSQL { select.from(Member as m) .where.eq(m.id, memberId).and.isNull(m.deletedAt) }.map(Member(m)).single.future() }
Tx は for 式で
val name = “Typesafe” val programmers = Seq(“Alice”, “Bob”, “Chris”) val resultFuture = AsyncDB localTx { implicit tx => for { company <- Company.create(name) employees <- company.hireAll(programmers) } yield () }
Tips
- Future[Option[_]] や Future[List[_]]
だらけになるので for 式で書くとよい- Play2 は Controller の Action に
Future のまま渡せるのでやりやすい
OMT?
LT なのに One more thing 的なアレ。
Really Must?確かに JDBC がブロックして困るアプリの開発もあるがそうじゃないものの方が多いというのが現実(リアル)では?
Most cases?- うちのアプリ、実際 Servlet + JDBC で十分さばけてる(知ってた)- Reactive? C10K? 何それおいしいの?- 実は普通の管理画面作りたいだけ- Java は得意だけど今更の Java 感
Rails? 実際、フロントエンドの合理的な選択。私自身 Java でできた API サーバと
Rails フロントエンドがメインのお仕事。でも、今日ここにいる皆さんはきっとできれば Scala がいいんですよね・・
Grails? SI 業界な事情があるところ以外は
「だったらもう Rails で(ry」と思うけどともあれ、今日ここにいる皆さんは
Groovy より Scala ですよね・・
Play2? Play2 は発展途上 & Reactive 指向。
見た目から Play1/Rails 的なものを期待してミスマッチになっていないか?
管理画面つくるの Play2 で本当に楽?
Skinny!なければつくるのが OSS ということで
Scala on Rails なフレームワークを作っています(2 週間前から)!
Scalatra + ScalikeJDBC + more...
http://git.io/skinny
ORM もあるよ case class Developer(id: Long, groupId: Opion[Long], group: Option[Group] = None, skills: Seq[Skill] = Nil) object Developer extends SkinnyCRUDMapper[Developer] { belongsTo[Group](Group, (d, g) => d.copy(group = g)).byDefault hasManyThrough[Skill](DeveloperSkill, Skill, (d, skills) => d.coply(skills = skills)) def extract ... }
Developer.findAll() Developer.findById(123) Developer.createWithAttributes(params.permit(“id”, “groupId”)) Developer.updateById(123).withAttributes(attrs) Developer.deleteById(123)
Thanks- 非同期 JDBC なんてなかったんやー- ScalikeJDBC のご紹介- ScalikeJDBC-Async のご紹介- Skinny Framework のご紹介