鍍金池/ 教程/ Scala/ 直接使用 SQL 語句
概述
基本查詢
查詢(二)
查詢(三)
直接使用 SQL 語句
數(shù)據(jù)庫連接和事務(wù)處理
數(shù)據(jù)庫 Schema
查詢(一)
準(zhǔn)備開發(fā)環(huán)境

直接使用 SQL 語句

如果你有需要直接使用 SQL 語句,Slick 也支持你直接使用 SQL 語句。

首先你需要引入一些引用包:

import scala.slick.jdbc.{GetResult, StaticQuery => Q}
import scala.slick.jdbc.JdbcBackend.Database
import Q.interpolation

其中最重要的一個相關(guān)類似 StaticQuery,為簡潔起見,我們使用 Q 作為它的別名。連接數(shù)據(jù)庫還是和以前一樣 Slick 編程(4): 數(shù)據(jù)庫連接和事務(wù)處理

DDL 和 DML 語句

StaticQuery 的方法 updateNA,(NA 代表無參數(shù)),它返回 DDL 指令影響的行數(shù),比如使用 H2 數(shù)據(jù)庫

連接數(shù)據(jù)庫:

case class Supplier(id:Int, name:String, street:String, city:String, state:String, zip:String)
case class Coffee(name:String, supID:Int, price:Double, sales:Int, total:Int)

Database.forURL("jdbc:h2:mem:test1", driver = "org.h2.Driver") withDynSession {

}

創(chuàng)建數(shù)據(jù)庫表:

// Create the tables, including primary and foreign keys
Q.updateNA("create table suppliers("+
  "id int not null primary key, "+
  "name varchar not null, "+
  "street varchar not null, "+
  "city varchar not null, "+
  "state varchar not null, "+
  "zip varchar not null)").execute
Q.updateNA("create table coffees("+
  "name varchar not null, "+
  "sup_id int not null, "+
  "price double not null, "+
  "sales int not null, "+
  "total int not null, "+
  "foreign key(sup_id) references suppliers(id))").execute

你可以使用字符串和一個 StaticQuery 對象相加(+)構(gòu)成一個新的 StaticQuery 對象,一個簡單的方法是使用 Q.u 和一個字符串相加,Q.u 代表一個相當(dāng)與 StaticQuery.updateNA(“”)

例如我們在表中插入一些數(shù)據(jù):

// Insert some suppliers
(Q.u + "insert into suppliers values(101, 'Acme, Inc.', '99 Market Street', 'Groundsville', 'CA', '95199')").execute
(Q.u + "insert into suppliers values(49, 'Superior Coffee', '1 Party Place', 'Mendocino', 'CA', '95460')").execute
(Q.u + "insert into suppliers values(150, 'The High Ground', '100 Coffee Lane', 'Meadows', 'CA', '93966')").execute

在 SQL 查詢語句中使用字面量不是一種推薦的方法,尤其是當(dāng)用戶提供數(shù)據(jù)時(不十分安全), 此時你可以使用 +? 操作符為查詢語句綁定一個參數(shù),比如:

def insert(c: Coffee) = (Q.u + "insert into coffees values (" +? c.name +
  "," +? c.supID + "," +? c.price + "," +? c.sales + "," +? c.total + ")").execute

// Insert some coffees
Seq(
  Coffee("Colombian", 101, 7.99, 0, 0),
  Coffee("French_Roast", 49, 8.99, 0, 0),
  Coffee("Espresso", 150, 9.99, 0, 0),
  Coffee("Colombian_Decaf", 101, 8.99, 0, 0),
  Coffee("French_Roast_Decaf", 49, 9.99, 0, 0)
).foreach(insert)

這段代碼相對于 insert into coffees values (?,?,?,?,?)

查詢語句

和 updateNA 類似, StaticQuery 還有一個 queryNA 方法,它支持一個類型參數(shù)(代表表的一行),比如:

Q.queryNA[AlbumRow]("select * from Album") foreach { a => 
    println(" " + a.albumid + " " + a.title + " " + a.artistid)
}

這段代碼之所以能工作,是因?yàn)?Tables.scala 中定義了

/** GetResult implicit for fetching AlbumRow objects using plain SQL queries */
implicit def GetResultAlbumRow(implicit e0: GR[Int], e1: GR[String]): GR[AlbumRow] = GR{
    prs => import prs._
    AlbumRow.tupled((<<[Int], <<[String], <<[Int]))
}

定義了從 JDBC 類型到 GetResult[T] 的隱含轉(zhuǎn)換,GetResult[T] 為函數(shù) PositionedResult => T 的一個封裝。<<[T] 返回指定位置上期望的值。

和 queryNA 對應(yīng)的帶參數(shù)的 query 定義了兩個類型參數(shù),一個是參數(shù)的類型,另外一個是返回的結(jié)果的每行的類型,例如:

val q2 = Q.query[Int,(Int,String,Int)] ( """
 select albumid,title,artistid from Album where artistid < ?
""")
val l2 = q2.list(10)
for(t <- l2) println( " " + t._1 + " " + t._2 + " " + t._3)

返回結(jié)果如下:

1 For Those About To Rock We Salute You 1
4 Let There Be Rock 1
2 Balls to the Wall 2
3 Restless and Wild 2
5 Big Ones 3
6 Jagged Little Pill 4
7 Facelift 5
8 Warner 25 Anos 6
34 Chill: Brazil (Disc 2) 6
9 Plays Metallica By Four Cellos 7
10 Audioslave 8
11 Out Of Exile 8
271 Revelations 8
12 BackBeat Soundtrack 9

Q.interpolation 支持字符串插值,比如:

def albumByTitle(title: String) = sql"select * from Album where title = $title".as[AlbumRow]
println("Album: " + albumByTitle("Let There Be Rock").firstOption)

使用 sql 做為前綴的字符串,可以將以 $ 開始的變量替換成該變量的值,此外對于 update/delete 語句,可以使用 sqlu 前綴。

上一篇:查詢(一)