响应式编程是一个新的流行词,它实际上仅表示异步编程或消息传递。
事实是,函数语法极大地帮助构建了异步执行链,今天,我们将看到如何使用jOOQ和新的CompletableFuture API在Java 8中做到这一点。
实际上,事情很简单:
// Initiate an asynchronous call chain
CompletableFuture// This lambda will supply an int value// indicating the number of inserted rows.supplyAsync(() -> DSL.using(configuration).insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME).values(3, "Hitchcock").execute())// This will supply an AuthorRecord value// for the newly inserted author.handleAsync((rows, throwable) -> DSL.using(configuration).fetchOne(AUTHOR, AUTHOR.ID.eq(3)))// This should supply an int value indicating// the number of rows, but in fact it'll throw// a constraint violation exception.handleAsync((record, throwable) -> {record.changed(true);return record.insert();})// This will supply an int value indicating// the number of deleted rows.handleAsync((rows, throwable) -> DSL.using(configuration).delete(AUTHOR).where(AUTHOR.ID.eq(3)).execute())// This tells the calling thread to wait for all// chained execution units to be executed.join();
这里真的发生了什么? 没有什么不寻常的。 有4个执行块:
- 插入新作者的
- 再次获取同一作者的
- 重新插入新获取的AUTHOR的代码(引发异常)
- 一种忽略引发的异常并再次删除AUTHOR的方法
最后,当执行链建立后,调用线程将使用CompletableFuture.join()
方法加入整个链,该方法与Future.get()
方法基本相同,不同之处在于它不会引发任何已检查的异常。
与其他API进行比较
诸如Scala的Slick之类的其他API也通过“标准API”实现了类似的功能,例如对flatMap()
调用。 我们目前不会模仿这样的API,因为我们相信新的Java 8 API对于本机Java讲者来说将变得更加惯用。 特别是,在执行SQL时,正确实现连接池和事务至关重要。 异步链接的执行块的语义以及它们与事务的关系非常微妙。 如果您希望一个事务跨越多个这样的块,则必须自己通过jOOQ的Configuration
及其包含的ConnectionProvider
对其进行编码。
阻止JDBC
显然,此类解决方案始终存在一个障碍,那就是JDBC本身-很难将其转变为异步API。 实际上,很少有数据库真正支持异步查询执行和游标,因为大多数情况下,单个数据库会话一次只能由单个线程用于单个查询。
翻译自: https://www.javacodegeeks.com/2014/09/asynchronous-sql-execution-with-jooq-and-java-8s-completablefuture.html