淺談Slick(2)- Slick101:第一個動手嘗試的項目


   看完Slick官方網站上關於Slick3.1.1技術文檔后決定開始動手建一個項目來嘗試一下Slick功能的具體使用方法。我把這個過程中的一些了解和想法記錄下來和大家一起分享。首先我用IntelliJ-Idea創建了一個scala項目。下一步就是如何選擇數據庫了。Slick是集成jdbc的更高層的Query編程語言,可以通過jdbc的url、DataSource等來指定目標數據庫類型及相關的參數。對應Slick中的具體函數有:

val db = Database.forConfig("mydb") val db = Database.forURL("jdbc:h2:mem:test1;DB_CLOSE_DELAY=-1", driver="org.h2.Driver") val db = Database.forDataSource(dataSource: slick.jdbc.DatabaseUrlDataSource)

在Slick的Database配置方面forConfig("confItem")是比較靈活、方便實用的。confItem是resources/application.conf文件里的一個配置項目。Slick是通過typesafe-config來解析配置文件的。forConfig函數用typesafe-config庫里的函數載入application.conf文件解析confItem並獲取項目里的數據庫配置參數,下面是項目中resources/application.conf文件內容:

h2mem { url = "jdbc:h2:mem:slickdemo" driver = "org.h2.Driver" connectionPool = disabled keepAliveConnection = true } h2 = { url = "jdbc:h2:~/slickdemo;mv_store=false;MODE=MSSQLServer;DB_CLOSE_DELAY=-1;AUTO_SERVER=TRUE" driver = org.h2.Driver connectionPool = disabled keepAliveConnection = true } mysql { driver = "slick.driver.MySQLDriver$" db { url = "jdbc:mysql://localhost/slickdemo" driver = com.mysql.jdbc.Driver keepAliveConnection = true user="root" password="123" numThreads=10 maxConnections = 12 minConnections = 4 } } mysqldb = { dataSourceClass = "com.mysql.jdbc.jdbc2.optional.MysqlDataSource" properties { user = "root" password = "123" databaseName = "slickdemo" serverName = "localhost" } numThreads = 10 maxConnections = 12 minConnections = 4 } postgres { driver = "slick.driver.PostgresDriver$" db { url = "jdbc:postgresql://127.0.0.1/slickdemo" driver = "org.postgresql.Driver" connectionPool = HikariCP user = "slick" password = "123" numThreads = 10 maxConnections = 12 minConnections = 4 } } postgressdb = { dataSourceClass = "org.postgresql.ds.PGSimpleDataSource" properties = { databaseName = "slickdemo" user = "slick" password = "123" } connectionPool = HikariCP numThreads = 10 maxConnections = 12 minConnections = 4 } mssql { driver = "com.typesafe.slick.driver.ms.SQLServerDriver$" db { url = "jdbc:sqlserver://host:port" driver = com.microsoft.sqlserver.jdbc.SQLServerDriver connectionTimeout = 30 second connectionPool = HikariCP user = "slick" password = "123" numThreads = 10 maxConnections = 12 minConnections = 4 keepAliveConnection = true } } tsql { driver = "slick.driver.H2Driver$" db = ${h2mem} }

在我使用的application.conf文件中匯集了一些常用數據庫的配置,我一並提供出來。除h2之外其它都沒進行測試驗證,具體配置參數和方法要參考數據庫開發商提供的技術文檔。我在這個示范里選用了h2配置:它會在我的用戶根目錄下創建一個slickdemo.h2.db數據庫文件。
好了,選擇了數據庫,下面我們就來試試使用它。基本流程是這樣的:首先在數據庫里創建表,跟着寫入一些數據,然后再讀出顯示。整個過程會涉及:表結構schema定義,數據插寫Insert,數據讀取Query及簡單的Query運算方法和數據顯示方法。

現在我們先設計表結構schema:

 1 package com.datatech.learn.slick101  2 import slick.driver.H2Driver.api._  3 object slick101 {  4 
 5 /* ----- schema */
 6   //表字段對應模版
 7   case class AlbumModel (id: Long  8  ,title: String  9  ,year: Option[Int] 10  ,artist: String 11  ) 12   //表結構: 定義字段類型, * 代表結果集字段
13   class AlbumTable(tag: Tag) extends Table[AlbumModel](tag, "ALBUMS") { 14     def id = column[Long]("ID",O.AutoInc,O.PrimaryKey) 15     def title = column[String]("TITLE") 16     def year = column[Option[Int]]("YEAR") 17     def artist = column[String]("ARTIST",O.Default("Unknown")) 18     def * = (id,title,year,artist) <> (AlbumModel.tupled, AlbumModel.unapply) 19  } 20   //庫表實例
21   val albums = TableQuery[AlbumTable]

在這個示范里我們確定使用H2數據庫,所以需要import H2Driver.api。使用了case class AlbumModel作為庫表字段對應模版。這樣一是可以規范代碼,再就是如果遇到一個寬表有很多列的話可以節省許多重復鋪墊及避免無謂錯誤。

現在需要從庫表實例albums產生它的schema,然后轉換成一個DBIOAction:

  //創建表動作
 val createTableAction = albums.schema.create

這個createTableAction就是個DBIOAction:一個效果描述。我們必須用具體的實現方式Database.run來運算產生實際效果:

1   //數據庫實例化
2 val db = Database.forConfig("h2") 3 def main(args: Array[String]): Unit = { 4    val res = db.run(createTableAction).andThen { 5        case Success(_) => println("table ALBUMS created.") 6        case Failure(e) => println(e.getMessage) 7  } 8    Await.result(res, 10 seconds) 9 }

db.run返回Future類型。我們是用Future類型的andThen組件來顯示運算結果的:

table ALBUMS created. Process finished with exit code 0

如果跟着再運算一次應該會產生重復重建錯誤:

Exception in thread "main" org.h2.jdbc.JdbcSQLException: Table "ALBUMS" already exists; SQL statement: Table "ALBUMS" already exists; SQL statement: ...

下面是一個插入數據的動作:

1 //插入數據動作
2   val insertAlbumsAction =
3   albums ++= Seq(
4     AlbumModel(0, "Keyboard Cat", Some(2003), "Keyboard Cat's Greatest Hits"),
5     AlbumModel(0, "Spice Girls", Some(2010), "Spice"),
6     AlbumModel(0, "Rick Astley", Some(1998), "Whenever You Need Somebody"),
7     AlbumModel(0, "Manowar", None,"The Triumph of Steel"),
8     AlbumModel(0, "Justin Bieber", Some(2011),"Believe"))

運算及顯示結果:

 1    val res2 = db.run(insertAlbumsAction).andThen {
 2       case Success(_) => println("albums inserted.")
 3       case Failure(e) => println(e.getMessage)
 4     }
 5     Await.result(res2, 10 seconds)
 6 ---
 7 table ALBUMS created.
 8 albums inserted.
 9 
10 Process finished with exit code 0

下面是抽取動作和數據顯示函數。我們把新插入的數據再讀出來驗證插入情況:

//數據抽取動作
  val selectAlbumsAction =
  albums.result
def printResults[T](fut: Future[Iterable[T]]): Unit
= Await.result(fut, Duration.Inf).foreach(println) val res3 = db.run(selectAlbumsAction) printResults(res3)

運算結果:

AlbumModel(1,Keyboard Cat,Some(2003),Keyboard Cat's Greatest Hits)
AlbumModel(2,Spice Girls,Some(2010),Spice)
AlbumModel(3,Rick Astley,Some(1998),Whenever You Need Somebody)
AlbumModel(4,Manowar,None,The Triumph of Steel)
AlbumModel(5,Justin Bieber,Some(2011),Believe)

Process finished with exit code 0

下面是完整的示范代碼:

 1 package com.datatech.learn.slick101
 2 import scala.concurrent.ExecutionContext.Implicits.global
 3 import scala.concurrent.duration._
 4 import scala.concurrent.{Await, Future}
 5 import scala.util.{Success,Failure}
 6 
 7 import slick.driver.H2Driver.api._
 8 object slick101 {
 9 
10   /* ----- schema  */
11   //表字段對應模版
12   case class AlbumModel(id: Long
13                         , artist: String
14                         , year: Option[Int]
15                         , title: String
16                        )
17 
18   //表結構: 定義字段類型, * 代表結果集字段
19   class AlbumTable(tag: Tag) extends Table[AlbumModel](tag, "ALBUMS") {
20     def id = column[Long]("ID", O.AutoInc, O.PrimaryKey)
21 
22     def title = column[String]("TITLE")
23 
24     def year = column[Option[Int]]("YEAR")
25 
26     def artist = column[String]("ARTIST", O.Default("Unknown"))
27 
28     def * = (id, artist, year, title) <> (AlbumModel.tupled, AlbumModel.unapply)
29   }
30 
31   //庫表實例
32   val albums = TableQuery[AlbumTable]
33 
34   //創建表動作
35   val createTableAction = albums.schema.create
36 
37   //數據庫實例化
38   val db = Database.forConfig("h2")
39 
40   //插入數據動作
41   val insertAlbumsAction =
42   albums ++= Seq(
43     AlbumModel(0, "Keyboard Cat", Some(2003), "Keyboard Cat's Greatest Hits"),
44     AlbumModel(0, "Spice Girls", Some(2010), "Spice"),
45     AlbumModel(0, "Rick Astley", Some(1998), "Whenever You Need Somebody"),
46     AlbumModel(0, "Manowar", None,"The Triumph of Steel"),
47     AlbumModel(0, "Justin Bieber", Some(2011),"Believe"))
48 
49   //數據抽取動作
50   val selectAlbumsAction =
51   albums.result
52 
53   def printResults[T](fut: Future[Iterable[T]]): Unit =
54     Await.result(fut, Duration.Inf).foreach(println)
55 
56   def main(args: Array[String]): Unit = {
57 
58      val res = db.run(createTableAction).andThen {
59        case Success(_) => println("table ALBUMS created.")
60        case Failure(e) => println(e.getMessage)
61      }
62      Await.result(res, 10 seconds)
63 
64     val res2 = db.run(insertAlbumsAction).andThen {
65       case Success(_) => println("albums inserted.")
66       case Failure(e) => println(e.getMessage)
67     }
68     Await.result(res2, 10 seconds) 
69 
70     val res3 = db.run(selectAlbumsAction)
71     printResults(res3)
72   }
73 }

 

 

 

 

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM