在Java程序中使用数据库的新方法_java

 Java 8终于到来了! 经过几年的等待, java程序员终于能在java中得到函数式编程的支持了. 函数式编程的支持能流程化现有的代码并且为java提供强大的能力.在这些新特性中最瞩目的是java程序员对数据库的操作方式.函数式编程带来了令人激动的简便高效的数据库API. Java 8 将会支持可与像C#的LINQ等语言竞争的新的数据库访问方式.
处理数据的函数式方式

Java 8 不仅仅添加了函数式支持,它也通过新的函数式处理数据的方式扩展了集合(Collection)类. 而通常情况下java处理大量数据时需要大量的循环和迭代器.

例如, 假设你有一个存储客户(Customer)对象的collection:
 

Collection<Customer> customers;

如果你只对来自Belgium的客户感兴趣, 你将不得不迭代所有的customer对象并只保存你需要的.
 

Collection<Customer> belgians = new ArrayList<>();
for (Customer c : customers) {
  if (c.getCountry().equals("Belgium"))
    belgians.add(c);
}

这不仅花费了5行代码,而且它也不怎么抽象.假使你有1千万个对象时会怎样呢?你会通过两个线程并发过滤所有对象来提速么?那你将不得不使用大量危险的多线程代码来重写所有代码.

而通过Java 8,仅仅只需要一行代码就能实现相同的功能.通过对函数式编程的支持, Java 8 能让你只写一个函数表明你对哪些客户(对象)感兴趣然后使用那个函数对集合做过滤就可以了. Java 8 的新 Steams API 支持你这样做:
 

customers.stream().filter(
  c -> c.getCountry().equals("Belgium")
);

上面Java 8 版本的代码不仅更短,而且更容易理解.它几乎没有什么 陈词滥调(循环或迭代器等).代码调用了filter()方法,那很明显这段代码是用来过滤客户(对象)的.你不需要再把时间浪费在解读循环中的代码来理解它在对它的数据做什么.

假使你想并发执行这段代码该怎么办呢?你只需使用另一个类型的stream
 

customers.parallelStream().filter(
  c -> c.getCountry().equals("Belgium")
);

更另人激动的是这种函数式风格的代码也同样适用于数据库

在数据库上使用函数式方式

传统上来说, 程序员需要用特殊数据库查询语句去访问数据库的数据. 例如,下面就是用 JDBC 代码去查找来自Belgium的客户:
 

PreparedStatement s = con.prepareStatement(
   "SELECT * "
  + "FROM Customer C "
  + "WHERE C.Country = ? ");
s.setString(1, "Belgium");
ResultSet rs = s.executeQuery();

大部分这些代码都是字符串, 这样会使编译器不能发现错误而且这草率的代码会导致安全问题. 还有这些大量的样板代码使得写数据访问代码变得十分冗余. 一些工具例如 jOOQ ,通过使用特殊的java库去提供数据库查询语言可以解决错误检查和安全问题。 或者使用对象关系映射工具可以免去大量的无趣的代码,可它们只能用在通用访问查询, 如果需要复杂的查询,还是需要用特殊的数据库查询语言。

使用Java 8,借助流式API就可以用函数式方式去查询数据库了。例如, Jinq 是一个开源的项目,它探索怎样的未来数据库API可以令函数式编程成为可能。这里就是一个使用Jinq的数据库查询:
 

customers.where(
  c -> c.getCountry().equals("Belgium")
);

这代码几乎跟跟使用流式API的代码一样. 事实上,未来的Jinq版本可以让你用流式API直接写数据库查询。 当代码运行的时候,Jinq将自动翻译成数据库查询代码,正如之前JDBC查询一样。

这样的话,就算没有学过一些新的数据库查询语言,你也可以写出有效率的数据库查询。你可以用同样样式的代码用在java集合上。你也不需要特殊的java编译器或者虚拟机。所有的代码编译和运行在普通的java 8 JDK上。如果你的代码有错误,编译器将找出它们并且报告给你,就像普通的java代码。

Jinq 支持跟SQL92一样的复杂查询. Selection(选择), projection(投影), joins(连接), 和子查询 它都支持。翻译java代码成数据库查询的算法是十分灵活的,只要是它能接受的,都能翻译。例如,Jinq能够翻译下面的数据库查询,尽管它很复杂。
 

customers
  .where( c -> c.getCountry().equals("Belgium") )
  .where( c -> {
    if (c.getSalary() < 100000)
      return c.getSalary() < c.getDebt();
    else
      return c.getSalary() < 2 * c.getDebt();
    } );

正如你看到的,java 8 的函数式编程非常适合数据库查询。而且查询紧凑,甚至复杂的查询也能够胜任。

内部运作

但这都是如何工作的呢?怎么能让普通的Java编译器将Java代码转换成数据库查询?Java 8 有什么特别之处使这个成为可能?

支持这些函数性风格的新的数据库PI的关键是一种叫做“象征性执行”的字节码分析手段。虽然你的代码是被一个普通的Java编译器编译的并运行在一个普通的Java虚拟机中,但 Jinq 能够在你被编译的Java代码运行时进行分析并从中构建数据库查询。使用 Java 8 Streams API 时,常会发现分析短小的函数时,象征性执行的工作效果最好。

要了解这个象征性执行是如何工作的,最简单的方法是用一个例子。让我们检查一下下面的查询是如何被 Jinq 转换为SQL查询语言的:
 

customers
  .where( c -> c.getCountry().equals("Belgium") )

初始时, 变量 customers 是一个集合,其对应的数据库查询是:
 

SELECT *
 FROM Customers C

然后,where() 方法被调用,一个函数被传递给它。在 where() 方法中,Jinq 打开这个函数的 .class 文件,得到这个函数被编译成的字节码进行分析。在这个例子中,不使用真正的字节码,让我们用一些简单的指令来代表这个函数的字节码:

  d = c.getCountry()

  e = “Belgium”

  e = d.equals(e)

  return e

在这里,我们假设函数已被Java编译器编译成这四条指令。当调用 where() 方法时,Jinq 看到的就是这些。如何才能使Jinq理解这些代码呢?

Jinq 通过执行代码来分析。但 Jinq 不直接运行代码。它是“抽象”地运行代码:不使用真实的变量和真实的值,Jinq 使用符号来表示执行代码时的所有值。这就是这个分析为什么被称为“象征性执行”。

Jinq 执行每条指令,并跟踪所有的副作用或代码在程序状态时改变的所有东西。下面是一个图表,显示出 Jinq 用象征性执行方式执行这四行代码时发现的所有副作用。

象征性执行的例子

在图中,你可以看到第一条指令运行后,Jinq 发现了两个副作用:变量d已经发生了变化,方法 Customer.getCountry() 被调用。由于是象征性执行,变量d没有给出一个真正的比如是“USA”或“Denmark”的值,它被分配为 c.getCountry() 的象征性的值。

在所有这些指令被象征性执行之后,Jinq 对副作用作精简。由于变量 d 和 e 是局部变量,它们的任何变化在函数退出后都会被丢弃,所以这些副作用可以忽略不计。Jinq也知道 Customer.getCountry() and String.equals() 方法没修改任何变量或显示任何输出,因此这些方法调用也可以被忽略。由此,Jinq 可以得出这样的结论:执行这个函数只会产生一个作用,它会返回 c.getCountry().equals("Belgium")。

一旦Jinq已明白在 where()方法中传递给它的函数,它可以混合数据库查询方面的知识,优先于 customers 集合来创建一个新的数据库查询。

生成数据库查询

这就是 Jinq 如何从你的代码生成数据库查询的。象征性执行的使用意味着,这种方法对于不同的Java编译器输出的不同的代码模式都是相当强大的。如果 Jinq 遇到的代码有不能转化为数据库查询的副作用,Jinq 将保持你的这些代码不变。因为一切都是用正常的Java代码写的,Jinq 可以直接运行那些代码,您的代码将产生预期的结果。

这个简单的翻译实例应该让你明白了怎样查询翻译作品。你可以确信,这些算法可以正确地从你的代码生成数据库查询。
美好前景

我希望我已经让你品尝到了Java 8带来的在Java中进行数据库工作的新方式。Java 8 支持的函数式编程允许你用和为Java集合编写代码同样的方式来为数据库写代码。希望不久现有的数据库API都能被扩展以支持这些类型的查询。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索java
数据库
java程序连接数据库、java数据库程序设计、java小程序连接数据库、纯java数据库驱动程序、java 数据库 抓阄程序,以便于您获取更多的相关知识。

时间: 2024-10-27 20:32:18

在Java程序中使用数据库的新方法_java的相关文章

Java程序中代理技术的使用方法简介

如果你这样的需求:在运行时创建实现一组给定接口的类,注意这个类是在运行时创建的,你就需要使用JAVA中的代理类来达成你的要求. 代理类提供在运行时创建类的能力,这个新建的类能实现你指定的接口. 当然你不能在运行时为要实现的接口中的方法定义新代码,而是提供一个调用处理器来实现.调用处理器是实现了InvocationHandler接口的类的对象,此接口只有一个方法: Object invoke(Object proxy,Method mtd,Object[] args) 其中proxy是代理对象:m

实例讲解Java编程中数组反射的使用方法_java

什么是反射"反射(Reflection)能够让运行于JVM中的程序检测和修改运行时的行为."这个概念常常会和内省(Introspection)混淆,以下是这两个术语在Wikipedia中的解释: 内省用于在运行时检测某个对象的类型和其包含的属性: 反射用于在运行时检测和修改某个对象的结构及其行为. 从它们的定义可以看出,内省是反射的一个子集.有些语言支持内省,但并不支持反射,如C++. 内省示例:instanceof 运算符用于检测某个对象是否属于特定的类. if (obj insta

在Java编程中使用正则表达式的基本方法_java

众所周知,在程序开发中,难免会遇到需要匹配.查找.替换.判断字符串的情况发生,而这些情况有时又比较复杂,如果用纯编码方式解决,往往会浪费程序员的时间及精力.因此,学习及使用正则表达式,便成了解决这一矛盾的主要手段.  大 家都知道,正则表达式是一种可以用于模式匹配和替换的规范,一个正则表达式就是由普通的字符(例如字符a到z)以及特殊字符(元字符)组成的文字模式,它 用以描述在查找文字主体时待匹配的一个或多个字符串.正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配.   自从jdk1

Java程序执行时间的2种简单方法_java

第一种是以毫秒为单位计算的.  Java代码  //伪代码   复制代码 代码如下: long startTime=System.currentTimeMillis();   //获取开始时间   doSomeThing();  //测试的代码段   long endTime=System.currentTimeMillis(); //获取结束时间   System.out.println("程序运行时间: "+(end-start)+"ms");  第二种是以纳秒

教你怎样在java程序中引入neo4j数据库

随着关系型数据库在某些方面的力不从心,了解当下流行的各种数据库模式的特点和性能,无疑会给我们提供更多的选择和方向. neo4j是一种图形数据库,在遍历和关联查询方面具有突出的优势.废话少说,深入了解neo4j之前,先让我们尝试一下怎样在程序中使用neo4j. neo4j采用java语言开发,如果我们要在java程序中以内嵌方式使用neo4j,只需导入neo4j的对应包即可. 首先,我们来创建一个maven项目并修改pom.xml添加对neo4j的依赖. <?xml version="1.0

如何在Java程序中访问mysql数据库中的数据并进行简单的操作_Mysql

在上篇文章给大家介绍了Myeclipse连接mysql数据库的方法,通过本文给大家介绍如何在Java程序中访问mysql数据库中的数据并进行简单的操作,具体详情请看下文. 创建一个javaProject,并输入如下java代码: package link; import java.sql.*; /** * 使用JDBC连接数据库MySQL的过程 * DataBase:fuck, table:person: * 使用myeclipse对mysql数据库进行增删改查的基本操作. */ public

Java 程序中的多线程

程序|多线程 在Java程序中使用多线程要比在 C 或 C++ 中容易得多,这是因为 Java 编程语言提供了语言级的支持.本文通过简单的编程示例来说明 Java 程序中的多线程是多么直观.读完本文以后,用户应该能够编写简单的多线程程序. 为什么会排队等待? 下面的这个简单的 Java 程序完成四项不相关的任务.这样的程序有单个控制线程,控制在这四个任务之间线性地移动.此外,因为所需的资源 - 打印机.磁盘.数据库和显示屏 -- 由于硬件和软件的限制都有内在的潜伏时间,所以每项任务都包含

介绍在Java程序中记录日志的最佳实践

本文介绍了在Java程序中记录日志的最佳实践,同时也介绍了如何使用开源软件对日志进行聚合和分析.对于现在的应用程序来说,日志的重要性是不言而喻的.很难想象没有任何日志记录功能的应用程序运行在生产环境中.日志所能提供的功能是多种多样的,包括记录程序运行时产生的错误信息.状态信息.调试信息和执行http://www.aliyun.com/zixun/aggregation/18195.html">时间信息等.在生产环境中,日志是 查找问题来源的重要依据.应用程序运行时的产生的各种信息,都应该通

在Java程序中运行外部类文件

程序 在Java程序中运行外部类文件 一.引言无论是用传统的编程语言(C++.VB等)还是Java语言编程,都经常需要在一个运行的程序中执行另外一个独立的外部程序.例如用Java设计一个IDE程序,那么这个IDE程序就必需能够调式.运行其它独立的外部Java程序.况且直接运行已经存在的外部程序来实现本程序的某些特定的功能,也是提高程序开发效率的一种重要手段.Java2为实现在一个Java程序中运行外部类文件(即Java程序)提供了的两种解决方案,即在同一进程中运行外部类文件和在不同进程中运行外部