目的
scalikejdbcをMysqlで動かしてみます。これからscalikejdbcを始める方向けです。
解説したコード全体はこちら: umeneri/scalikejdbc-example: example for scalikejdbc
参考
環境
- intellij community edition 2018.1
- scalaVersion 2.12.7
- sbt.version 1.2.6
- scalikejdbc 3.3.2
前準備
新規or既存のscalaプロジェクトを立ち上げておきます。
intelljの場合、File > New.. > Projectから、sbtのプロジェクトを作っておきます。
全体の流れ
- mysqlのセットアップ
- テーブルの作成
- コード自動生成
- テスト実行 → こちらは別記事
mysqlの立ち上げ
ローカルのmysqlを立ち上げるか、以下のようにdocker-compose.ymlを用意してdocker上で立ち上げます。
dockerでの立ち上げはmacの場合Docker.Appが必要です。
Docker.Appは以下でインストールします。
$ brew cask install docker
docker-compose.ymlの例です。
version: "3"
services:
example-mysql:
container_name: example
image: "mysql:5.6"
ports:
- "4306:3306"
environment:
MYSQL_ALLOW_EMPTY_PASSWORD: 1
MYSQL_DATABASE: "example"
上記docker-composeで立ち上げれば「example」という名前のdatabaseが作成されています。
作成されていない場合は、mysqlにログインして以下で作成です。
create database example;
テーブルの作成
例としてmemberを管理するためのテーブルを作成します。
こちらのスクリプトを作ります。
DROP TABLE IF EXISTS member;
CREATE TABLE member
(
id BIGINT NOT NULL AUTO_INCREMENT,
name VARCHAR(256) NOT NULL,
description VARCHAR(1000),
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL,
PRIMARY KEY (id)
) ENGINE = 'InnoDB', DEFAULT CHARSET=utf8mb4, ROW_FORMAT=DYNAMIC;
insert into member values (1, 'Alice', '', current_timestamp, current_timestamp);
insert into member values (2, 'Bob', '', current_timestamp, current_timestamp);
memberテーブルを作成します。
$ mysql -h 127.0.0.1 -uroot -P 4306 example < init.sql
build.sbtの設定
build.sbtへ以下を追加。
- scalikejdbc … 本体
- scalikejdbc-test … コードの自動生成でテストも生成するため
- scalikejdbc-config … application.confにscalikejdbc設定を書くため
- logback-classic … あまり詳しく調べてないのですが、ログ出力に使用
- mysql-connector-java … mysqlとの連携に必要
- scalatest … テストコードの自動生成で使用
libraryDependencies ++= Seq(
"org.scalikejdbc" %% "scalikejdbc" % "3.3.+",
"org.scalikejdbc" %% "scalikejdbc-test" % "3.3.+" % "test",
"org.scalikejdbc" %% "scalikejdbc-config" % "3.3.+",
"ch.qos.logback" % "logback-classic" % "1.2.3",
"mysql" % "mysql-connector-java" % "5.1.29",
"org.scalatest" %% "scalatest" % "3.0.5" % "test"
)
コードの自動生成
コード自動生成機能を使うため、以下をbuild.sbtへ追加。
enablePlugins(ScalikejdbcPlugin)
自動生成には、以下2つのファイルをprojectディレクトリ直下に入れる必要があります。
libraryDependencies += "mysql" % "mysql-connector-java" % "5.1.29"
addSbtPlugin("org.scalikejdbc" %% "scalikejdbc-mapper-generator" % "3.3.+")
# ---
# jdbc settings
jdbc.driver="com.mysql.jdbc.Driver"
jdbc.url="jdbc:mysql://127.0.0.1:4306/example"
jdbc.username=root
jdbc.password=
jdbc.schema=
# ---
# source code generator settings
generator.packageName=models
# generator.lineBreak: LF/CRLF
generator.lineBreak=LF
# generator.template: interpolation/queryDsl
generator.template=queryDsl
# generator.testTemplate: specs2unit/specs2acceptance/ScalaTestFlatSpec
generator.testTemplate=ScalaTestFlatSpec
generator.encoding=UTF-8
# When you're using Scala 2.11 or higher, you can use case classes for 22+ columns tables
generator.caseClassOnly=true
# Set AutoSession for implicit DBSession parameter's default value
generator.defaultAutoSession=true
# Use autoConstruct macro (default: false)
generator.autoConstruct=false
# joda-time (org.joda.time.DateTime) or JSR-310 (java.time.ZonedDateTime java.time.OffsetDateTime)
generator.dateTimeClass=java.time.ZonedDateTime
上記ファイルはjdbcのアクセス先URL等を記述します。デフォルトでのアクセス先をexampleとしています。
自動生成実行
それでは自動生成します。
$ sbt "scalikejdbcGenAll"
コマンド実行後、エラーが無ければ以下2ファイルが生成されています。
- src/main/scala/models/Member.scala
- src/test/scala/models/MemberSpec.scala
jdbc設定
アプリケーションコードでscalikejdbcを使用するため、application.confに以下設定を書きます。
# JDBC settings
db.default.driver="com.mysql.jdbc.Driver"
db.default.url="jdbc:mysql://127.0.0.1:4306/example"
db.default.user="root"
db.default.password=""
# Connection Pool settings
db.default.poolInitialSize=10
db.default.poolMaxSize=20
db.default.connectionTimeoutMillis=1000
# Connection Pool settings
db.default.poolInitialSize=5
db.default.poolMaxSize=7
db.default.poolConnectionTimeoutMillis=1000
db.default.poolValidationQuery="select 1 as one"
db.default.poolFactoryName="commons-dbcp2"
試しにMemberのデータにアクセスしてみます。
package scalike
import models.Member
import scalikejdbc.config._
object MysqlAccess extends App {
DBs.setupAll()
val maybeFound = Member.find(1L)
val name = maybeFound.get.name
println(name) // => Alice
}
実行すると、実際のDBへのクエリもログに流れるのでデバッグしやすいですね。
[SQL Execution]
select m.id as i_on_m, m.name as n_on_m, m.description as d_on_m, m.created_at as ca_on_m, m.updated_at as ua_on_m from member m where m.id = 1; (8 ms)
[Stack Trace]
...
models.Member$.find(Member.scala:42)
scalike.mysqlAccess$.delayedEndpoint$scalike$mysqlAccess$1(MysqlAccess.scala:10)
scalike.mysqlAccess$delayedInit$body.apply(MysqlAccess.scala:7)
scala.Function0.apply$mcV$sp(Function0.scala:39)
scala.Function0.apply$mcV$sp$(Function0.scala:39)
scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:17)
scala.App.$anonfun$main$1$adapted(App.scala:80)
scala.collection.immutable.List.foreach(List.scala:392)
scala.App.main(App.scala:80)
scala.App.main$(App.scala:78)
scalike.mysqlAccess$.main(MysqlAccess.scala:7)
scalike.mysqlAccess.main(MysqlAccess.scala)
...
今回生成したテストはそのままでは通らないので、テストを通すよう書き換えます。(次回へ)