H2演进-嵌入式数据库中的窗口函数,CTE,JSON / XML

有开源项目已经成为商业上成功的主流,例如PostgreSQL / Elasticsearch。 其他公司,例如RethinkDB,失去了市场并停止了开发。 用Java编写的嵌入式数据库的H2数据库项目正在发展并处于其利基地位。


为了演示SonarQube,Jira,Confluence的功能,首次使用H2数据库。 H2是在几乎所有JVM项目中的内存中运行SQL测试的基础。 有一个用户鲜为人知的应用程序示例-这是在分布式ignite-sql中使用H2,这已经是生产准备就绪的脚本,用于将嵌入式数据库用作另一个解决方案的一部分。 不到一个月前,发布了1.4.199版本,您现在可以在其中编写相当复杂的SQL查询。

在项目中,我从来不依赖H2作为将数据保存到磁盘的完整数据库。 而是作为具有良好SQL支持的JVM内存中的数据转换模块。 但是对于此应用程序,由于缺少窗口功能而受到极大限制。 而现在,自从功能开发开始以来已经过去了半年多的时间,现在H2database已经赶上了SQLite 。 这是由于伊尔库茨克(Irkutsk)的叶夫根尼·里亚扎诺夫Yevgeny Ryazanov)的伟大功绩-在非营利性开源项目中,我从未见过像他以前那样的发展速度。 另外,其他说俄语的人的贡献也经常出现在项目资料库中。 并且在发布之时-该项目的创始人托马斯穆勒(Thomas Mueller)

H2支持递归查询(CTE) 。 这是SQL中处理表中的分层数据和查询分解的标准方法(您可以在这里使用调度程序)。 在出版物中通过示例描述递归查询。

为了处理结构不良的数据,将出现SQL / JSON标准的即将实现。 同时,出于其需求,它借助基于BaseX的自定义功能XQuery 3.1处理器扩展了H2。 该代码在github H2XQueryAdapter项目中可用。 这是一个表函数,可以使用XQuery从XML或JSON格式提取数据,并检查该函数返回的值的类型和非null的限制。 此外,SQL表达式的全部功能可用于将XQuery转换的结果转换为JVM进程内存。

表函数xquery()已重载,有两个选项-一个参数xQuery查询,一个参数xQuery查询和第二个-sql查询字符串,形成xQuery本身的参数。

生物医学数据存储项目中处理PB级原始数据的项目中,采用这种转换的方法被证明是极好的。

create table xresult (GR VARCHAR(500) not null,AR varchar, VER VARCHAR(50)) as select * from xquery('declare variable $getHeader as xs:boolean external := false(); declare variable $getData as xs:boolean external := true(); <csv> { if($getHeader) then( <record><mavengr>VARCHAR(500) not null</mavengr><artifactname>varchar</artifactname><versionname>VARCHAR(50)</versionname></record> ), if($getData) then(( for $row in doc("http://central.maven.org/maven2/org/springframework/spring-context/5.1.4.RELEASE/spring-context-5.1.4.RELEASE.pom")//*:dependency return <record><mavengr>{$row/*:groupId/text()}</mavengr><artifactname>{$row/*:artifactId/text()}</artifactname><versionname>{$row/*:version/text()}</versionname></record> )) } </csv>') 

此实现对xquery查询的格式有限制。

  • 首先,您需要声明两个外部变量getHeader和getData-这是必需的,以便表函数不会多次导致数据转换,并丢弃不必要的结果,以便仅获取列的名称和类型。 多个函数调用是H2 base的功能,可与java函数一起返回值列表。
  • 其次,结果格式应类似于csv序列化

     <csv> <record><1> </1>...<N> </N></record> <record><1></1>...<N></N></record> </csv> 
  • 第三,您需要声明数据类型,维数和必填字段,例如:十进制(20,4)不为null

通过列数据类型解析,我尝试重用H2中的SQL解析器,但事实证明它与其他数据库对象之间的联系如此紧密,以至于它拒绝创建而不创建数据库和会话就无法工作。 我想到开发人员这样做是为了简化应用程序的设计,而不是在所有场合下都无法为任何BNF语法创建解析器,这使我感到欣慰。

您可以在Java调试模式下运行此示例 。 可以在熟悉的xquery编辑器或开源BaseX GUI中开发新的转换规则。

几乎可以将所有Java集合或POJO转换为虚拟H2表。 github上的H2POJOTable项目代码 。 在示例中,通过引用,基于平台的MemoryManagerMXBeans变成了H2表函数。 对于那些对缺少LINQ和对Java集合中的操作的支持感到悲伤的人来说,这种方法可能会有些安慰。

 try (Statement statement = connection.createStatement()) { String pojoTableAlias = "create alias MemoryManagerMXBeans as $$ \n" + "import java.lang.management.ManagementFactory;\n" + "import java.lang.management.MemoryManagerMXBean;\n" + "import org.h2.expression.function.pojo.*;\n" + "import java.sql.*;\n" + "import java.util.Collections;\n" + "@CODE\n" + " ResultSet getRuntimeStat(Connection connection) throws Exception{\n" + " return H2PojoAdapter.toTable(connection, new CollectionWraper<>(MemoryManagerMXBean.class," + " ManagementFactory::getMemoryManagerMXBeans, Collections.emptyMap()));\n" + " }\n" + "\n$$"; statement.executeUpdate(pojoTableAlias); } try (Statement statement = connection.createStatement()) { try (ResultSet resultSet = statement.executeQuery("select * from MemoryManagerMXBeans()")) { int columnCount = assertResultSet(resultSet, new String[]{"memoryPoolNames", "name", "valid"}); assertThat(columnCount).isGreaterThan(1); } } 

有时,H2中的旧功能崩溃了,用户并没有那么要求。 例如,在我的工作项目中,程序从AWS S3 URL读取数据。 因此,我希望可以通过接受我的pull request 来解决已知错误。 修正此错误的方法是对TLS的不稳定测试,这些测试在Java 11下也无法正常工作。

H2允许您使用ODBC驱动程序PostgreSQL模拟其网络协议的子集。 从理论上讲,这也允许您通过PostgreSQL中的FDW进行绑定。

除了数据库本身,H2的交付还包括一个极简的Web控制台,该控制台支持在编辑时自动完成,Servlet或独立启动选项。 对于开发人员来说,H2就像一把“瑞士刀”-如果您的项目已经使用JVM,则它是一种紧凑而通用的工具。 当尝试通过“弯曲的” jdbc驱动程序使用此控制台时,DBMS Redshift向项目发出了第一个红眼的请求。 项目参与者之一Noel Grandin帮助我进行了代码审查并接受了更正。

如果您需要Berkeley DB Java Edition的类似产品-该项目具有MVStore-持久存储键值数据,并且与MVCC结合使用,默认情况下,数据库的最新版本中为“引擎”。 令人惊讶的是,该数据库甚至对地理功能全文搜索具有基本支持。

感谢H2database的贡献者,每个人都使用此数据库并报告错误! H2数据库自2005年以来一直在开发,现在支持窗口函数,递归查询,它是处理JVM内存中数据的最强大的SQL“引擎”之一,并通过表函数进行了扩展以处理松散结构的数据。

Source: https://habr.com/ru/post/zh-CN446380/


All Articles