Edited at

MysqlでScalikeJDBC入門


目的

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のプロジェクトを作っておきます。


全体の流れ


  1. mysqlのセットアップ

  2. テーブルの作成

  3. コード自動生成

  4. テスト実行 → こちらは別記事


mysqlの立ち上げ

ローカルのmysqlを立ち上げるか、以下のようにdocker-compose.ymlを用意してdocker上で立ち上げます。

dockerでの立ち上げはmacの場合Docker.Appが必要です。

Docker.Appは以下でインストールします。

$ brew cask install docker

docker-compose.ymlの例です。


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を管理するためのテーブルを作成します。

こちらのスクリプトを作ります。


init.sql

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 … テストコードの自動生成で使用


build.sbt

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ディレクトリ直下に入れる必要があります。


scalikejdbc-gen.sbt

libraryDependencies += "mysql" % "mysql-connector-java" % "5.1.29"

addSbtPlugin("org.scalikejdbc" %% "scalikejdbc-mapper-generator" % "3.3.+")



scalikejdbc.properties

# ---

# jdbc settings
jdbc.driver="com.mysql.cj.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に以下設定を書きます。


src/main/resources/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のデータにアクセスしてみます。


MysqlAccess.scala

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)
...

今回生成したテストはそのままでは通らないので、テストを通すよう書き換えます。(次回へ