Slick experiences and introduction

advertisement
What is Slick and
why we use it?
Mark van der Tol
Why we moved to SQL
MongoDB has
• No joins or referential integrity
• No transactions
• Max element size for index
Advantages PostgreSQL has
• Better indexes
• Better tooling
• Strict schema
2
Problem faced with MongoDB
Query unseen alerts for users
Data:
{
"message": "Example alert",
"seenBy": [...]
}
Query:
{
"seenBy": { "$ne": "user" }
}
Max element size for indexed elements: 1 KB
3
Trivial in SQL
SELECT message
FROM alerts
WHERE id NOT IN (
SELECT messageId
FROM views
WHERE user = "user"
)
4
MongoDB
• We keep using Mongo for statistics data
• Easier to shard/replicate
• No schema enforcement
5
What is Slick
• Database query library for Scala
• Table mapping
• Strongly typed
• Collection like syntax
6
Available for
•
•
•
•
•
•
•
•
•
•
DB2*
Derby/JavaDB
H2
HSQLDB/HyperSQL
Microsoft Access
Microsoft SQL Server
MySQL
Oracle*
PostgreSQL
SQLite
*Requires subscription for production use
7
Database connection
import scala.slick.driver.PostgresDriver.simple._
import Database.threadLocalSession
Database.forURL("jdbc:postgresql://…", driver =
"org.postgresql.Driver") withSession {
//session is now implicitly available in thread-local storage
}
Database.forURL("jdbc:postgresql://…", driver =
"org.postgresql.Driver") withTransaction {
//session is now implicitly available in thread-local storage
}
8
Table definition
object CoffeeTable
extends Table[(String, BigDecimal, Int)]("COFFEE") {
def name = column[String]("NAME", O.PrimaryKey)
def price = column[BigDecimal]("PRICE")
def sales = column[Int]("SALES")
def * = name ~ price ~ sales
}
9
Simple SELECT query
val minPrice: BigDecimal = 1.0
val query = for {
c <- CoffeeTable
if (c.price >= minPrice)
} yield (c.name)
val names = query.list
10
Table definition for Case class
case class Coffee
(name: String, price: BigDecimal, sales: Int)
object CoffeeTable
extends Table[Coffee]("coffee") {
def
def
def
def
}
name = column[String]("NAME", O.PrimaryKey)
price = column[BigDecimal]("PRICE")
sales = column[Int]("SALES")
* = name ~ price ~ sales <> (Coffee, Coffee.unapply _)
11
Simple SELECT query
val query = for {
c <- CoffeeTable
} yield (c)
val coffees = query.list
12
SELECT query with join
val query = for {
p <- PersonTable
c <- CoffeeTable
if (p.favoriteCoffee === c.name)
} yield (p.name, c.name, c.price)
13
INSERT query
CoffeeTable.insert(
Coffee("Java", 2.50, 0)
)
14
UPDATE/DELETE query
val query = for {
c <- CoffeeTable
if (c.price < 1.50)
} yield (c.price)
query.update(1.50)
query.delete
15
Plain SQL queries
val query = StaticQuery
.query[BigDecimal, (String, Int)](
"""select c.name, c.sales
from coffees c
where c.price < ?"""
)
16
Features not shown
• Queries with parameters
• Extensible: Add own types and functions
• "Direct embedding"
17
Features
•
•
•
•
Query library that stays close to SQL
Hides dbms specific syntax
Prevents SQL-injections
Many checks compile time
18
Disadvantages
•
•
•
•
DSL not always intuitive
Difficult compile errors
Focus on single thread usage
Not very comprehensive documentation
19
Multi-threaded use workaround
val session = Database.forURL("jdbc:…", driver =
“…").createSession()
session.conn.setAutoCommit(false)
//prevent Slick from creating transactions itself
session.asInstanceOf[BaseSession].inTransaction = true
…
session.conn.commit()
session.close()
20
Resources
• Slick:
http://slick.typesafe.com/
http://groups.google.com/group/scalaquery
• Sheets:
http://www.plotprojects.com/
21
THANK YOU
22
Download