当前位置: 首页 > 科技观察

Java8彻底改变了数据库访问

时间:2023-03-16 21:22:48 科技观察

Java8终于来了!经过多年的等待,java程序员终于可以在java中得到函数式编程的支持了。函数式编程支持简化现有代码并为java提供强大的能力。这些新特性中最引人注目的是Java程序员操作数据库的方式。函数式编程带来令人兴奋的简单高效的数据库API。Java8将支持与C#的兼容性,与LINQ等语言竞争的新数据库访问方法。处理数据的功能方式。Java8不仅增加了功能支持,它还通过新的处理数据的功能方式扩展了集合(Collection)类。而且通常Java在处理大量数据时需要大量的循环和迭代器。例如,假设您有一个存储Customer对象的集合:Collectioncustomers;如果您只对来自比利时的客户感兴趣,您将不会迭代所有客户对象并仅保存您需要的客户对象。Collectionbelgians=newArrayList<>();for(Customerc:customers){if(c.getCountry().equals("比利时"))belgians.add(c);}这不仅花费了5行代码,而且还不是很抽象。如果你有1000万个对象怎么办?你会通过让两个线程同时过滤所有对象来加快速度吗?那么你将不得不使用大量危险的多线程代码来重写所有代码。使用Java8,只需一行代码即可实现相同的功能。由于支持函数式编程,Java8允许您只编写一个函数来指示您对哪些客户(对象)感兴趣,然后使用该函数来过滤集合。Java8的新SteamsAPI支持您这样做:customers.stream().filter(c->c.getCountry().equals("Belgium"));上述代码的Java8版本不仅更短,而且更易于理解。它有一些陈词滥调(循环或迭代器等)。代码调用了filter()方法,可见这段代码是用来过滤客户(对象)的。您不需要在解释循环中浪费时间代码来理解它正在用它的数据做什么。如果要并发执行这段代码怎么办?您只需使用另一种类型的streamcustomers.parallelStream().filter(c->c.getCountry().equals("Belgium"));更令人兴奋的是,这种函数式代码风格也适用于数据库。在数据库上使用函数式方法传统上,程序员需要使用特殊的数据库查询语句来访问数据库。数据。例如,以下JDBC代码用于查找来自比利时的客户:PreparedStatements=con.prepareStatement("SELECT*"+"FROMCustomerC"+"WHEREC.Country=?");s.setString(1,"比利时");ResultSetrs=s.executeQuery();这些代码大部分是字符串,因此编译器无法发现错误,而且这种草率的代码会导致安全问题。还有很多样板代码使得编写数据访问代码变得非常多余。一些工具如jOOQ可以通过使用专门的java库提供数据库查询语言或者使用对象-关系映射工具来解决错误检查和安全问题,避免很多枯燥的代码,但是它们只能用于一般的访问查询,如果你需要复杂的查询,还是需要使用专门的数据库查询语言。使用Java8,您可以在流式API的帮助下以函数式方式查询数据库。例如,Jinq是一个开源项目,它探索未来的数据库API如何支持函数式编程。这是一个使用Jinq的数据库查询:customers.where(c->c.getCountry().equals("Belgium"));此代码与使用流式API几乎相同。事实上,Jinq的未来版本允许您直接使用流式API编写数据库查询。当代码运行时,Jinq会自动将其翻译成数据库查询代码,就像之前的JDBC查询一样。这样,您无需学习一些新的数据库查询语言就可以编写高效的数据库查询。您可以对Java集合使用相同风格的代码。您也不需要特殊的Java编译器或虚拟机。所有代码都在纯Java8JDK上编译和运行。如果你的代码有错误,编译器会发现它们并报告给你,就像普通的java代码一样。Jinq支持与SQL92相同的复杂查询。Selection(选择)、projection(投影)、joins(连接)、子查询都支持。java代码翻译成数据库查询的算法非常灵活,只要能接受就可以翻译。例如,Jinq能够翻译以下数据库查询,尽管它很复杂。客户.where(c->c.getCountry().equals("比利时")).where(c->{if(c.getSalary()<100000)returnc.getSalary()c.getCountry().equals("Belgium"))最初,变量customers是一个集合,其对应的数据库查询是:SELECT*FROMCustomersC然后,调用where()方法并将一个函数传递给它。在where()方法中,Jinq打开这个函数的.class文件,获取编译成这个函数的字节码进行分析。在这个例子中,我们不使用真正的字节码,而是用一些简单的指令来表示这个函数的字节码:d=c.getCountry()e=“Belgium”e=d。equals(e)returne这里,我们假设函数已经被Java编译器编译成了这4条指令。这是Jinq在where()方法被调用时看到的。Jinq如何理解这些代码?Jinq通过执行代码来分析。但Jinq不直接运行代码。它“抽象地”运行代码:Jinq没有使用真实变量和真实值,而是在代码执行时使用符号来表示所有值。这就是为什么这种分析被称为“符号执行”。Jinq执行每条指令并在程序处于状态时跟踪任何副作用或代码更改的任何内容。下图显示了Jinq在使用符号执行执行这四行代码时发现的所有副作用。符号执行示例在图中,您可以看到在运行第一条指令后,Jinq发现了两个副作用:变量d发生了变化,并且调用了Customer.getCountry()方法。由于符号执行,变量d没有被赋予真实值,例如“美国”或“丹麦”,它被赋予了c.getCountry()的符号值。在所有这些指令都被符号化执行后,Jinq简化了副作用。由于变量d和e是局部变量,在函数退出后对它们的任何更改都将被丢弃,因此这些副作用可以忽略不计。Jinq还知道Customer.getCountry()和String.equals()方法不会修改任何变量或显示任何输出,因此也可以忽略这些方法调用。由此Jinq可以得出结论,执行这个函数只会产生一个效果,它会返回c.getCountry().equals("Belgium")。一旦Jinq理解了where()方法中传递给它的函数,它就可以在客户集合之前混合它对数据库查询的了解,以创建一个新的数据库查询。生成数据库查询这就是Jinq从您的代码中生成数据库查询的方式。使用符号执行意味着这种方法对于不同Java编译器输出的不同代码模式非常健壮。如果Jinq遇到具有无法转换为数据库查询的副作用的代码,Jinq将保持您的代码不变。因为一切都是用普通的Java代码编写的,Jinq可以直接运行该代码,并且您的代码将产生预期的结果。这个简单的翻译示例应该可以让您了解如何查找翻译作品。您可以确信这些算法可以从您的代码中正确生成数据库查询。光明的未来我希望我已经让您领略了Java8带来的使用Java处理数据库的新方法。Java8支持的函数式编程让您可以像为Java集合编写代码一样为数据库编写代码。希望很快现有的数据库API将得到扩展以支持这些类型的查询。英文原文:Java8Friday:Java8WillRevolutionizeDatabaseAccess翻译链接:http://www.oschina.net/translate/java-8-friday-java-8-will-revolutionize-database-access