slick小白入門

slick 介紹

Slick(“Scala語言集成連接工具包”)是Lightbend用于Scala的功能關(guān)系映射(FRM)庫,可以輕松使用關(guān)系數(shù)據(jù)庫挥唠。它允許您使用存儲(chǔ)的數(shù)據(jù)撒踪,就像使用Scala集合一樣,同時(shí)讓您完全控制數(shù)據(jù)庫訪問何時(shí)發(fā)生以及傳輸哪些數(shù)據(jù)壳猜。您也可以直接使用SQL枚赡。數(shù)據(jù)庫操作的執(zhí)行是異步完成的氓癌,這使得Slick非常適合基于Play和Akka的被動(dòng)應(yīng)用程序。

Slick的新功能關(guān)系映射(FRM)范例允許在Scala中完成映射贫橙,具有松散耦合贪婉,最小配置要求以及許多其他主要優(yōu)勢,這些優(yōu)勢從連接關(guān)系數(shù)據(jù)庫中抽象出復(fù)雜性卢肃。

Slick沒有嘗試彌合對象模型和數(shù)據(jù)庫模型之間的差距疲迂,而是將數(shù)據(jù)庫模型引入Scala,因此開發(fā)人員不需要編寫SQL代碼莫湘。

Slick將數(shù)據(jù)庫直接集成到Scala中尤蒿,允許使用普通的Scala類和集合以與內(nèi)存數(shù)據(jù)相同的方式查詢和處理存儲(chǔ)和遠(yuǎn)程數(shù)據(jù)。

Slick用于函數(shù)式編程的FRM方法的一些主要優(yōu)點(diǎn)包括:
- 預(yù)優(yōu)化效率
FRM是一種更有效的連接方式; 與ORM不同幅垮,它能夠預(yù)先優(yōu)化與數(shù)據(jù)庫的通信 - 而使用FRM腰池,您可以開箱即用。使用FRM比使用ORM更快地制作應(yīng)用程序的道路要短得多忙芒。
- 沒有類型安全的繁瑣故障排除
FRM為構(gòu)建數(shù)據(jù)庫查詢帶來了類型安全性示弓。開發(fā)人員的工作效率更高,因?yàn)榫幾g器會(huì)自動(dòng)發(fā)現(xiàn)錯(cuò)誤呵萨,而不是在非類型化字符串中查找錯(cuò)誤所需的典型繁瑣故障排除避乏。
- 用于構(gòu)建查詢的更高效,可組合的模型
FRM支持用于構(gòu)建查詢的可組合模型甘桑。這是一個(gè)非常自然的模型,可以將各個(gè)部分組合在一起構(gòu)建查詢歹叮,然后在代碼庫中重用各個(gè)部分跑杭。

支持的數(shù)據(jù)庫

  • DB2
  • Derby / JavaDB
  • H2
  • HSQLDB (HyperSQL)
  • Microsoft SQL Server
  • MySQL
  • Oracle
  • PostgreSQL
  • SQLite

slick 如何通過代碼生成器生成實(shí)體類

Slick的代碼生成器附帶一個(gè)默認(rèn)運(yùn)行器,可以從命令行或Java / Scala中使用咆耿。你可以簡單地執(zhí)行

slick.codegen.SourceCodeGenerator.main(
  Array(profile, jdbcDriver, url, outputFolder, pkg, user, password)
)
  • uri:在類型安全配置中配置路徑的URL和/或片段德谅,例如 url#slick.db.default
  • profile:配置文件類的完全限定名稱,例如 slick.jdbc.H2Profile
  • jdbcDriver:JDBC驅(qū)動(dòng)程序類的完全限定名稱萨螺,例如 org.h2.Driver
  • url:JDBC url窄做,例如 jdbc:postgresql://localhost/test
  • outputFolder:應(yīng)放置包文件夾結(jié)構(gòu)的位置
  • pkg:Scala包生成的代碼應(yīng)該放在哪里
  • user:數(shù)據(jù)庫連接用戶名
  • password:數(shù)據(jù)庫連接密碼

slick 數(shù)據(jù)庫配置

  1. Using Typesafe Config
mydb = {
  dataSourceClass = "org.postgresql.ds.PGSimpleDataSource"
  properties = {
    databaseName = "mydb"
    user = "myuser"
    password = "secret"
  }
  numThreads = 10
}
val db = Database.forConfig("mydb")
  1. Using a JDBC URL
val db = Database.forURL("jdbc:h2:mem:test1;DB_CLOSE_DELAY=-1",
  driver="org.h2.Driver")
  1. Using a DataSource(常用)
val db = Database.forDataSource(dataSource: javax.sql.DataSource,
  Some(size: Int))
  1. Using a JNDI Name
val db = Database.forName(jndiName: String, Some(size: Int))

slick 常規(guī)操作

  1. SELECT *
sql"select * from PERSON".as[Person]
people.result
  1. SELECT
sql"""
  select AGE
  from PERSON
""".as[(Int,String)]
people.map(_.age).result
  1. WHERE
sql"select * from PERSON where AGE >= 18 AND NAME = 'C. Vogt'".as[Person]
people.filter(p => p.age >= 18 && p.name === "C. Vogt").result
  1. ORDER BY
sql"select * from PERSON order by AGE asc, NAME".as[Person]
people.sortBy(p => (p.age.asc, p.name)).result
  1. Aggregations
sql"select max(AGE) from PERSON".as[Option[Int]].head
people.map(_.age).max.result
  1. GROUP BY
sql"""
  select ADDRESS_ID, AVG(AGE)
  from PERSON
  group by ADDRESS_ID
""".as[(Int,Option[Int])]
people.groupBy(p => p.addressId)
       .map{ case (addressId, group) => (addressId, group.map(_.age).avg) }
       .result
  1. HAVING
sql"""
  select ADDRESS_ID
  from PERSON
  group by ADDRESS_ID
  having avg(AGE) > 50
""".as[Int]
people.groupBy(p => p.addressId)
       .map{ case (addressId, group) => (addressId, group.map(_.age).avg) }
       .filter{ case (addressId, avgAge) => avgAge > 50 }
       .map(_._1)
       .result
  1. Implicit inner joins
sql"""
  select P.NAME, A.CITY
  from PERSON P, ADDRESS A
  where P.ADDRESS_ID = a.id
""".as[(String,String)]
people.flatMap(p =>
  addresses.filter(a => p.addressId === a.id)
           .map(a => (p.name, a.city))
).result

// or equivalent for-expression:
(for(p <- people;
     a <- addresses if p.addressId === a.id
 ) yield (p.name, a.city)
).result
  1. Explicit inner joins
sql"""
  select P.NAME, A.CITY
  from PERSON P
  join ADDRESS A on P.ADDRESS_ID = a.id
""".as[(String,String)]
(people join addresses on (_.addressId === _.id))
  .map{ case (p, a) => (p.name, a.city) }.result
  1. Outer joins (left/right/full)
sql"""
  select P.NAME,A.CITY
  from ADDRESS A
  left join PERSON P on P.ADDRESS_ID = a.id
""".as[(Option[String],String)]
(addresses joinLeft people on (_.id === _.addressId))
  .map{ case (a, p) => (p.map(_.name), a.city) }.result
  1. Subquery
sql"""
  select *
  from PERSON P
  where P.ID in (select ID
                 from ADDRESS
                 where CITY = 'New York City')
""".as[Person]
val address_ids = addresses.filter(_.city === "New York City").map(_.id)
people.filter(_.id in address_ids).result // <- run as one query
  1. insert
sqlu"""
  insert into PERSON (NAME, AGE, ADDRESS_ID) values ('M Odersky', 12345, 1)
"""
people.map(p => (p.name, p.age, p.addressId)) += ("M Odersky",12345,1)
  1. update
sqlu"""
  update PERSON set NAME='M. Odersky', AGE=54321 where NAME='M Odersky'
"""
people.filter(_.name === "M Odersky")
       .map(p => (p.name,p.age))
       .update(("M. Odersky",54321))
  1. delete
sqlu"""
  delete PERSON where NAME='M. Odersky'
"""
people.filter(p => p.name === "M. Odersky")
       .delete
  1. CASE
sql"""
  select
    case
      when ADDRESS_ID = 1 then 'A'
      when ADDRESS_ID = 2 then 'B'
    end
  from PERSON P
""".as[Option[String]]
import slick.ast.ScalaBaseType.stringType
people.map(p =>
  Case
    If(p.addressId === 1) Then "A"
    If(p.addressId === 2) Then "B"
).result

slick 限制

  1. 缺少查詢運(yùn)算符(Slick在某種程度上是可擴(kuò)展的愧驱,這意味著您可以自己添加一些缺少的操作符)
  2. 非最佳SQL代碼(在某些情況下,生成的查詢比手動(dòng)編寫查詢更復(fù)雜椭盏。例如组砚,Slick偶爾會(huì)生成不必要的子查詢。在MySQL <= 5.5中掏颊,這很容易導(dǎo)致不必要的表掃描或索引未被使用)

slick 純sql查詢

普通SQL在查詢使用的是通過sql糟红,sqlu和 tsql插值
sqlu插用于其產(chǎn)生的行數(shù),而不是一個(gè)結(jié)果集的DML語句乌叶。因此它們屬于類型DBIO[Int]盆偿。

注入查詢的任何變量或表達(dá)式都會(huì)在生成的查詢字符串中變?yōu)榻壎ㄗ兞俊K粫?huì)直接插入查詢字符串准浴,因此不存在SQL注入攻擊的危險(xiǎn)事扭。

def insert(c: Coffee): DBIO[Int] =
  sqlu"insert into coffees values (${c.name}, ${c.supID}, ${c.price}, ${c.sales}, ${c.total})"

此方法生成的SQL語句始終相同:

insert into coffees values (?, ?, ?, ?, ?)

以下代碼使用sql內(nèi)插器返回由語句生成的結(jié)果集。插值器本身不產(chǎn)生DBIO值乐横。需要跟隨調(diào)用.as來定義行類型:

sql"""select c.name, s.name
      from coffees c, suppliers s
      where c.price < $price and s.id = c.sup_id""".as[(String, String)]

這導(dǎo)致了DBIO[Seq[(String, String)]]求橄。調(diào)用as采用隱式 GetResult參數(shù),該參數(shù)從結(jié)果集中提取所請求類型的數(shù)據(jù)晰奖。GetResult標(biāo)準(zhǔn)JDBC類型有預(yù)定義的含義谈撒,對于那些(表示可為空的列)的選項(xiàng)和有類型的類型的元組GetResult。對于非標(biāo)準(zhǔn)類型匾南,您必須定義自己的轉(zhuǎn)換器:

case class Coffee(name: String, supID: Int, price: Double, sales: Int, total: Int)

implicit val getCoffeeResult = GetResult(r => Coffee(r.<<, r.<<, r.<<, r.<<, r.<<))

使用快捷方法<<啃匿,該方法 返回在此處預(yù)期的任何類型的值。(當(dāng)然蛆楞,只有在這個(gè)構(gòu)造函數(shù)調(diào)用中實(shí)際知道類型時(shí)才能使用它溯乒。)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市豹爹,隨后出現(xiàn)的幾起案子裆悄,更是在濱河造成了極大的恐慌,老刑警劉巖臂聋,帶你破解...
    沈念sama閱讀 221,430評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件光稼,死亡現(xiàn)場離奇詭異,居然都是意外死亡孩等,警方通過查閱死者的電腦和手機(jī)艾君,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來肄方,“玉大人冰垄,你說我怎么就攤上這事∪ㄋ” “怎么了虹茶?”我有些...
    開封第一講書人閱讀 167,834評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵逝薪,是天一觀的道長。 經(jīng)常有香客問我蝴罪,道長董济,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,543評(píng)論 1 296
  • 正文 為了忘掉前任洲炊,我火速辦了婚禮感局,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘暂衡。我一直安慰自己询微,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評(píng)論 6 397
  • 文/花漫 我一把揭開白布狂巢。 她就那樣靜靜地躺著撑毛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪唧领。 梳的紋絲不亂的頭發(fā)上藻雌,一...
    開封第一講書人閱讀 52,196評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音斩个,去河邊找鬼胯杭。 笑死,一個(gè)胖子當(dāng)著我的面吹牛受啥,可吹牛的內(nèi)容都是我干的做个。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼滚局,長吁一口氣:“原來是場噩夢啊……” “哼居暖!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起藤肢,我...
    開封第一講書人閱讀 39,671評(píng)論 0 276
  • 序言:老撾萬榮一對情侶失蹤太闺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后嘁圈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體省骂,經(jīng)...
    沈念sama閱讀 46,221評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評(píng)論 3 340
  • 正文 我和宋清朗相戀三年最住,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了冀宴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,444評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡温学,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出甚疟,到底是詐尸還是另有隱情仗岖,我是刑警寧澤逃延,帶...
    沈念sama閱讀 36,134評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站轧拄,受9級(jí)特大地震影響揽祥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜檩电,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評(píng)論 3 333
  • 文/蒙蒙 一拄丰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧俐末,春花似錦料按、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至烹卒,卻和暖如春闷盔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背旅急。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評(píng)論 1 272
  • 我被黑心中介騙來泰國打工逢勾, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人藐吮。 一個(gè)月前我還...
    沈念sama閱讀 48,837評(píng)論 3 376
  • 正文 我出身青樓溺拱,卻偏偏與公主長得像,于是被迫代替她去往敵國和親炎码。 傳聞我的和親對象是個(gè)殘疾皇子盟迟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容