本节主要内容

  1. Scala Mavenproject的创建
  2. Scala JDBC方式訪问MySQL
  3. Slick简单介绍
  4. Slick数据库编程实战
  5. SQL与Slick相互转换

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

1. Scala Mavenproject的创建

本节的project项目採用的是Maven Project,在POM.xml文件里加入以下两个依赖就能够使用scala进行JDBC方式及Slick框架操作MySQL数据库:

 <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.18</version>
</dependency>
<dependency>
<groupId>com.typesafe.slick</groupId>
<artifactId>slick_2.11</artifactId>
<version>2.1.0</version>
</dependency>

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的代码演示样例

package cn.scala.xtwy.jdbc

import java.sql.{ Connection, DriverManager }
object ScalaJdbcConnectSelect extends App {
// 訪问本地MySQLserver,通过3306端口訪问mysql数据库
val url = "jdbc:mysql://localhost:3306/mysql"
//驱动名称
val driver = "com.mysql.jdbc.Driver"
//用户名
val username = "root"
//密码
val password = "123"
//初始化数据连接
var connection: Connection = _
try {
//注冊Driver
Class.forName(driver)
//得到连接
connection = DriverManager.getConnection(url, username, password)
val statement = connection.createStatement
//运行查询语句,并返回结果
val rs = statement.executeQuery("SELECT host, user FROM user")
//打印返回结果
while (rs.next) {
val host = rs.getString("host")
val user = rs.getString("user")
println("host = %s, user = %s".format(host, user))
}
} catch {
case e: Exception => e.printStackTrace
}
//关闭连接。释放资源
connection.close
}

3. Slick简单介绍

在前一小节中我们演示了怎样通过JDBC进行数据库訪问。相同在Scala中也能够利用JAVA中的ORM框架如Hibernate、IBatis等进行数据库的操纵,但它们都是Java风格的数据库操纵方式,Scala语言中也有着自己的ORM框架。眼下比較流行的框架包括:

1、Slick (typesafe公司开发)

2、Squeryl

3、Anorm

4、ScalaActiveRecord (基于Squeryl之上)

5、circumflex-orm

6、activate-framework(Scala版的Hibernate)

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

DB2 (via slick-extensions)
Derby/JavaDB
H2
HSQLDB/HyperSQL
Microsoft Access
Microsoft SQL Server (via slick-extensions)
MySQL
Oracle (via slick-extensions)
PostgreSQL
SQLite

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

1 数据库的訪问採用Scala风格:

//以下给出的是数据查询操作
class Coffees(tag: Tag) extends Table[(String, Double)](tag, "COFFEES") {
def name = column[String]("COF_NAME", O.PrimaryKey)
def price = column[Double]("PRICE")
def * = (name, price)
}
val coffees = TableQuery[Coffees] //以下给出的数据訪问API
// Query that only returns the "name" column
coffees.map(_.name) // Query that does a "where price < 10.0"
coffees.filter(_.price < 10.0)

从上面的代码能够看到。Slick訪问数据库就跟Scala操纵自身的集合一样.

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

// The result of "select PRICE from COFFEES" is a Seq of Double
// because of the type safe column definitions
val coffeeNames: Seq[Double] = coffees.map(_.price).list // Query builders are type safe:
coffees.filter(_.price < 10.0)
// Using a string in the filter would result in a compilation error

3 支持链式操作

// Create a query for coffee names with a price less than 10, sorted by name
coffees.filter(_.price < 10.0).sortBy(_.name).map(_.name)
// The generated SQL is equivalent to:
// select name from COFFEES where PRICE < 10.0 order by NAME

4. Slick 数据库编程实战

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

package cn.scala.xtwy

//导入MySQL相关方法
import scala.slick.driver.MySQLDriver.simple._ object UseInvoker extends App { // 定义一个Test表
//表中包括两列,各自是id,name
class Test(tag: Tag) extends Table[(Int, String)](tag, "Test") {
def k = column[Int]("id", O.PrimaryKey)
def v = column[String]("name")
// Every table needs a * projection with the same type as the table's type parameter
//每一个Table中都应该有*方法。它的类型必须与前面定义的类型參数(Int, String)一致
def * = (k, v)
}
//创建TableQuery对象(这里调用的是TableQuery的apply方法
//没有显式地调用new
val ts = TableQuery[Test] //forURL注冊MySQL驱动器,传入URL,用户名及密码
//方法回返的是一个DatabaseDef对象,然后再调用withSession方法
Database.forURL("jdbc:mysql://localhost:3306/slick", "root","123",
driver = "com.mysql.jdbc.Driver") withSession { //定义一个隐式值
//implicit session: MySQLDriverbackend.Session
//兴许方法中当做隐式參数传递
implicit session => // 创建Test表
//create方法中带有一个隐式參数
//def create(implicit session: JdbcBackend.SessionDef): Unit
ts.ddl.create
//插入数据
//def insertAll(values: U*)(implicit session: JdbcBackend.SessionDef): MultiInsertResult
ts.insertAll(1 -> "a", 2 -> "b", 3 -> "c", 4 -> "d", 5 -> "e")
//数据库查询(这里返回全部数据)
ts.foreach { x => println("k="+x._1+" v="+x._2) } //这里查询返回全部主鍵 <3的
ts.filter { _.k <3 }.foreach { x => println("k="+x._1+" v="+x._2) }
}
//模式匹配方式
ts.foreach { case(id,name) => println("id="+id+" name="+name) }
}

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

package cn.scala.xtwy

import scala.slick.driver.MySQLDriver.simple._

object CoffeeExample extends App {
// Definition of the SUPPLIERS table
//定义Suppliers表
class Suppliers(tag: Tag) extends Table[(Int, String, String, String, String, String)](tag, "SUPPLIERS") {
def id = column[Int]("SUP_ID", O.PrimaryKey) // This is the primary key column
def name = column[String]("SUP_NAME")
def street = column[String]("STREET")
def city = column[String]("CITY")
def state = column[String]("STATE")
def zip = column[String]("ZIP")
// Every table needs a * projection with the same type as the table's type parameter
def * = (id, name, street, city, state, zip)
}
val suppliers = TableQuery[Suppliers] // Definition of the COFFEES table
//定义Coffees表
class Coffees(tag: Tag) extends Table[(String, Int, Double, Int, Int)](tag, "COFFEES") {
def name = column[String]("COF_NAME", O.PrimaryKey)
def supID = column[Int]("SUP_ID")
def price = column[Double]("PRICE")
def sales = column[Int]("SALES")
def total = column[Int]("TOTAL")
def * = (name, supID, price, sales, total)
// A reified foreign key relation that
//can be navigated to create a join
//外鍵定义,它使得supID域中的值关联到suppliers中的id
//从而保证表中数据的正确性
//它定义的事实上是一个n:1的关系,
//即一个Coffees相应仅仅有一个Suppliers,
//而一个Suppliers能够相应多个Coffees
def supplier = foreignKey("SUP_FK", supID, suppliers)(_.id)
}
val coffees = TableQuery[Coffees] Database.forURL("jdbc:mysql://localhost:3306/slick", "root", "123",
driver = "com.mysql.jdbc.Driver") withSession { implicit session =>
// Create the tables, including primary and foreign keys
//按顺序创建表
(suppliers.ddl ++ coffees.ddl).create // Insert some suppliers
//插入操作,集合的方式
suppliers += (101, "Acme, Inc.", "99 Market Street", "Groundsville", "CA", "95199")
suppliers += (49, "Superior Coffee", "1 Party Place", "Mendocino", "CA", "95460")
suppliers += (150, "The High Ground", "100 Coffee Lane", "Meadows", "CA", "93966") // Insert some coffees (using JDBC's batch insert feature, if supported by the DB)
//批量插入操作,集合方式
coffees ++= Seq(
("Colombian", 101, 7.99, 0, 0),
("French_Roast", 49, 8.99, 0, 0),
("Espresso", 150, 9.99, 0, 0),
("Colombian_Decaf", 101, 8.99, 0, 0),
("French_Roast_Decaf", 49, 9.99, 0, 0))
//返回表中全部数据,相当于SELECT * FROM COFFEES
coffees foreach {
case (name, supID, price, sales, total) =>
println(" " + name + "\t" + supID + "\t" + price + "\t" + sales + "\t" + total) }
//返回表中全部数据。仅仅只是这次是直接让数据库帮我们进行转换
val q1 = for (c <- coffees)
yield LiteralColumn(" ") ++ c.name ++ "\t" ++ c.supID.asColumnOf[String] ++
"\t" ++ c.price.asColumnOf[String] ++ "\t" ++ c.sales.asColumnOf[String] ++
"\t" ++ c.total.asColumnOf[String]
// The first string constant needs to be lifted manually to a LiteralColumn
// so that the proper ++ operator is found
q1 foreach println //联合查询
//採用===进行比較操作,而非==操作符。用于进行值比較
//相同的还有!=值不等比較符
//甚至其他比較操作符与scala是一致的 <, <=, >=, >
val q2 = for {
c <- coffees if c.price < 9.0
s <- suppliers if s.id === c.supID
} yield (c.name, s.name) }

5. SQL与Slick相互转换

package cn.scala.xtwy

import scala.slick.driver.MySQLDriver.simple._
import scala.slick.jdbc.StaticQuery.interpolation
import scala.slick.jdbc.GetResult object SQLAndSlick extends App {
type Person = (Int, String, Int, Int)
class People(tag: Tag) extends Table[Person](tag, "PERSON") {
def id = column[Int]("ID", O.PrimaryKey)
def name = column[String]("NAME")
def age = column[Int]("AGE")
def addressId = column[Int]("ADDRESS_ID")
def * = (id, name, age, addressId)
def address = foreignKey("ADDRESS", addressId, addresses)(_.id)
}
lazy val people = TableQuery[People] type Address = (Int, String, String)
class Addresses(tag: Tag) extends Table[Address](tag, "ADDRESS") {
def id = column[Int]("ID", O.PrimaryKey)
def street = column[String]("STREET")
def city = column[String]("CITY")
def * = (id, street, city)
} lazy val addresses = TableQuery[Addresses] val dbUrl = "jdbc:mysql://localhost:3306/slick"
val jdbcDriver = "com.mysql.jdbc.Driver"
val user = "root"
val password = "123"
val db = Database.forURL(dbUrl, user, password, driver = jdbcDriver) db.withSession { implicit session => (people.ddl ++ addresses.ddl).create //插入address数据
addresses += (23, "文一西路", "浙江省杭州市")
addresses += (41, "紫荆花路", "浙江省杭州市") //插入people数据
people += (1, "摇摆少年梦", 27, 23)
people += (2, "john", 28, 41)
people += (3, "stephen", 28, 23) //以下两条语句是等同的(获取固定几个字段)
val query = sql"select ID, NAME, AGE from PERSON".as[(Int, String, Int)]
query.list.foreach(x => println("id=" + x._1 + " name=" + x._2 + " age=" + x._3)) val query2 = people.map(p => (p.id, p.name, p.age))
query2.list.foreach(x => println("id=" + x._1 + " name=" + x._2 + " age=" + x._3)) //以下两条语句是等同的(Where语句)
val query3 = sql"select * from PERSON where AGE >= 18 AND NAME = '摇摆少年梦'".as[Person]
query3.list.foreach(x => println("id=" + x._1 + " name=" + x._2 + " age=" + x._3)) val query4 = people.filter(p => p.age >= 18 && p.name === "摇摆少年梦")
query4.list.foreach(x => println("id=" + x._1 + " name=" + x._2 + " age=" + x._3)) //orderBy
sql"select * from PERSON order by AGE asc, NAME".as[Person].list
people.sortBy(p => (p.age.asc, p.name)).list //max
sql"select max(AGE) from PERSON".as[Option[Int]].first
people.map(_.age).max //隐式join
sql"""
select P.NAME, A.CITY
from PERSON P, ADDRESS A
where P.ADDRESS_ID = a.id
""".as[(String, String)].list people.flatMap(p =>
addresses.filter(a => p.addressId === a.id)
.map(a => (p.name, a.city))).run // or equivalent for-expression:
(for (
p <- people;
a <- addresses if p.addressId === a.id
) yield (p.name, a.city)).run //join操作
sql"""select P.NAME, A.CITY from PERSON P join ADDRESS A on P.ADDRESS_ID = a.id """.as[(String, String)].list
(people join addresses on (_.addressId === _.id))
.map{ case (p, a) => (p.name, a.city) }.run
} }

上面列出的仅仅是Slick与SQL的部分转换,还有诸如:Update、Delete等操作能够參见:http://slick.typesafe.com/doc/2.1.0/sql-to-slick.html

加入公众微信号,能够了解很多其他最新Spark、Scala相关技术资讯

Scala入门到精通——第二十九节 Scala数据库编程的更多相关文章

  1. Scala入门到精通——第二十四节 高级类型 (三)

    作者:摆摆少年梦 视频地址:http://blog.csdn.net/wsscy2004/article/details/38440247 本节主要内容 Type Specialization Man ...

  2. Scala入门到精通——第十九节 隐式转换与隐式參数(二)

    作者:摇摆少年梦 配套视频地址:http://www.xuetuwuyou.com/course/12 本节主要内容 隐式參数中的隐式转换 函数中隐式參数使用概要 隐式转换问题梳理 1. 隐式參数中的 ...

  3. Scala入门到精通——第十六节 泛型与注解

    本节主要内容 泛型(Generic Type)简单介绍 注解(Annotation)简单介绍 注解经常使用场景 1. 泛型(Generic Type)简单介绍 泛型用于指定方法或类能够接受随意类型參数 ...

  4. Scala入门到精通——第十五节 Case Class与模式匹配(二)

    本节主要内容 模式匹配的类型 for控制结构中的模式匹配 option类型模式匹配 1. 模式的类型 1 常量模式 object ConstantPattern{ def main(args: Arr ...

  5. centos MySQL主从配置 ntsysv chkconfig setup命令 配置MySQL 主从 子shell MySQL备份 kill命令 pid文件 discuz!论坛数据库读写分离 双主搭建 mysql.history 第二十九节课

    centos  MySQL主从配置 ntsysv   chkconfig  setup命令  配置MySQL 主从 子shell  MySQL备份  kill命令  pid文件  discuz!论坛数 ...

  6. 大白话5分钟带你走进人工智能-第二十九节集成学习之随机森林随机方式 ,out of bag data及代码(2)

              大白话5分钟带你走进人工智能-第二十九节集成学习之随机森林随机方式 ,out  of  bag  data及代码(2) 上一节中我们讲解了随机森林的基本概念,本节的话我们讲解随机森 ...

  7. 风炫安全web安全学习第二十九节课 CSRF防御措施

    风炫安全web安全学习第二十九节课 CSRF防御措施 CSRF防御措施 增加token验证 对关键操作增加token验证,token值必须随机,每次都不一样 关于安全的会话管理(SESSION) 不要 ...

  8. Simulink仿真入门到精通(十九) 总结回顾&自我练习

    从2019年12月27到2020年2月12日,学习了Simulink仿真及代码生成技术入门到精通,历时17天. 学习的比较粗糙,有一些地方还没理解透彻,全书梳理总结: Simulink的基础模块已基本 ...

  9. Scala入门到精通——第二十七节 Scala操纵XML

    本节主要内容 XML 字面量 XML内容提取 XML对象序列化及反序列化 XML文件读取与保存 XML模式匹配 1. XML 字面量 XML是一种很重要的半结构化数据表示方式,眼下大量的应用依赖于XM ...

随机推荐

  1. Servlet doPost方法同时上传图片和传递参数

    上传图片和传递参数 上传图片和文件属于enctype="multipart/form-data"  form中加入enctype="multipart/form-data ...

  2. UESTC 1599 wtmsb

    这天,AutSky_JadeK看到了n张图片,他忍不住说道:“我TM社保!”. 每张图片有一个社保值,他可以合并两张图片,合并所得的图片的社保值是原来两张图片的社保值之和. 每次合并需要消耗的体力也是 ...

  3. linux RAC 安装失败完全卸载

    1,删除软件安装目录 rm -rf /u01/app 2,删除以下目录内容 rm -rf /tmp/.oracle rm -rf   /tmp/* rm -rf   /tmp/ora* rm -rf ...

  4. JS之闭包详细解读

    闭包在红宝书中的解释就是:有权访问另一个函数作用域中的变量的函数. 1.变量作用域 全局变量:所有的函数外部定义的变量,它的作用域是整个script. 局部变量:定义在函数体内部的变量,作用域仅限于函 ...

  5. 推荐学习《Python与量化投资从基础到实战》PDF及代码+《量化投资以Python为工具》PDF及代码

    利用python分析量化投资问题是现在研究的热点,推荐两份资料用于学习 <Python与量化投资:从基础到实战>主要讲解如何利用Python进行量化投资,包括对数据的获取.整理.分析挖掘. ...

  6. Windows系统的关机、休眠和睡眠状态究的区别

    原文:Windows系统的关机.休眠和睡眠状态究的区别 相信有些小伙伴跟我一样,对电脑的一些常用操作或名词不太熟悉,今天我们就简单来聊聊电脑的关机.休眠和睡眠状态究竟有何区别吧! 如果你在电脑左下角的 ...

  7. Android基于XMPP Smack及Openfire学习笔记(1)

    之前开发的项目中实用到IM聊天功能.可是这块功能公司有专门的IM团队来开发,由他们开发好后.直接接入到我们APP中.我參与写IM相关功能非常地少,所以也一直想学习相关知识 . 眼下Android主要用 ...

  8. 一入python深似海--对象的属性

    Python中一切皆是对象,每一个对象都能够有多个属性.Python是怎样管理这些属性呢?我们来探讨一下. 属性的__dict__系统 对象的属性包括两部分:类属性和对象属性.对象的属性可能来自于其类 ...

  9. 智课雅思词汇---二、词根acu和acr

    智课雅思词汇---二.词根acu和acr 一.总结 一句话总结:acu和acr:sharp锋利的,敏捷的: acuteacutelyacuity sharp锋利的,敏捷的 1.词根acr表示什么意思? ...

  10. Python: PS 图像调整--对比度调整

    本文用 Python 实现 PS 里的图像调整–对比度调整.具体的算法原理如下: (1).nRGB = RGB + (RGB - Threshold) * Contrast / 255 公式中,nRG ...