FRM介绍

最近看到了一个FRM的框架Slick。 FRM的意思是Functional Relational Mapping, 一种基于函数式的ORM。

举一个最简单的例子:

val queryResult = db.query(queryStr)queryResult.onSuccess { result =>result.doSomething ...
}

数据库db查询一条sql语句。查询成功的时候使用闭包完成处理。 看到这段代码的第一反应就是js的ajax处理,代码几乎是一样的,也发现之前在学校里写nodejs的时候查询db也是这样的语法。

var jqxhr = $.ajax( {url: 'url',method: 'GET',data: [user: 'format']
});jqxhr.success(function() {...
});

FRM相比ORM最明显的优势就是FRM基于多线程的Future的数据查询,而ORM是单线程的线性执行。

FRM构造sql查询也是相当简单的:

// 构造查询
val newQuery = students.filter(_.age > 24).sortBy(_.name)
// 执行查询
db.run(newQuery)

FRM其他的优势可以参考官方文档。

Slick实例

下面以一个Students和Classrooms的实例来说明一下Slick的使用。

首先是创建对应的domain,学生与教室的关系是1对多。

Students domain(使用Option类型说明该列是可为空的):

class Student(tag: Tag) extends Table[(Int, String, Int, Int, Option[Date])](tag, "Students") {def id: Rep[Int] = column[Int]("id", O.PrimaryKey, O.AutoInc)def name: Rep[String] = column[String]("name")def age: Rep[Int] = column[Int]("age")def birthDate: Rep[Option[Date]] = column[Option[Date]]("birth_date")def classroomId = column[Int]("classroom_id")def * : ProvenShape[(Int, String, Int, Int, Option[Date])] = (id, name, age, classroomId, birthDate)def classroom: ForeignKeyQuery[Classroom, (Int, String)] = foreignKey("FK_CLASSROOM", classroomId, TableQuery[Classroom])(_.id)
}

Classrooms domain:

class Classroom(tag: Tag) extends Table[(Int, String)](tag, "Classrooms") {def id = column[Int]("id", O.PrimaryKey, O.AutoInc)def name = column[String]("name")def * = (id, name)
}

各个db操作,schema创建,sql插入,sql查询等操作如下,加了几句备注,具体的代码就不分析了:

object SampleSlickDemo extends App {val db = Database.forConfig("h2mem1")try {val classrooms = TableQuery[Classroom]val students = TableQuery[Student]val setupAction: DBIO[Unit] = DBIO.seq(// create student and classroom table in database(classrooms.schema ++ students.schema).create,// insert some rows in classroomclassrooms += (1, "classroom1"),classrooms += (2, "classroom2"),classrooms += (3, "classroom2"))val setupFuture = db.run(setupAction)val f = setupFuture.flatMap { _ =>val insertAction: DBIO[Option[Int]] = students ++= Seq ((1, "format1", 11, 1, new Date(System.currentTimeMillis())),(2, "format2", 22, 2, new Date((System.currentTimeMillis()))),(3, "format3", 33, 3, new Date((System.currentTimeMillis()))))val insertAndPrintAction = insertAction.map { studentResult =>studentResult.foreach { numRows =>println(s"inserted $numRows students")}}db.run(insertAndPrintAction)}.flatMap { _ =>// print All Classroomsdb.run(classrooms.result).map { classroom =>classroom.foreach(println);}// print All Studentsdb.run(students.result).map { studnet =>studnet.foreach(println);}// condition searchval studentQuery = students.filter(_.age > 20).sortBy(_.name)db.run(studentQuery.result).map { student =>student.foreach(println)}}Await.result(f, Duration.Inf)} finally db.close()
}

数据库配置

在配置文件application.conf里配置数据库配置信息:

h2mem1 = {url = "jdbc:h2:mem:test1"driver = org.h2.DriverconnectionPool = disabledkeepAliveConnection = true
}

然后就可使用Database初始化数据库,参数就是配置文件里对应的数据库name:

val db = Database.forConfig("h2mem1")

DBIOAction介绍

DBIOAction就是数据库的一个操作,比如Insert,Update,Delete,Query等操作。

可以使用上面分析的数据库配置变量db进行操作。

db有个run方法使用DBIOAction作为参数,返回Future类型的返回值。

DBIO是一个单例对象,它的seq方法可以传入多个DBIOAction,然后返回一个新的DBIOAction。 += 方法返回的也是DBIOAction。

val setupAction: DBIO[Unit] = DBIO.seq((classrooms.schema ++ students.schema).create,classrooms += (1, "classroom1"),classrooms += (2, "classroom2"),classrooms += (3, "classroom2")
)

++=方法跟+=方法一样会返回DBIOAction,只不过它的参数是个Iterable:

val insertAction: DBIO[Option[Int]] = students ++= Seq ((1, "format1", 11, 1, new Date(System.currentTimeMillis())),(2, "format2", 22, 2, new Date((System.currentTimeMillis()))),(3, "format3", 33, 3, new Date((System.currentTimeMillis()))))

DBIOAction提供许多好用的方法:

map方法:参数是个函数,这个函数可以返回任意类型的值,返回是个DBIOAction。 所以可以使用map关联起来多个DBIOAction。

flatMap方法:参数是个函数,这个函数的返回值必须是个DBIOAction,返回值是个DBIOAction。作用跟map类似,只不过函数参数的返回值不一样。

filter方法:参数是个函数,这个函数的返回值必须是个Boolean,返回值是个DBIOAction。过滤作用。

andThen方法:参数是个DBIOAction,返回值是个DBIOAction。在Action完成后执行另外一个Action。

增删改查操作

查询

Slick的查询可以直接通过TableQuery操作,使用TableQuery提供的filter可以实现过滤操作,使用drop和take完成分页操作,使用sortBy完成排序操作。

students.filter(_.classroomId === 1)
students.drop(1).take(2)
students.sortBy(_.age.desc)

可以使用map方法找出需要的列。

多列:

students.map { student =>(student.name, student.age)
}

一列:

students.map(_.name)

Join方法:

cross join操作:

val crossJoin = for {(s, c) <- students join classrooms
} yield (s.name, c.name)

inner Join操作:

val innerJoin = for {(s, c) <- students join classrooms on (_.classroomId === _.id)
} yield (s.name, c.name)

另外一个inner join:

val innerJoin = for {s <- studentsc <- classrooms if c.id === s.classroomId
} yield (s.name, c.name)

left join操作:

val leftJoin = for {(s, c) <- students joinLeft classrooms on (_.classroomId === _.id)
} yield (s.name, c.map(_.name))

right join操作:

val rightJoin = for {(s, c) <- students joinRight classrooms on (_.classroomId === _.id)
} yield (s.map(_.name), c.name)

新增

所有列都有值:

val insertAction = DBIO.seq(students += (4, "format4", 44, 3, new Date(System.currentTimeMillis())),students += (5, "format5", 55, 3, new Date(System.currentTimeMillis())),students ++= Seq ((6, "format6", 66, 3, new Date(System.currentTimeMillis())),(7, "format7", 77, 3, new Date(System.currentTimeMillis())))
)

部分列有值:

students.map(s => (s.name, s.age, s.classroomId)) += ("format8", 88, 3)

删除

删除classroomId为3的所有数据:

val q = students.filter(_.classroomId === 3)
val affectedRowsCountFuture = db.run(q.delete)
affectedRowsCountFuture.map { rows =>println(rows)
}

修改

修改单列:

val q = students.filter(_.id === 2).map(_.name)
val updateSql = q.update("format2222")
db.run(updateSql)

修改多列:

val q = students.filter(_.id === 2).map(s => (s.name, s.age))
val updateSql = q.update(("format2222", 222))
db.run(updateSql)

CaseClass的使用

之前的例子都是使用Tuple构造domain。 还有一种更方便的方式,那就是使用CaseClass。

case class People(id: Long, name: String, age: Int)

例子:

private class PeopleTable(tag: Tag) extends Table[People](tag, "people") {val id = column[Long]("id", O.PrimaryKey, O.AutoInc)val name = column[String]("name")val age = column[Int]("age")def * = (id, name, age) <> ((People.apply _).tupled, People.unapply)
}val db = Database.forConfig("h2mem1")try {val people = TableQuery[PeopleTable]val setupAction = DBIO.seq(
      people.schema.create,
      people += People(1, "format1", 11))val setupFuture = db.run(setupAction);val f = setupFuture.flatMap { _ =>
    db.run(people.result).map { p =>
      p.foreach(println)
    }}Await.result(f, Duration.Inf)} finally db.close()

Scala持久层框架Slick介绍相关推荐

  1. 持久层框架之MyBatis

    1.mybatis框架介绍: MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并 ...

  2. java持久层用文件_Java持久层框架MyBatis简单实例

    MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis .本文 ...

  3. 优秀的持久层框架-Mybatis(上)

    文章目录 前言 一.MyBatis概述 1.1传统JDBC编程 1.2 mybatis的历史 1.3 mybatis是什么? 1.4如何使用? 1.5Mybatis架构 二. MyBatis环境搭建 ...

  4. Java数据库持久层框架基础:jdbc原理和使用综述

    Java数据库持久层框架基础:jdbc原理和使用综述 前言 jdbc基础架构 jbdc的使用 jdbc的主要接口 驱动 连接 连接池 会话Statement 结果集ResultSet 前言 目前jav ...

  5. SpringBoot项目拥抱Mybatis-Plus持久层框架实践

    本文目录 前言 自从 Mybatis-Plus推出以来,越来越多的公司在自己的项目中选择Mybatis-Plus框架替换了持久层框架Mybatis.因为Mybatis-Plus用起来既有Mybatis ...

  6. 一起来学SpringBoot(七)持久层框架

    springboot具有非常棒的持久层框架支持,下面我将介绍我用过的三种持久层框架进行简述使用. 由于这里操作的都是一张表,这里贴出通用的yml和建表语句 切记这里使用的是mysql8 ,5.8之前的 ...

  7. Java持久层框架之mybatis使用

    一.什么是框架,框架从何而来,为什么使用框架? 框架(framework): 1.是一系列jar包,其本质是对JDK功能的拓展.(jar包,jar:class文件的压缩包) 2.框架是一组程序的集合, ...

  8. 酷帅狂拽吊炸天——一统江湖的持久层框架之SpringData

    一.SpringData概述 1.1 现有问题 ​ 随着互联网的发展,互联网产品的复杂度越来越高,在开发中使用到的数据存储产品不再仅限于关系型数据库,还会使用到Redis.MongoDB.Elasti ...

  9. bbossgroups持久层框架ConfigSQLExecutor组件api实例

    本文简单介绍bbossgroups持久层框架ConfigSQLExecutor组件api实例,以下就是相关接口的使用实例: /* * Copyright 2008 biaoping.yin * * L ...

最新文章

  1. 中科院自动化所博士带你入门CV物体检测算法
  2. 高并发之存储篇:关注下索引原理和优化吧!躲得过实践,躲不过面试官!
  3. web前端入门学习 css(4)(盒子模型)
  4. 【CSWS2014 Summer School】互联网广告中的匹配和排序算法-蒋龙(上)
  5. C#中简单的正则表达式(也经常会用到的)
  6. intellij中出現org.apache.hadoop.fs.FSDataInputStream解決方案
  7. python读取xml文件内容显示不全_python读取xml文件时的问题
  8. element table批量删除_element 表格批量删除
  9. IAR编译器中函数智能提示
  10. 都说如果朋友都是有钱人,你也会更容易发财
  11. Linux eclipse+perl开发环境安装
  12. poi向word插入图片_【工作应用】Java根据word模板动态生成word文档(SpringBoot项目)...
  13. matlab中[d1_sj_d1],Matlab中竖曲线计算程序
  14. 设置国内maven镜像仓库
  15. 考研:研究生考试(五天学完)之《线性代数与空间解析几何》研究生学霸重点知识点总结之目录(矩阵及其运算、向量与向量空间、欧氏空间、线性方程组、特征值/特征向量及相似矩阵、二次型、线性空间与线性变换)
  16. Android Studio的安装与配置
  17. 音频怎么转换mp3格式?
  18. 打开word2016文档时提示用文本恢复转换器打开文件
  19. 全国计算机一级学科博士点,一级学科博士点高校排名
  20. 给本本换硬盘,直接克隆旧盘!

热门文章

  1. 观看《辛德勒的名单》后的感想
  2. 如何在阿里技术面试中脱颖而出?
  3. 大数据:变革世界的关键资源
  4. 【转 | 侵删】2D 绘图技术中的坐标系统与坐标变换
  5. Hadoop_mapreduce2
  6. Android 系统增加字体库及修改系统默认字体
  7. Integrated Clock Gating (ICG)
  8. Java根据模板生成pdf文件并导出
  9. matlab apfc,基于Matlab的三相APFC建模与仿真
  10. 计算机视觉基础与模式识别,计算机视觉与模式识别(3)—— FaceMorphing