介绍
当您想在Java中使用SQL而不用过多的ORM时,jOOQ是一个很好的框架。 同时,它可以集成到许多环境中,因为它为您提供了许多特定于数据库的功能的支持。 一种此类特定于数据库的功能是PostgreSQL中的分区。 PostgreSQL中的分区主要是出于性能方面的考虑,因为它可以在某些情况下提高查询性能。 jOOQ没有对此功能的明确支持,但是正如我们将向您展示的,它可以很容易地集成。
本文由位于德国的jOOQ集成合作伙伴 UWS Software Service(UWS)提供 。 UWS专门从事定制软件开发,应用程序现代化和外包,并且特别关注Java Enterprise生态系统。
在PostgreSQL中分区
使用PostgreSQL的分区功能,您可以将构成一个巨大表的数据拆分为多个单独的表。 每个分区都是一个普通表,该表从父表继承其列和约束。 这种所谓的表继承可用于“范围划分”,例如,在标识符,日期或其他条件方面,一个范围的数据与另一范围的数据不重叠。
像下面的示例一样,您可以对表“ author”进行分区,该表的所有行都与表“ authorgroup”共享相同的外键。
CREATE TABLE author (
authorgroup_id int,
LastName varchar(255)
);
CREATE TABLE author_1 (
CONSTRAINT authorgroup_id_check_1
CHECK ((authorgroup_id = 1))
) INHERITS (author);
CREATE TABLE author_2 (
CONSTRAINT authorgroup_id_check_2
CHECK ((authorgroup_id = 2))
) INHERITS (author);
...
如您所见,我们设置了继承,并且(为了举一个简单的示例)我们只用一个约束检查分区是否具有相同的“ authorgroup_id”。 基本上,这将导致“作者”表仅包含表和列定义,而没有数据。 但是,当查询“ author”表时,PostgreSQL会真正查询所有继承的“ author_n”表,并返回组合结果。
使用jOOQ进行分区的简单方法
为了使用上述分区,jOOQ提供了几个选项。 您可以使用默认方式,即让jOOQ为每个表生成一个类。 为了将数据插入到多个表中,您将不得不使用不同的类。 以下代码段中使用了这种方法:
// add
InsertQuery query1 = dsl.insertQuery(AUTHOR_1);
query1.addValue(AUTHOR_1.ID, 1);
query1.addValue(AUTHOR_1.LAST_NAME, "Nowak");
query1.execute();
InsertQuery query2 = dsl.insertQuery(AUTHOR_2);
query2.addValue(AUTHOR_2.ID, 1);
query2.addValue(AUTHOR_2.LAST_NAME, "Nowak");
query2.execute();
// select
Assert.assertTrue(dsl
.selectFrom(AUTHOR_1)
.where(AUTHOR_1.LAST_NAME.eq("Nowak"))
.fetch().size() == 1);
Assert.assertTrue(dsl
.selectFrom(AUTHOR_2)
.where(AUTHOR_2.LAST_NAME.eq("Nowak"))
.fetch().size() == 1);
您会看到需要使用jOOQ生成的多个类,因此,根据您拥有的分区数量,生成的类可能会污染您的代码库。 同样,假设您最终需要遍历分区,而使用这种方法将很麻烦。 另一种方法可能是使用jOOQ通过字符串操作来构建字段和表,但这又容易出错,并且会阻止对通用类型安全性的支持。 另外,考虑要在多租户方面实现真正的数据分离的情况。
您会看到在使用分区时有一些注意事项。 幸运的是,jOOQ提供了多种处理分区表的方法,下面我们将对方法进行比较,以便您选择最适合的一种方法。
将jOOQ与分区和多租户一起使用
JOOQ的运行时模式映射通常用于实现数据库环境,例如,在开发过程中,查询一个数据库,但是当部署到生产环境时,查询将转到另一个数据库。 多租户是用于运行时模式映射的另一个推荐用例,因为它允许严格分区并配置您的应用程序以仅使用在运行时模式映射中配置的数据库或表。 因此,运行相同的代码将导致根据配置使用不同的数据库或表,从而可以根据多租户真正分离数据。
创建DSLContext时,将执行jOOQ文档中的以下配置,因此可以将其视为系统范围的设置:
Settings settings = new Settings()
.withRenderMapping(new RenderMapping()
.withSchemata(
new MappedSchema().withInput("DEV")
.withOutput("MY_BOOK_WORLD")
.withTables(
new MappedTable().withInput("AUTHOR")
.withOutput("AUTHOR_1"))));
// Add the settings to the Configuration
DSLContext create = DSL.using(
connection, SQLDialect.ORACLE, settings);
// Run queries with the "mapped" configuration
create.selectFrom(AUTHOR).fetch();
// results in SQL:
// “SELECT * FROM MY_BOOK_WORLD.AUTHOR_1”
使用这种方法,您可以将一个表永久映射到一个分区,例如。 环境“ DEV”的“ AUTHOR”到“ AUTHOR_1”。 在另一个环境中,您可以选择将“ AUTHOR”表映射到“ AUTHOR_2”。
运行时模式映射仅允许您在每个查询的基础上精确映射到一个表,因此您无法处理要操纵多个表分区的用例。 如果您想拥有更大的灵活性,则可以考虑使用下一种方法。
在分区和无多租户情况下使用jOOQ
如果需要在没有多租户的情况下处理多个表分区,则需要一种更灵活的访问分区的方法。 下面的示例显示了如何以动态和类型安全的方式进行操作,如何避免错误并以与jOOQ相同的优雅方式使用:
// add
for(int i=1; i<=2; i++) {
Builder part = forPartition(i);
InsertQuery query = dsl.insertQuery(part.table(AUTHOR));
query.addValue(part.field(AUTHOR.ID), 1);
query.addValue(part.field(AUTHOR.LAST_NAME), "Nowak");
query.execute();
}
// select
for(int i=1; i<=2; i++) {
Builder part = forPartition(i);
Assert.assertTrue(dsl
.selectFrom(part.table(AUTHOR))
.where(part.field(AUTHOR.LAST_NAME).eq("Nowak"))
.fetch()
.size() == 1);
}
上面您可以看到,分区号被抽象出来,因此您可以使用“ AUTHOR”表而不是“ AUTHOR_1”。 因此,您的代码不会被许多生成的类污染。 另一件事是, 分区程序对象是动态初始化的,因此您可以在例如上述循环中使用它。 它还遵循Builder模式,以便您可以像jOOQ一样对它进行操作。
上面的代码与第一个琐碎的代码片段完全相同,但是有很多好处,例如类型安全和对分区表的可重用访问。
无需多租户即可将jOOQ分区集成到Maven构建过程中(可选)
如果使用的是Continuous-Integration,则可以集成以上解决方案,以便jOOQ不会为分区表生成表。 这可以通过使用在生成Java类时排除某些表名的正则表达式来实现。 使用Maven时,您的集成可能看起来像这样:
<generator>
<name>org.jooq.util.DefaultGenerator</name>
<database>
<name>org.jooq.util.postgres.PostgresDatabase</name>
<includes>.*</includes>
<excludes>.*_[0-9]+</excludes>
<inputSchema>${db.schema}</inputSchema>
</database>
<target>
<packageName>com.your.company.jooq</packageName>
<directory>target/generated-sources/jooq</directory>
</target>
</generator>
然后,它只是调用mvn install,而jOOQ maven插件将在编译时生成数据库模式。
将jOOQ与PostgreSQL集成:分区
本文介绍了如何将jOOQ与PostgreSQL的分区功能结合使用来实现多租户和提高数据库性能。 PostgreSQL的文档指出,对于分区“通常只有在表很大的情况下,好处才是值得的。 表可以从分区中受益的确切时间取决于应用程序,尽管经验法则是表的大小应超过数据库服务器的物理内存。”
实现对jOOQ分区的支持就像添加配置或小型实用程序类一样容易,然后jOOQ可以支持有或没有多租户且不牺牲类型安全性的分区。 除了Java级别的集成之外,上述解决方案还可以平滑地集成到您的构建和测试过程中。
您可能需要查看partitioner实用程序类的源,该类还包括一个测试类,以便您可以更详细地了解行为和集成。
如果您需要在环境中对此或其他jOOQ集成进行支持,请告诉我们。 UWS软件服务(UWS)是jOOQ的官方集成合作伙伴 。
翻译自: https://www.javacodegeeks.com/2014/08/integrating-jooq-with-postgresql-partitioning.html