您的位置:首页 > 数据库

Scala数据库编程

2015-11-07 11:42 459 查看
主要内容

Scala Maven工程的创建
Scala JDBC方式访问MySQL
Slick简介
Slick数据库编程实战
SQL与Slick相互转换

本课程在多数内容是在官方教程上修改而来的,官方给的例子是H2数据库上的,经过本人改造,用在MySQL数据库上,官方教程地址:http://slick.typesafe.com/doc/2.1.0/sql-to-slick.html

1. Scala Maven工程的创建

本节的工程项目采用的是Maven Project,在POM.xml文件中添加下面两个依赖就可以使用scala进行JDBC方式及Slick框架操作MySQL数据库:

<code class="hljs xml has-numbering"> <span class="hljs-tag"><<span class="hljs-title">dependency</span>></span>
<span class="hljs-tag"><<span class="hljs-title">groupId</span>></span>mysql<span class="hljs-tag"></<span class="hljs-title">groupId</span>></span>
<span class="hljs-tag"><<span class="hljs-title">artifactId</span>></span>mysql-connector-java<span class="hljs-tag"></<span class="hljs-title">artifactId</span>></span>
<span class="hljs-tag"><<span class="hljs-title">version</span>></span>5.1.18<span class="hljs-tag"></<span class="hljs-title">version</span>></span>
<span class="hljs-tag"></<span class="hljs-title">dependency</span>></span>
<span class="hljs-tag"><<span class="hljs-title">dependency</span>></span>
<span class="hljs-tag"><<span class="hljs-title">groupId</span>></span>com.typesafe.slick<span class="hljs-tag"></<span class="hljs-title">groupId</span>></span>
<span class="hljs-tag"><<span class="hljs-title">artifactId</span>></span>slick_2.11<span class="hljs-tag"></<span class="hljs-title">artifactId</span>></span>
<span class="hljs-tag"><<span class="hljs-title">version</span>></span>2.1.0<span class="hljs-tag"></<span class="hljs-title">version</span>></span>
<span class="hljs-tag"></<span class="hljs-title">dependency</span>></span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li></ul>

scala IDE for eclipse 中创建scala Maven项目的方式如下:

在Eclispe 中点击” File->new->other”,如下图



输入Maven可以看到Maven Project:



直接next,得到



再点击next,在filter中输入scala得到:



选中,然后next输入相应的groupId等,直接finish即可。创建完项目将上述依赖添加到pom.xml文件当中,这样就完成了scala maven Project的创建。

2. Scala JDBC方式访问MySQL

下面给出的是scala采用JDBC访问MySQL的代码示例

<code class="hljs scala has-numbering"><span class="hljs-keyword">package</span> cn.scala.xtwy.jdbc

<span class="hljs-keyword">import</span> java.sql.{ Connection, DriverManager }
<span class="hljs-class"><span class="hljs-keyword">object</span> <span class="hljs-title">ScalaJdbcConnectSelect</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">App</span> {</span>
<span class="hljs-comment">// 访问本地MySQL服务器,通过3306端口访问mysql数据库</span>
<span class="hljs-keyword">val</span> url = <span class="hljs-string">"jdbc:mysql://localhost:3306/mysql"</span>
<span class="hljs-comment">//驱动名称</span>
<span class="hljs-keyword">val</span> driver = <span class="hljs-string">"com.mysql.jdbc.Driver"</span>
<span class="hljs-comment">//用户名</span>
<span class="hljs-keyword">val</span> username = <span class="hljs-string">"root"</span>
<span class="hljs-comment">//密码</span>
<span class="hljs-keyword">val</span> password = <span class="hljs-string">"123"</span>
<span class="hljs-comment">//初始化数据连接</span>
<span class="hljs-keyword">var</span> connection: Connection = _
<span class="hljs-keyword">try</span> {
<span class="hljs-comment">//注册Driver</span>
Class.forName(driver)
<span class="hljs-comment">//得到连接</span>
connection = DriverManager.getConnection(url, username, password)
<span class="hljs-keyword">val</span> statement = connection.createStatement
<span class="hljs-comment">//执行查询语句,并返回结果</span>
<span class="hljs-keyword">val</span> rs = statement.executeQuery(<span class="hljs-string">"SELECT host, user FROM user"</span>)
<span class="hljs-comment">//打印返回结果</span>
<span class="hljs-keyword">while</span> (rs.next) {
<span class="hljs-keyword">val</span> host = rs.getString(<span class="hljs-string">"host"</span>)
<span class="hljs-keyword">val</span> user = rs.getString(<span class="hljs-string">"user"</span>)
println(<span class="hljs-string">"host = %s, user = %s"</span>.format(host, user))
}
} <span class="hljs-keyword">catch</span> {
<span class="hljs-keyword">case</span> e: Exception => e.printStackTrace
}
<span class="hljs-comment">//关闭连接,释放资源</span>
connection.close
}</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li></ul>

3. Slick简介

在前一小节中我们演示了如何通过JDBC进行数据库访问,同样在Scala中也可以利用JAVA中的ORM框架如Hibernate、IBatis等进行数据库的操纵,但它们都是Java风格的数据库操纵方式,Scala语言中也有着自己的ORM框架,目前比较流行的框架包括:

<code class="hljs lasso has-numbering"><span class="hljs-number">1</span>、Slick (typesafe公司开发)

<span class="hljs-number">2</span>、Squeryl

<span class="hljs-number">3</span>、Anorm

<span class="hljs-number">4</span>、ScalaActiveRecord (基于Squeryl之上)

<span class="hljs-number">5</span>、circumflex<span class="hljs-attribute">-orm</span>

<span class="hljs-number">6</span>、activate<span class="hljs-attribute">-framework</span>(Scala版的Hibernate)</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li></ul>

本节课程要讲的便是Slick框架,它是Scala语言创建者所成立的公司TypeSafe所开发的一个Scala风格的开源数据库操纵框架,它目前支持下面几种主流的数据:

<code class="hljs lasso has-numbering">DB2 (via slick<span class="hljs-attribute">-extensions</span>)
Derby/JavaDB
H2
HSQLDB/HyperSQL
Microsoft Access
Microsoft SQL Server (via slick<span class="hljs-attribute">-extensions</span>)
MySQL
Oracle (via slick<span class="hljs-attribute">-extensions</span>)
PostgreSQL
SQLite</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li></ul>

当然它也支持其它数据,只不过功能可能还不完善。在Slick中,可以像访问Scala自身的集合一样对数据库进行操作,它具有如下几个特点:

1 数据库的访问采用Scala风格:

<code class="hljs markdown has-numbering">//下面给出的是数据查询操作
class Coffees(tag: Tag) extends Table[<span class="hljs-link_label">(String, Double)</span>](<span class="hljs-link_url">tag, "COFFEES"</span>) {
def name = column[<span class="hljs-link_label">String</span>](<span class="hljs-link_url">"COF_NAME", O.PrimaryKey</span>)
def price = column[<span class="hljs-link_label">Double</span>](<span class="hljs-link_url">"PRICE"</span>)
def * = (name, price)
}
val coffees = TableQuery[Coffees]

//下面给出的数据访问API
// Query that only returns the "name" column
coffees.map(_.name)

// Query that does a "where price <span class="xml"><span class="hljs-tag">< <span class="hljs-attribute">10.0</span>"
<span class="hljs-attribute">coffees.filter</span>(<span class="hljs-attribute">_.price</span> < <span class="hljs-attribute">10.0</span>)
</span></span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li></ul>

从上面的代码可以看到,Slick访问数据库就跟Scala操纵自身的集合一样.

2 Slick数据操纵是类型安全的

<code class="hljs vhdl has-numbering">// The result <span class="hljs-keyword">of</span> <span class="hljs-string">"select PRICE from COFFEES"</span> <span class="hljs-keyword">is</span> a Seq <span class="hljs-keyword">of</span> Double
// because <span class="hljs-keyword">of</span> the <span class="hljs-keyword">type</span> safe column definitions
val coffeeNames: Seq[Double] = coffees.<span class="hljs-keyword">map</span>(_.price).list

// Query builders are <span class="hljs-keyword">type</span> safe:
coffees.filter(_.price < <span class="hljs-number">10.0</span>)
// Using a <span class="hljs-typename">string</span> <span class="hljs-keyword">in</span> the filter would result <span class="hljs-keyword">in</span> a compilation error</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li></ul>

3 支持链式操作

<code class="hljs sql has-numbering">// <span class="hljs-operator"><span class="hljs-keyword">Create</span> a query <span class="hljs-keyword">for</span> coffee <span class="hljs-keyword">names</span> <span class="hljs-keyword">with</span> a price less than <span class="hljs-number">10</span>, sorted <span class="hljs-keyword">by</span> name
coffees.filter(_.price < <span class="hljs-number">10.0</span>).sortBy(_.name).map(_.name)
// The generated <span class="hljs-keyword">SQL</span> <span class="hljs-keyword">is</span> equivalent <span class="hljs-keyword">to</span>:
// <span class="hljs-keyword">select</span> name <span class="hljs-keyword">from</span> COFFEES <span class="hljs-keyword">where</span> PRICE < <span class="hljs-number">10.0</span> <span class="hljs-keyword">order</span> <span class="hljs-keyword">by</span> NAME</span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul>

4. Slick 数据库编程实战

下面的代码演示了Slick如何创建数据库表、如何进行数据插入操作及如何进行数据的查询操作(以MySQL为例):

<code class="hljs scala has-numbering"><span class="hljs-keyword">package</span> cn.scala.xtwy

<span class="hljs-comment">//导入MySQL相关方法</span>
<span class="hljs-keyword">import</span> scala.slick.driver.MySQLDriver.simple._

<span class="hljs-class"><span class="hljs-keyword">object</span> <span class="hljs-title">UseInvoker</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">App</span> {</span>

<span class="hljs-comment">// 定义一个Test表</span>
<span class="hljs-comment">//表中包含两列,分别是id,name</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Test</span><span class="hljs-params">(tag: Tag)</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Table</span>[<span class="hljs-params">(Int, String)</span>]<span class="hljs-params">(tag, <span class="hljs-string">"Test"</span>)</span> {</span>
<span class="hljs-keyword">def</span> k = column[Int](<span class="hljs-string">"id"</span>, O.PrimaryKey)
<span class="hljs-keyword">def</span> v = column[String](<span class="hljs-string">"name"</span>)
<span class="hljs-comment">// Every table needs a * projection with the same type as the table's type parameter</span>
<span class="hljs-comment">//每个Table中都应该有*方法,它的类型必须与前面定义的类型参数(Int, String)一致</span>
<span class="hljs-keyword">def</span> * = (k, v)
}
<span class="hljs-comment">//创建TableQuery对象(这里调用的是TableQuery的apply方法</span>
<span class="hljs-comment">//没有显式地调用new </span>
<span class="hljs-keyword">val</span> ts = TableQuery[Test]

<span class="hljs-comment">//forURL注册MySQL驱动器,传入URL,用户名及密码</span>
<span class="hljs-comment">//方法回返的是一个DatabaseDef对象,然后再调用withSession方法</span>
Database.forURL(<span class="hljs-string">"jdbc:mysql://localhost:3306/slick"</span>, <span class="hljs-string">"root"</span>,<span class="hljs-string">"123"</span>,
driver = <span class="hljs-string">"com.mysql.jdbc.Driver"</span>) withSession {

<span class="hljs-comment">//定义一个隐式值</span>
<span class="hljs-comment">//implicit session: MySQLDriverbackend.Session</span>
<span class="hljs-comment">//后续方法中当做隐式参数传递</span>
implicit session =>

<span class="hljs-comment">// 创建Test表</span>
<span class="hljs-comment">//create方法中带有一个隐式参数</span>
<span class="hljs-comment">//def create(implicit session: JdbcBackend.SessionDef): Unit</span>
ts.ddl.create
<span class="hljs-comment">//插入数据</span>
<span class="hljs-comment">//def insertAll(values: U*)(implicit session: JdbcBackend.SessionDef): MultiInsertResult</span>
ts.insertAll(<span class="hljs-number">1</span> -> <span class="hljs-string">"a"</span>, <span class="hljs-number">2</span> -> <span class="hljs-string">"b"</span>, <span class="hljs-number">3</span> -> <span class="hljs-string">"c"</span>, <span class="hljs-number">4</span> -> <span class="hljs-string">"d"</span>, <span class="hljs-number">5</span> -> <span class="hljs-string">"e"</span>)
<span class="hljs-comment">//数据库查询(这里返回所有数据)</span>
ts.foreach { x => println(<span class="hljs-string">"k="</span>+x._1+<span class="hljs-string">" v="</span>+x._2) }

<span class="hljs-comment">//这里查询返回所有主鍵 <3的</span>
ts.filter { _.k <<span class="hljs-number">3</span> }.foreach { x => println(<span class="hljs-string">"k="</span>+x._1+<span class="hljs-string">" v="</span>+x._2) }
}
<span class="hljs-comment">//模式匹配方式</span>
ts.foreach { <span class="hljs-keyword">case</span>(id,name) => println(<span class="hljs-string">"id="</span>+id+<span class="hljs-string">" name="</span>+name) }
}</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li></ul>

下面我们再给一个更为复杂的例子来演示Slick中是如何进行数据的入库与查询操作的:

<code class="hljs scala has-numbering"><span class="hljs-keyword">package</span> cn.scala.xtwy

<span class="hljs-keyword">import</span> scala.slick.driver.MySQLDriver.simple._

<span class="hljs-class"><span class="hljs-keyword">object</span> <span class="hljs-title">CoffeeExample</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">App</span> {</span>
<span class="hljs-comment">// Definition of the SUPPLIERS table</span>
<span class="hljs-comment">//定义Suppliers表</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Suppliers</span><span class="hljs-params">(tag: Tag)</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Table</span>[<span class="hljs-params">(Int, String, String, String, String, String)</span>]<span class="hljs-params">(tag, <span class="hljs-string">"SUPPLIERS"</span>)</span> {</span>
<span class="hljs-keyword">def</span> id = column[Int](<span class="hljs-string">"SUP_ID"</span>, O.PrimaryKey) <span class="hljs-comment">// This is the primary key column</span>
<span class="hljs-keyword">def</span> name = column[String](<span class="hljs-string">"SUP_NAME"</span>)
<span class="hljs-keyword">def</span> street = column[String](<span class="hljs-string">"STREET"</span>)
<span class="hljs-keyword">def</span> city = column[String](<span class="hljs-string">"CITY"</span>)
<span class="hljs-keyword">def</span> state = column[String](<span class="hljs-string">"STATE"</span>)
<span class="hljs-keyword">def</span> zip = column[String](<span class="hljs-string">"ZIP"</span>)
<span class="hljs-comment">// Every table needs a * projection with the same type as the table's type parameter</span>
<span class="hljs-keyword">def</span> * = (id, name, street, city, state, zip)
}
<span class="hljs-keyword">val</span> suppliers = TableQuery[Suppliers]

<span class="hljs-comment">// Definition of the COFFEES table</span>
<span class="hljs-comment">//定义Coffees表</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Coffees</span><span class="hljs-params">(tag: Tag)</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Table</span>[<span class="hljs-params">(String, Int, Double, Int, Int)</span>]<span class="hljs-params">(tag, <span class="hljs-string">"COFFEES"</span>)</span> {</span>
<span class="hljs-keyword">def</span> name = column[String](<span class="hljs-string">"COF_NAME"</span>, O.PrimaryKey)
<span class="hljs-keyword">def</span> supID = column[Int](<span class="hljs-string">"SUP_ID"</span>)
<span class="hljs-keyword">def</span> price = column[Double](<span class="hljs-string">"PRICE"</span>)
<span class="hljs-keyword">def</span> sales = column[Int](<span class="hljs-string">"SALES"</span>)
<span class="hljs-keyword">def</span> total = column[Int](<span class="hljs-string">"TOTAL"</span>)
<span class="hljs-keyword">def</span> * = (name, supID, price, sales, total)
<span class="hljs-comment">// A reified foreign key relation that </span>
<span class="hljs-comment">//can be navigated to create a join</span>
<span class="hljs-comment">//外鍵定义,它使得supID域中的值关联到suppliers中的id</span>
<span class="hljs-comment">//从而保证表中数据的正确性</span>
<span class="hljs-comment">//它定义的其实是一个n:1的关系,</span>
<span class="hljs-comment">//即一个Coffees对应只有一个Suppliers,</span>
<span class="hljs-comment">//而一个Suppliers可以对应多个Coffees</span>
<span class="hljs-keyword">def</span> supplier = foreignKey(<span class="hljs-string">"SUP_FK"</span>, supID, suppliers)(_.id)
}
<span class="hljs-keyword">val</span> coffees = TableQuery[Coffees]

Database.forURL(<span class="hljs-string">"jdbc:mysql://localhost:3306/slick"</span>, <span class="hljs-string">"root"</span>, <span class="hljs-string">"123"</span>,
driver = <span class="hljs-string">"com.mysql.jdbc.Driver"</span>) withSession {

implicit session =>
<span class="hljs-comment">// Create the tables, including primary and foreign keys</span>
<span class="hljs-comment">//按顺序创建表</span>
(suppliers.ddl ++ coffees.ddl).create

<span class="hljs-comment">// Insert some suppliers</span>
<span class="hljs-comment">//插入操作,集合的方式</span>
suppliers += (<span class="hljs-number">101</span>, <span class="hljs-string">"Acme, Inc."</span>, <span class="hljs-string">"99 Market Street"</span>, <span class="hljs-string">"Groundsville"</span>, <span class="hljs-string">"CA"</span>, <span class="hljs-string">"95199"</span>)
suppliers += (<span class="hljs-number">49</span>, <span class="hljs-string">"Superior Coffee"</span>, <span class="hljs-string">"1 Party Place"</span>, <span class="hljs-string">"Mendocino"</span>, <span class="hljs-string">"CA"</span>, <span class="hljs-string">"95460"</span>)
suppliers += (<span class="hljs-number">150</span>, <span class="hljs-string">"The High Ground"</span>, <span class="hljs-string">"100 Coffee Lane"</span>, <span class="hljs-string">"Meadows"</span>, <span class="hljs-string">"CA"</span>, <span class="hljs-string">"93966"</span>)

<span class="hljs-comment">// Insert some coffees (using JDBC's batch insert feature, if supported by the DB)</span>
<span class="hljs-comment">//批量插入操作,集合方式</span>
coffees ++= Seq(
(<span class="hljs-string">"Colombian"</span>, <span class="hljs-number">101</span>, <span class="hljs-number">7.99</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>),
(<span class="hljs-string">"French_Roast"</span>, <span class="hljs-number">49</span>, <span class="hljs-number">8.99</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>),
(<span class="hljs-string">"Espresso"</span>, <span class="hljs-number">150</span>, <span class="hljs-number">9.99</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>),
(<span class="hljs-string">"Colombian_Decaf"</span>, <span class="hljs-number">101</span>, <span class="hljs-number">8.99</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>),
(<span class="hljs-string">"French_Roast_Decaf"</span>, <span class="hljs-number">49</span>, <span class="hljs-number">9.99</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>))
<span class="hljs-comment">//返回表中所有数据,相当于SELECT * FROM COFFEES</span>
coffees foreach {
<span class="hljs-keyword">case</span> (name, supID, price, sales, total) =>
println(<span class="hljs-string">"  "</span> + name + <span class="hljs-string">"\t"</span> + supID + <span class="hljs-string">"\t"</span> + price + <span class="hljs-string">"\t"</span> + sales + <span class="hljs-string">"\t"</span> + total)

}
<span class="hljs-comment">//返回表中所有数据,只不过这次是直接让数据库帮我们进行转换</span>
<span class="hljs-keyword">val</span> q1 = <span class="hljs-keyword">for</span> (c <- coffees)
<span class="hljs-keyword">yield</span> LiteralColumn(<span class="hljs-string">"  "</span>) ++ c.name ++ <span class="hljs-string">"\t"</span> ++ c.supID.asColumnOf[String] ++
<span class="hljs-string">"\t"</span> ++ c.price.asColumnOf[String] ++ <span class="hljs-string">"\t"</span> ++ c.sales.asColumnOf[String] ++
<span class="hljs-string">"\t"</span> ++ c.total.asColumnOf[String]
<span class="hljs-comment">// The first string constant needs to be lifted manually to a LiteralColumn</span>
<span class="hljs-comment">// so that the proper ++ operator is found</span>
q1 foreach println

<span class="hljs-comment">//联合查询</span>
<span class="hljs-comment">//采用===进行比较操作,而非==操作符,用于进行值比较</span>
<span class="hljs-comment">//同样的还有!=值不等比较符</span>
<span class="hljs-comment">//甚至其它比较操作符与scala是一致的 <, <=, >=, ></span>
<span class="hljs-keyword">val</span> q2 = <span class="hljs-keyword">for</span> {
c <- coffees <span class="hljs-keyword">if</span> c.price < <span class="hljs-number">9.0</span>
s <- suppliers <span class="hljs-keyword">if</span> s.id === c.supID
} <span class="hljs-keyword">yield</span> (c.name, s.name)

}
</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li><li>68</li><li>69</li><li>70</li><li>71</li><li>72</li><li>73</li><li>74</li><li>75</li><li>76</li><li>77</li><li>78</li><li>79</li><li>80</li><li>81</li><li>82</li><li>83</li><li>84</li><li>85</li><li>86</li><li>87</li></ul>

5. SQL与Slick相互转换

<code class="hljs scala has-numbering"><span class="hljs-keyword">package</span> cn.scala.xtwy

<span class="hljs-keyword">import</span> scala.slick.driver.MySQLDriver.simple._
<span class="hljs-keyword">import</span> scala.slick.jdbc.StaticQuery.interpolation
<span class="hljs-keyword">import</span> scala.slick.jdbc.GetResult

<span class="hljs-class"><span class="hljs-keyword">object</span> <span class="hljs-title">SQLAndSlick</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">App</span> {</span>
<span class="hljs-keyword">type</span> Person = (Int, String, Int, Int)
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">People</span><span class="hljs-params">(tag: Tag)</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Table</span>[<span class="hljs-title">Person</span>]<span class="hljs-params">(tag, <span class="hljs-string">"PERSON"</span>)</span> {</span>
<span class="hljs-keyword">def</span> id = column[Int](<span class="hljs-string">"ID"</span>, O.PrimaryKey)
<span class="hljs-keyword">def</span> name = column[String](<span class="hljs-string">"NAME"</span>)
<span class="hljs-keyword">def</span> age = column[Int](<span class="hljs-string">"AGE"</span>)
<span class="hljs-keyword">def</span> addressId = column[Int](<span class="hljs-string">"ADDRESS_ID"</span>)
<span class="hljs-keyword">def</span> * = (id, name, age, addressId)
<span class="hljs-keyword">def</span> address = foreignKey(<span class="hljs-string">"ADDRESS"</span>, addressId, addresses)(_.id)
}
<span class="hljs-keyword">lazy</span> <span class="hljs-keyword">val</span> people = TableQuery[People]

<span class="hljs-keyword">type</span> Address = (Int, String, String)
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Addresses</span><span class="hljs-params">(tag: Tag)</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Table</span>[<span class="hljs-title">Address</span>]<span class="hljs-params">(tag, <span class="hljs-string">"ADDRESS"</span>)</span> {</span>
<span class="hljs-keyword">def</span> id = column[Int](<span class="hljs-string">"ID"</span>, O.PrimaryKey)
<span class="hljs-keyword">def</span> street = column[String](<span class="hljs-string">"STREET"</span>)
<span class="hljs-keyword">def</span> city = column[String](<span class="hljs-string">"CITY"</span>)
<span class="hljs-keyword">def</span> * = (id, street, city)
}

<span class="hljs-keyword">lazy</span> <span class="hljs-keyword">val</span> addresses = TableQuery[Addresses]

<span class="hljs-keyword">val</span> dbUrl = <span class="hljs-string">"jdbc:mysql://localhost:3306/slick"</span>
<span class="hljs-keyword">val</span> jdbcDriver = <span class="hljs-string">"com.mysql.jdbc.Driver"</span>
<span class="hljs-keyword">val</span> user = <span class="hljs-string">"root"</span>
<span class="hljs-keyword">val</span> password = <span class="hljs-string">"123"</span>
<span class="hljs-keyword">val</span> db = Database.forURL(dbUrl, user, password, driver = jdbcDriver)

db.withSession { implicit session =>

(people.ddl ++ addresses.ddl).create

<span class="hljs-comment">//插入address数据</span>
addresses += (<span class="hljs-number">23</span>, <span class="hljs-string">"文一西路"</span>, <span class="hljs-string">"浙江省杭州市"</span>)
addresses += (<span class="hljs-number">41</span>, <span class="hljs-string">"紫荆花路"</span>, <span class="hljs-string">"浙江省杭州市"</span>)

<span class="hljs-comment">//插入people数据</span>
people += (<span class="hljs-number">1</span>, <span class="hljs-string">"摇摆少年梦"</span>, <span class="hljs-number">27</span>, <span class="hljs-number">23</span>)
people += (<span class="hljs-number">2</span>, <span class="hljs-string">"john"</span>, <span class="hljs-number">28</span>, <span class="hljs-number">41</span>)
people += (<span class="hljs-number">3</span>, <span class="hljs-string">"stephen"</span>, <span class="hljs-number">28</span>, <span class="hljs-number">23</span>)

<span class="hljs-comment">//下面两条语句是等同的(获取固定几个字段)</span>
<span class="hljs-keyword">val</span> query = sql<span class="hljs-string">"select ID, NAME, AGE from PERSON"</span>.as[(Int, String, Int)]
query.list.foreach(x => println(<span class="hljs-string">"id="</span> + x._1 + <span class="hljs-string">" name="</span> + x._2 + <span class="hljs-string">" age="</span> + x._3))

<span class="hljs-keyword">val</span> query2 = people.map(p => (p.id, p.name, p.age))
query2.list.foreach(x => println(<span class="hljs-string">"id="</span> + x._1 + <span class="hljs-string">" name="</span> + x._2 + <span class="hljs-string">" age="</span> + x._3))

<span class="hljs-comment">//下面两条语句是等同的(Where语句)</span>
<span class="hljs-keyword">val</span> query3 = sql<span class="hljs-string">"select * from PERSON where AGE >= 18 AND NAME = '摇摆少年梦'"</span>.as[Person]
query3.list.foreach(x => println(<span class="hljs-string">"id="</span> + x._1 + <span class="hljs-string">" name="</span> + x._2 + <span class="hljs-string">" age="</span> + x._3))

<span class="hljs-keyword">val</span> query4 = people.filter(p => p.age >= <span class="hljs-number">18</span> && p.name === <span class="hljs-string">"摇摆少年梦"</span>)
query4.list.foreach(x => println(<span class="hljs-string">"id="</span> + x._1 + <span class="hljs-string">" name="</span> + x._2 + <span class="hljs-string">" age="</span> + x._3))

<span class="hljs-comment">//orderBy</span>
sql<span class="hljs-string">"select * from PERSON order by AGE asc, NAME"</span>.as[Person].list
people.sortBy(p => (p.age.asc, p.name)).list

<span class="hljs-comment">//max</span>
sql<span class="hljs-string">"select max(AGE) from PERSON"</span>.as[Option[Int]].first
people.map(_.age).max

<span class="hljs-comment">//隐式join</span>
sql<span class="hljs-string">"""
select P.NAME, A.CITY
from PERSON P, ADDRESS A
where P.ADDRESS_ID = a.id
"""</span>.as[(String, String)].list

people.flatMap(p =>
addresses.filter(a => p.addressId === a.id)
.map(a => (p.name, a.city))).run

<span class="hljs-comment">// or equivalent for-expression:</span>
(<span class="hljs-keyword">for</span> (
p <- people;
a <- addresses <span class="hljs-keyword">if</span> p.addressId === a.id
) <span class="hljs-keyword">yield</span> (p.name, a.city)).run

<span class="hljs-comment">//join操作</span>
sql<span class="hljs-string">"""select P.NAME, A.CITY from PERSON P join ADDRESS A on P.ADDRESS_ID = a.id """</span>.as[(String, String)].list
(people join addresses on (_.addressId === _.id))
.map{ <span class="hljs-keyword">case</span> (p, a) => (p.name, a.city) }.run
}

}</code>

上面列出的只是Slick与SQL的部分转换,还有诸如:Update、Delete等操作可以参见:http://slick.typesafe.com/doc/2.1.0/sql-to-slick.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: