Java 8 彻底改变数据库访问(2)

支持这些函数性风格的新的数据库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理解这些代码呢?

Java 8 彻底改变数据库访问

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 集合来创建一个新的数据库查询。

Java 8 彻底改变数据库访问

生成数据库查询

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

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

美好前景

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

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/790574ea08330d4486d4d41065ba2293.html