Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

ScalikeJDBC Tutorial for Beginners

6,387 views

Published on

ScalikeJDBC Tutorial for Beginners

http://git.io/scalikejdbc

Published in: Technology, Education

ScalikeJDBC Tutorial for Beginners

  1. 1. ScalikeJDBCTutorialfor Beginners@seratchKazuhiro Sera
  2. 2. Table of contentsWhat’s this?ConnectionPoolImplicit SessionSQL SyntaxQuery DSLMore FeaturesGet Started Now
  3. 3. What’s this?
  4. 4. ScalikeJDBChttp://git.io/scalikejdbcA tidy SQL-based DB access libraryfor Scala developers....SQL-based?
  5. 5. SQL-basedimport scalikejdbc._, SQLInterpolation._val id = 123// Anorm-like API for Scala 2.9val name = SQL(“select name from company where id = {id}”).bindByName(‘id -> id).map(rs => rs.string(“name”)).single.apply()// SQL Interpolation since 2.10val name = sql”select name from company where id = ${id}”.map(rs => rs.string(“name”)).single.apply()// Query DSLval name = withSQL {select(c.name).from(Company as c).where.eq(c.id, id)}.map(rs => rs.string(c.resultName.name)).single.apply()
  6. 6. Everybody knows SQLWe don’t need something new anddifferent from SQL.Maybe, you can write the code on theprevious slide immediately, right?Because you already know SQL.
  7. 7. ConnectionPool
  8. 8. Easy-to-use CPDB block such as DB.readOnly { ... }borrows a connection fromConnectionPool.Since ConnectionPool is a singletonobject, you can easily borrowanywhere.
  9. 9. ConnectionPoolimport scalikejdbc._Class.forName(“org.h2.Driver”)// default connection poolval (url, user, password) = (“jdbc:h2:mem:db”, “sa”, “”)ConnectionPool.singleton(url, user, password)val conn: java.sql.Connection = ConnectionPool.borrow()val names: List[String] = DB readOnly { implicit session =>sql”select name from company”.map(_.string(“name”).list.apply()}// named connection poolval poolSettings = new ConnectionPoolSettings(maxSize = 50)ConnectionPool.add(‘secondary, url, user, passsword, poolSettings)NamedDB(‘secondary) readOnly { implicit session =>
  10. 10. DBCP by defaultBy default, only Commons DBCPimplementation is provided.It’s also possible to implement yourpreferred connection pool.(e.g. C3P0, BoneCP)
  11. 11. Implicit Session
  12. 12. Go implicitlyDBSession representsjava.sql.Connectionwith a transaction(if exists).#apply() requires DBSessionimplicitly.
  13. 13. Implicit DBSessionimport scalikejdbc._, SQLInterpolation._val id = 123// DBSession usageval name: Option[String] = DB readOnly { session: DBSession =>session.single(“select name from company where id = ?”, id) { rs =>rs.string(“name”)}}// SQL API requires implicit DBSessionval name: Option[String] = DB readOnly { implicit session =>sql”select name from company where id = ${id}”.map(_.string(“name”)).single.apply()}
  14. 14. AutomaticAutoSession creates & closes an ad-hoc session if absent.query: read-only sessionupdate: auto-commit session
  15. 15. Flexible Transactionimport scalikejdbc._, SQLInterpolation._implicit val session = AutoSessionsql”select name from company”.map(_.string(“name”)).list.apply()def addCompany(name: String)(implicit s: DBSession = AutoSession) {sql”insert into company values (${name})”.update.apply()}def getAllNames()(implicit s: DBSession = AutoSession): List[String] = {sql”select name from company”.map(_.string(“name”)).list.apply()}val names: List[String] = getAllNames() // read-only sessionDB localTx { implicit session =>addCompany(“Typesafe”) // within a transactiongetAllNames() // within a transaction, includes “Typesafe”}
  16. 16. SQL Syntax
  17. 17. SQLSyntax?// SQLSyntax = a part of SQL object, will be embedded as-isval c: SQLSyntax = sqls”count(*)”val bobby: String = “Bob%”val query = sql”select ${c} from members where name like ${bobby}”// -> “select count(*) from members where name like ?”A part of SQL object which will beembedded as-is.
  18. 18. SQLSyntaxSupportSQLSyntaxSupport provides DRY andtype safe SQL.- CoC but configurable- Write complex join queries- Using type-dynamic(similar toRuby’s method-missing) but havecompile-time check with macro
  19. 19. CoC Rules// Scala objectcase class GroupMember(id: Long, fullName: Option[String] = None)obejct GroupMember extends SQLSyntaxSupport[GroupMember]// DDLcreate table group_member {id bigint not null primary key,full_name varchar(255)}Simply snake_case’d name
  20. 20. Customize it// Scala objectcase class GroupMember(id: Long, fullName: Option[String] = None)obejct GroupMember extends SQLSyntaxSupport[GroupMember] {override val tableName = “group_members”override val nameConverters = Map(“fullName” -> “fullname”)}// DDLcreate table group_members {id bigint not null primary key,fullname varchar(255)}
  21. 21. Query & Extractingimport scalikejdbc._, SQLInterpolation._// entity class (Plain Old Scala Object)case class Member(id: Long, fullName: Option[String] = None)// companion object for entityobejct Member extends SQLSyntaxSupport[Member] {def apply(m: ResultName[Member])(rs: WrappedResultSet) = new Member(id = rs.long(m.id), name = rs.stringOpt(m.fullName)))val m = Member.syntax(“m”)val id = 123val memebr: Option[Member] = DB readOnly { implicit s =>sql”select ${m.result.*} from ${Member as m} where ${m.id} = ${id}”.map(Member(m.resultName)).single.apply()}
  22. 22. result? resultName?val m = Member.syntax(“m”)m.fullName == “m.full_name”m.result.fullName == “m.full_name as fn_on_m”m.resultName.fullName == “fn_on_m”Scala:sql”select ${m.result.fullName} from ${Member as m} where ${m.id} = 123”SQL:“select m.full_name as fn_on_m from member m where m.id = 123”ResultSet extractor:val name = sql”...”.map(rs => rs.string(m.resultName.fullName)).single.apply()// extracting “fn_on_m” from ResultSet
  23. 23. Type safe dynamicimport scalikejdbc._, SQLInterpolation._val m = Member.syntax(“m”)val id = 123val memebr: Option[Member] = DB readOnly { implicit s =>sql”select ${m.result.fullNamee} from ${Member as m} where ${m.id} = ${id}”.map(Member(m.resultName)).single.apply()}<console>:28: error: Member#fullNamee not found. Expected fields are #id,#fullName, #createdAt, #deletedAt.m.fullNamee^
  24. 24. Query DSL
  25. 25. Uniqueness- DBSession inspired by Querulous- SQL(String) inspired by Anorm- sql”...” inspired by SlickQuery DSL is surelyScalikeJDBC’s originalway!
  26. 26. What’s Query DSL- Just appends SQL parts- Type safe and pragmatic- Easy to understand- Not composable but reusable- Parts from sqls object- Append sqls”...” when needed
  27. 27. Query DSL examplesimport scalikejdbc._, SQLInterpolation._implicit val session = AutoSessionval c = Company.syntax(“c”)val id = 123val company: Option[Company] = withSQL {select.from(Company as c).where.eq(c.id, id)}.map(Company(c.resultName)).single.apply()insert.into(Company).values(123, “Typesafe”)val column = Company.columnupdate(Company).set(column.name -> “Oracle”).where.eq(column.id, 123)delete.from(Company).where.eq(column.id, 123)
  28. 28. Joins, one-to-x APIval programmerWithSkills = withSQL {select.from(Programmer as p).leftJoin(Company as c).on(p.companyId, c.id).leftJoin(ProgrammerSkill as ps).on(ps.programmerId, p.id).leftJoin(Skill as s).(ps.skillId, s.id).where.eq(p.id, id).and.isNull(p.deletedAt)}.one(Programmer(p, c)).toMany(SKill.opt(s)).map { (pg, skills) => pg.copy(skills = skills) }.single.apply()
  29. 29. Sub query, Pagingval noSkillProgrammers = withSQL {select.from(Programmer as p).leftJoin(Company as c).on(p.companyId, c.id).where.notIn(p.id,select(sqls.distinct(ps.programmerId)).from(ProgrammerSkill as ps)).isNull(p.deletedAt).limit(10).offset(0).orderBy(p.id).desc}.map(Programmer(p, c)).list.apply()
  30. 30. sqls.xxx, sqls”...”val userId =val orderCount: Long = withSQL {select(sqls.count(sqls.distinct(o.id))) // sqls object.from(Order as o).innerJoin(Product as p).on(p.id,o.productId).where.append(sqls”${o.userId} = ${userId}”) // direct SQL embedding}.map(rs => rs.long(1)).single.apply().get
  31. 31. More and More- insert select- groupBy, having- in, exists, like, between- union, unionAll- withRoundBracket { ... }- dynamic(And|Or)Conditions { ... }In detail:QueryDSLFeature.scalaQueryInterfaceSpec.scala
  32. 32. More Features
  33. 33. Code Generator- sbt plugin- Code from existing tables- project/scalikejdbc.properties- Play2 style models and testsIn detail:Wiki Pagesbt “scalikejdbc-gen [table-name]”
  34. 34. Testing with ScalaTestimport scalikejdbc._, scalatest.AutoRollbackimport org.scalatest.fixture.FlatSpecclass MemberSpec extends FlatSpec with AutoRollback {override def fixture(implicit s: DBSession) {sql”delete from members”.update.apply()Member.create(1, “Alice”)}behavior of “Member”it should “create a new record” in { implicit s =>val beforeCount = Member.countMember.create(123, “Brian”)Member.count should equal(before + 1)}}
  35. 35. Testing with specs2 (1)import scalikejdbc._, specs2.mutable.AutoRollbackimport org.specs2.mutable.Specificationobject MemberSpec extends Specification {“Member should create a new record” in new MyAutoRollback {val beforeCount = Member.countMember.create(123, “Brian”)Member.count should equal(before + 1)}}trait MyAutoRollback extends AutoRollback {override def fixture(implicit s: DBSession) {sql”delete from members”.update.apply()Member.create(1, “Alice”)}}
  36. 36. Testing with specs2 (2)import scalikejdbc._, specs2.AutoRollbackimport org.specs2.Specificationobject MemberSpec extends Specification { def is =“Member should create a new record” ! autoRollback().createend}case class autoRollback() extends AutoRollback {override def fixture(implicit s: DBSession) {sql”delete from members”.update.apply()Member.create(1, “Alice”)}def create = this {val beforeCount = Member.countMember.create(123, “Brian”)Member.count should equal(before + 1)}}
  37. 37. Play2 Support- Integrates with Play2 seamlessly- Read conf/application.conf- Add plugin to conf/play.plugins- FixturePlugin is also available- Great contribution by @tototoshiIn detail:Wiki Page
  38. 38. Get Started Now
  39. 39. More infoExamplesdevteam-app exampleQueryInterfaceSpec.scalaReferenceWiki PagesUsers GroupScalikeJDBC Users GroupScalikeJDBC Users Group Japan
  40. 40. Enjoy!Just write SQLand get things done!git.io/scalikejdbc

×