关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » JAVA »Java 8 彻底改变数据库访问

    Java 8 彻底改变数据库访问

    2014-08-12 00:00:00 出处:ITJS
    分享

    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 = &#8220;Belgium&#8221; 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都能被扩展以支持这些类型的查询。

    来自:oschina

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    正版 Windows 11产品密钥怎么查找/查看?

    还有3个月,微软将停止 Windows 10 的更新

    Windows 10 终止支持后,企业为何要立即升级?

    Windows 10 将于 2025年10 月终止技术支持,建议迁移到 Windows 11

    Windows 12 发布推迟,微软正全力筹备Windows 11 25H2更新

    Linux 退出 mail的命令是什么

    Linux 提醒 No space left on device,但我的空间看起来还有不少空余呢

    hiberfil.sys文件可以删除吗?了解该文件并手把手教你删除C盘的hiberfil.sys文件

    Window 10和 Windows 11哪个好?答案是:看你自己的需求

    盗版软件成公司里的“隐形炸弹”?老板们的“法务噩梦” 有救了!

    IT头条

    公安部:我国在售汽车搭载的“智驾”系统都不具备“自动驾驶”功能

    02:03

    液冷服务器概念股走强,博汇、润泽等液冷概念股票大涨

    01:17

    亚太地区的 AI 驱动型医疗保健:2025 年及以后的下一步是什么?

    16:30

    智能手机市场风云:iPhone领跑销量榜,华为缺席引争议

    15:43

    大数据算法和“老师傅”经验叠加 智慧化收储粮食尽显“科技范”

    15:17

    技术热点

    商业智能成CIO优先关注点 技术落地方显成效(1)

    用linux安装MySQL时产生问题破解

    JAVA中关于Map的九大问题

    windows 7旗舰版无法使用远程登录如何开启telnet服务

    Android View 事件分发机制详解

    MySQL用户变量的用法

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。