Java8中使用流方式查询数据库的方法

由于关系型数据库操作语言和面向对象语言之间的差异,如今我们仍然需要花费许多时间建立数据库与 Java 应用之间互相沟通的桥梁。通常,我们可以编写自己的映射层(mapping layer),或者使用第三方的 ORM(Object Relational Mapper)对象关系映射框架,比如 Hibernate。ORM 框架虽然使用起来很方便,但是如何正确地配置和提高框架操作数据库的性能却不太容易,ORM 框架往往会使我们的应用性能下降。 最近,我贡献了一个新的开源项目——Speedment,它能使我们使用 Java 8 开发数据库应用程序变得更为快捷和高效。

Speedment 是使用 ORM 方式操作数据库的一种选择,以前我们需要100行操作数据库的 Java 代码,在 Java 8中,可能只需要一行代码。

在90年代末,我使用 Java 开发数据库应用的时候,许多代码逻辑都需要自己来编写,比如捕获异常、类型转换等,经过许多改动,最后这些代码变得难以维护和扩展。

由于关系型数据库操作语言和面向对象语言之间的差异,如今我们仍然需要花费许多时间建立数据库与 Java 应用之间互相沟通的桥梁。通常,我们可以编写自己的映射层(mapping layer),或者使用第三方的 ORM(Object Relational Mapper)对象关系映射框架,比如 Hibernate。ORM 框架虽然使用起来很方便,但是如何正确地配置和提高框架操作数据库的性能却不太容易,ORM 框架往往会使我们的应用性能下降。

最近,我贡献了一个新的开源项目——Speedment,它能使我们使用 Java 8 开发数据库应用程序变得更为快捷和高效。

Speedment 是什么?

Speedment 是一个开源项目,它是一个基于 Java 8 的新特性开发的新的 Java 库,从这个项目开发开始,它的代码就全部使用 Java 8来编写。Speedment 使用标准流查询数据库,这使得开发者不需要学习任何新的查询 API ,以及不必考虑 JDBC 、ResultSet 和其他有关数据库的指定的操作。

Speedment 会根据现有数据库来自动生成代码。由于它的这种方式,开发者不需要编写一行关于数据库实体(database entities)的代码。它生成的代码中也包含 JavaDocs 帮助文档,这使开发者不需要编写关于 User 或者 Book 等对象的实体类。取而代之地,我们只需要创建或者使用一个现有的数据库,然后用 Speedment 去连接它,接着 Speedment 会分析数据库结构来生成实体类的代码。

更有趣的是,Speedment 用野兔来作为它的吉祥物。 在接下来的例子中,我们会使用一个名为 “hare” 的数据库来给大家演示 Speedment 的使用方式。该数据库的表结构如下:

mysql> explain hare;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(45) | NO | | NULL | |
| color | varchar(45) | NO | | NULL | |
| age | int(11) | NO | | NULL | |
+-------+-------------+------+-----+---------+----------------+
4 rows in set (0.01 sec)

下面是 Speedment 根据数据库信息生成的一个相应的实体类(为简洁起见,我们将 JavaDocs 在这里移除了):

public interface Hare extends Entity<Hare> {
public final static ReferenceComparableField<Hare, Integer> ID = new ReferenceComparableFieldImpl<>("id", Hare::getId, Hare::setId);
public final static ReferenceComparableStringField<Hare> NAME = new ReferenceComparableStringFieldImpl<>("name", Hare::getName, Hare::setName);
public final static ReferenceComparableStringField<Hare> COLOR = new ReferenceComparableStringFieldImpl<>("color", Hare::getColor, Hare::setColor);
public final static ReferenceComparableField<Hare, Integer> AGE = new ReferenceComparableFieldImpl<>("age", Hare::getAge, Hare::setAge);
Integer getId();
String getName();
String getColor();
Integer getAge();
Hare setId(Integer id);
Hare setName(String name);
Hare setColor(String color);
Hare setAge(Integer age);
/** Graph-like traversal methods eliminating JOINs */
Stream<Carrot> findCarrotsByOwner();
Stream<Carrot> findCarrotsByRival();
Stream<Carrot> findCarrots();
}

我将用一篇单独的文章介绍 find*() 方法的用法,它可以被用来代替 SQL joins 操作。

Queries查询示例

下面的例子展示如何查询 Hare 表的数据库信息:

List<Hare> oldHares = hares.stream()
.filter(AGE.greaterThan(8))
.collect(toList());

智能流

上面的代码看起来已经遍历了 hare 数据库表的所有行,但实际上并不是这样的。 Stream 是智能的,当它到达 collect() 操作的时候,会分析 filter 操作,并推断出 hare.age 大于8的列,因此会节省 hares 的流操作,产生与 “select * from hare where age > 8” 操作一样的效果。如果你使用了多个 filters,他们会被合并起来以节省流操作。下面是另一种用流方式进行多个操作的例子:

long noOldHares = hares.stream()
.filter(AGE.greaterThan(8))
.mapToInt(Hare::getAge)
.sorted()
.count();

在上面的代码中,当流到达 count() 操作时,它将检查它自己的管道。首先会推断上面例子中的 AGE 操作,其次在不改变 count() 结果的情况下,会推断 mapToInt() 和 sorted() 操作,这些操作可以被消除,因此这段代码的操作被节省为 “select count(*) from hare where age > 8”。这意味着您可以使用 Java 8 流而你不必如此在意流是如何转换为SQL的。

如何下载和加入我们

如果你想学习如何使用 Speedment 的 API 和在项目中如何使用 Speedment,可以访问网址 www.speedment.org,并可以在 gitter 上发表评论,也可以从 GitHub 上下载 Speedment 的源码,来贡献你自己的代码。

总结

回顾早期的一些老项目,一个超过100行代码的数据库类,现在可以使用 Java 8 缩减成1行代码。那是反转后的摩尔定律,在14年内(=7摩尔周期),行数大约减半了七次。这就是进步!

什么是数据流

流代表从支持聚合操作源的序列的对象。以下是数据流的特点。

元素序列 - 流提供了一组特定类型的以顺序方式元素。流获取/计算需求的元素。它不存储元素。

源- 流使用集合,数组或I/O资源为输入源。

聚合操作 - 数据流支持如filter, map, limit, reduced, find, match等聚合操作。

管道传输 - 大多数流操作的返回流本身使他们的结果可以被管道传输。这些操作被称为中间操作以及它们的功能是利用输入,处理输入和输出返回到目标。collect()方法是终端操作,这是通常出现在管道传输操作结束标记流的结束。

自动迭代 - 流操作内部做了反复对比,其中明确迭代需要集合提供源元素。

(0)

相关推荐

  • 简单总结Java IO中stream流的使用方法

    Java语言的输入输出功能是十分强大而灵活的,对于数据的输入和输出操作以"流"(stream)的方式进行.J2SDK提供了各种各样的"流"类,用以获取不同种类的数据,定义在包java.io中.程序中通过标准的方法输入或输出数据. Java中的流可以从不同的角度进行分类: 按照流的方向不同:分为输入流和输出流. 按照处理数据单位的不同:分为字节流(8位)和字符流(16位). 按照功能不同:分为节点流和处理流. 节点流:是可以从一个特定的数据源(节点)读写数据的流(例如

  • Java输入输出流的使用详细介绍

    1.什么是IO Java中I/O操作主要是指使用Java进行输入,输出操作. Java所有的I/O机制都是基于数据流进行输入输出,这些数据流表示了字符或者字节数据的流动序列.Java的I/O流提供了读写数据的标准方法.任何Java中表示数据源的对象都会提供以数据流的方式读写它的数据的方法. Java.io是大多数面向数据流的输入/输出类的主要软件包.此外,Java也对块传输提供支持,在核心库 java.nio中采用的便是块IO. 流IO的好处是简单易用,缺点是效率较低.块IO效率很高,但编程比较

  • Java 使用IO流实现大文件的分割与合并实例详解

    Java 使用IO流实现大文件的分割与合并 文件分割应该算一个比较实用的功能,举例子说明吧比如说:你有一个3G的文件要从一台电脑Copy到另一台电脑, 但是你的存储设备(比如SD卡)只有1G ,这个时候就可以把这个文件切割成3个1G的文件 ,分开复制, 最后把三个文件合并, 这样就解决问题了 :再比如说, 你有一个上百M的文件要上传到FTP ,但是这个FTP限制你单个文件不能超过10M 这时候也可以用文件分割的办法解决问题.既然分割了,那么在我们再次使用的时候就需要合并了,今天我们就通过Java

  • java IO流 之 输出流 OutputString()的使用

    FileOutPutStream:子类,写出数据的通道 步骤: 1.获取目标文件 2.创建通道(如果原来没有目标文件,则会自动创建一个) 3.写入数据 write() 4.释放资源 注意: (1)如果目标文件不存在,那么会自己创建一个目标文件 (2)如果目标文件存在,先将里面的数据清空,再写入数据 (3)想在原有的数据上写入数据,则在创建通道的时候使用 构造方法: OutPutStream(File file,Boolean append),boolean值为true则可以 (4)用 write

  • Java输入流Scanner/BufferedReader使用方法示例

    1.使用Scanner 使用时需要引入包import java.util.Scanner;首先定义Scanner对象 Scanner sc = new Scanner(System.in);如果要输入整数,则 int n = sc.nextInt();String类型的,则String temp = sc.next(); 比如: 复制代码 代码如下: import java.util.Scanner; public class Test {    @SuppressWarnings("resou

  • java中流的使用

    Java中的流,可以从不同的角度进行分类. 一.按照数:输入流和输出流. 输出流: 输入流: 因此输入和输出都是从程序的角度来说的. 二.按照处理数据单位不同可以分为:字节流和字符流. 字节流和字符流的原理是相同的,只不过处理的单位不同而已,字节流.字符流,两类都分为输入和输出操作. 以下是java中io中常用的流. 1.在字节流中输出数据主要是使用OutputStream完成,输入流使用的是InputStream. 输出流OutputStream String a = "d:\\bbb.txt

  • java基础知识I/O流使用详解

    "流"概念源于UNIX中的管道(pipe)的概念.在UNIX中,管道是一条不间断的字节流,用来实现程序或进程间的通信,或读写外围设备.外部文件等,它屏蔽了实际的I/O设备中处理数据的细节.   一个流,必有源端和目的端,它们可以是计算机内存的某些区域,也可以是磁盘文件,甚至可以是Internet上的某个URL. 流的方向是重要的,根据流的方向,流可以分为两类:输入流和输出流.其实输入/输出是想对于内存来说的.实际上,流的源端和目的端可简单地看成是字节的生产者和消费者,对于输入流,可不必

  • java IO流 之 输入流 InputString()的使用

    本文主要给大家介绍java的InputStream 流的使用. (1)FileInputstream: 子类,读取数据的通道 使用步骤: 1.获取目标文件:new File() 2.建立通道:new FileInputString() 3.读取数据:read() 4.释放资源:close() //一些默认要导入的包 import java.io.File; import java.io.FileInputStream; import java.io.IOException; public sta

  • Java8中使用流方式查询数据库的方法

    由于关系型数据库操作语言和面向对象语言之间的差异,如今我们仍然需要花费许多时间建立数据库与 Java 应用之间互相沟通的桥梁.通常,我们可以编写自己的映射层(mapping layer),或者使用第三方的 ORM(Object Relational Mapper)对象关系映射框架,比如 Hibernate.ORM 框架虽然使用起来很方便,但是如何正确地配置和提高框架操作数据库的性能却不太容易,ORM 框架往往会使我们的应用性能下降. 最近,我贡献了一个新的开源项目--Speedment,它能使我

  • 在java List中进行模糊查询的实现方法

    比如我有下面这样一个List,里面存放的是多个Employee对象.然后我想对这个List进行按照Employee对象的名字进行模糊查询.有什么好的解决方案么? 比如我输入的查询条件为"wang",那么应该返回只包含employee1的List列表. List list = new ArrayList(); Employee employee1 = new Employee(); employee1.setName("wangqiang"); employee1.s

  • 一文带你掌握Java8中Lambda表达式 函数式接口及方法构造器数组的引用

    目录 函数式接口概述 函数式接口示例 1.Runnable接口 2.自定义函数式接口 3.作为参数传递 Lambda 表达式 内置函数式接口 Lambda简述 Lambda语法 方法引用 构造器引用 数组引用 函数式接口概述 只包含一个抽象方法的接口,称为函数式接口. 可以通过 Lambda 表达式来创建该接口的对象. 可以在一个接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口.同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口.

  • Java8中对泛型目标类型推断方法的改进

    一.简单理解泛型 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数.通俗点将就是"类型的变量".这种类型变量可以用在类.接口和方法的创建中. 理解Java泛型最简单的方法是把它看成一种便捷语法,能节省你某些Java类型转换(casting)上的操作: 复制代码 代码如下: List<Apple> box = new ArrayList<Apple>();box.add(new Apple());Apple a

  • PHP的中使用非缓冲模式查询数据库的方法

    最近在开发一个PHP程序时遇到了下面的错误: PHP Fatal error: Allowed memory size of 268 435 456 bytes exhausted 错误信息显示允许的最大内存已经耗尽.遇到这样的错误起初让我很诧异,但转眼一想,也不奇怪,因为我正在开发的这个程序是要用一个foreach循环语句在一个有4万条记录的表里全表搜索具有特定特征的数据,也就是说,一次要把4万条数据取出,然后逐条检查每天数据.可想而知,4万条数据全部加载到内存中,内存不爆才怪. 毕竟编程这么

  • VMware中Linux共享mysql数据库的方法

    win7 +Navicat Lite 9+ VMware7 在VMware中安装openSUSE11.x mysql5 Navicat Lite8\9 VMware网络连接方式 桥接(Bridged) 两个重要的设置 1)防火墙(这个如果不设置,防火墙启用时,从其它机器永远连接不上.) 2)用户帐户(linux Navicat Lite8)(这个如果不设置,从其它机器永远连接不上.) 上图表明指定的用户root可以从任意一个主机上登录. 如果Host设为:192.168.0.%表明用户root可

  • Python 中使用 PyMySQL模块操作数据库的方法

    之前用的Python2,连接MySQL用的是MySQLdb.现在换成python3.x了,由于 MySQLdb 模块还不支持 Python3.x,所以 Python3.x 如果想连接MySQL需要安装 PyMySQL模块,以下将介绍PyMySQL的安装及常用操作. 一.安装 pip install PyMySQL 二.常用操作 查询数据 import pymysql # 连接数据库 conn = pymysql.connect( host='127.0.0.1', user='root', pa

  • php+mysqli使用面向对象方式查询数据库实例

    本文实例讲述了php+mysqli使用面向对象方式查询数据库的方法.分享给大家供大家参考.具体实现方法如下: <?php //第一步:创建数据连接对象 $mysqli = new MySQLi("localhost","root","123456"); //默认的 MySQL的类,其属性与方法见手册 if($mysqli->connect_error){//connect_error为属性,报错 die("数据库连接失败:&

  • 使用JDBC从数据库中查询数据的方法

    * ResultSet 结果集:封装了使用JDBC 进行查询的结果 * 1. 调用Statement 对象的 executeQuery(sql) 方法可以得到结果集 * 2. ResultSet 返回的实际上就是一张数据表,有一个指针指向数据表的第一行的前面, * 可以调用next()方法检测下一行是否有效,若有效,返回true,且指针下移, * 相当于iterator 对象的 hasNext() 和 next()方法的结合体 * 3. 当指针定位到一行时,可以通过调用getXxx(index)

  • 用SQL语句查询数据库中某一字段下相同值的记录方法

    今天接到一任务,有一张学生信息表(Excel表),里面有一万多条记录,现在要把这张表导入到数据库中,并设置学生学号为主键,但是现在这张表中的学生学号有重复的记录,我必须先找出这些重复的记录,然后再进行筛选,经过研究问题终于得到解决.      以上问题实际上就是查询数据库表中某一字段值重复的记录,这里省略如何将Excel表导入到数据库步骤,只讨论用SQL查询数据库中某一字段下相同值的记录方法. 现在假设数据库表名为student,里面有字段Sno(学号),ID(身份证),这里提供两种查询的方法:

随机推荐