如何一起使用flyway + h2 + jooq codegen?

问题描述 投票:0回答:1

我使用 Flyway 和 jooq 根据我的架构迁移和生成代码。我有一个基本的迁移脚本:

CREATE TABLE BOOKS (
                       book_id  BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
                       title VARCHAR(50) NOT NULL,
                       author_last_name VARCHAR(30) NOT NULL,
                       author_first_name VARCHAR(30),
                       rating INTEGER CHECK (rating IS NULL OR (rating >= 1 and rating <= 10)),
                       UNIQUE (author_last_name, title)
);

我的 pom.xml 和插件部分如下所示:

<properties>
        <java.version>17</java.version>
        <flyway-maven-plugin.version>10.7.1</flyway-maven-plugin.version>
        <database.user>sa</database.user>   
  <database.url>jdbc:h2:file:./testdb;MODE=MSSQLServer;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS public\;set SCHEMA public</database.url>
        <database.password>password</database.password>
        <jooq.version>3.18.13</jooq.version>
        <flyway.cleanDisabled>false</flyway.cleanDisabled>
        <h2.version>2.1.214</h2.version>
        <testcontainers.version>1.19.1</testcontainers.version>
        <testcontainers-jooq-codegen-maven-plugin.version>0.0.2</testcontainers-jooq-codegen-maven-plugin.version>
    </properties>

...

<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>


            <plugin>
                <groupId>org.testcontainers</groupId>
                <artifactId>testcontainers-jooq-codegen-maven-plugin</artifactId>
                <version>${testcontainers-jooq-codegen-maven-plugin.version}</version>
                <dependencies>
                    <dependency>
                        <groupId>org.testcontainers</groupId>
                        <artifactId>postgresql</artifactId>
                        <version>${testcontainers.version}</version>
                    </dependency>
                    <dependency>
                        <groupId>org.postgresql</groupId>
                        <artifactId>postgresql</artifactId>
                        <version>42.6.0</version>
                    </dependency>
                </dependencies>
                <executions>
                    <execution>
                        <id>generate-jooq-sources</id>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <phase>generate-sources</phase>
                        <configuration>
                            <database>
                                <type>POSTGRES</type>
                                <containerImage>postgres:15.3-alpine</containerImage>
                            </database>
                            <flyway>
                                <defaultSchema>public</defaultSchema>
                                <createSchemas>true</createSchemas>
                                <locations>
                                    filesystem:src/main/resources/db/migration
                                </locations>
                            </flyway>
                            <jooq>
                                <generator>
                                    <database>
                                        <includes>.*</includes>
                                        <excludes>flyway_schema_history</excludes>
                                        <inputSchema>public</inputSchema>
                                    </database>
                                    <target>
                                        <packageName>example.micronaut.jooqtest</packageName>
                                        <directory>src/main/java</directory>
                                    </target>
                                </generator>
                            </jooq>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>build-helper-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>add-source</goal>
                        </goals>
                        <configuration>
                            <sources>
                                <source>src/main/jooq</source>
                            </sources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>


            <plugin>
                <groupId>org.flywaydb</groupId>
                <artifactId>flyway-maven-plugin</artifactId>
                <version>10.10.0</version>
                <executions>

                    <execution>
                        <id>flyway-migrate</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>migrate</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <user>${database.user}</user>
                    <password>${database.password}</password>
                    <url>${database.url}</url>
                    <password>${database.password}</password>
                    <locations>
                        <location>classpath:db/migration</location>
                    </locations>

                </configuration>
            </plugin>

        </plugins>
    </build>

最后,我有一个简单的 REST 控制器和用于添加书籍的存储库:

@Repository
public class BookRepository {

    @Autowired
    DSLContext dslContext;

    public Book addBook(Book book){
        BooksRecord booksRecord = dslContext.insertInto(Tables.BOOKS).set(toRecord(book)).returning().fetchOneInto(BooksRecord.class);
        book.setBook_id(booksRecord.getBookId());
        return book;
    }

    public List<Book> getAllBooks(){
        List<BooksRecord> booksRecords = dslContext.selectFrom(Tables.BOOKS).fetchInto(BooksRecord.class);
        return booksRecords.stream().map(this::fromRecord).collect(Collectors.toList());
    }

    public Book fromRecord(BooksRecord record){
        return Book.builder()
                .book_id(record.getBookId())
                .author_first_name(record.getAuthorFirstName())
                .author_last_name(record.getAuthorLastName())
                .rating(record.getRating())
                .build();
    }

    public BooksRecord toRecord(Book book){
        BooksRecord booksRecord = new BooksRecord();
        booksRecord.setTitle(book.getTitle());
        booksRecord.setAuthorFirstName(book.getAuthor_first_name());
        booksRecord.setAuthorLastName(book.getAuthor_last_name());
        booksRecord.setRating(book.getRating());
        return booksRecord;
    }
}

我运行了“mvn clean install”,jooq 确实为我生成了代码:

但是,当我尝试通过 Postman 发送请求来添加书籍时,出现异常:

org.h2.jdbc.JdbcSQLSyntaxErrorException: Schema "public" not found; SQL statement:
select "book_id", "title", "author_last_name", "author_first_name", "rating" from final table (insert into "public"."books" ("title", "author_last_name", "author_first_name", "rating") values (?, ?, ?, ?)) "books" [90079-214]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:632) ~[h2-2.1.214.jar:2.1.214]

然后我问 ChatGPT 如何将 JOOQ 使用的模式更改为“PUBLIC”,他给了我这个解决方案:

DataSourceConfig.java

@Configuration
public class DataSourceConfiguration {

    @Bean
    public DataSource dataSource() {
        return DataSourceBuilder.create()
                .url("jdbc:h2:file:./testdb;INIT=CREATE SCHEMA IF NOT EXISTS public\\;SET SCHEMA public;")
                .username("sa")
                .password("password")
                .driverClassName("org.h2.Driver")
                .build();
    }
}

JooqConfiguration.java

@Configuration
public class JooqConfiguration {

    @Autowired
    private DataSource dataSource;

    @Bean(name = "jooqConfig")
    public DefaultConfiguration jooqConfiguration() {
        DefaultConfiguration configuration = new DefaultConfiguration();
        configuration.set(SQLDialect.H2);
        configuration.setDataSource(dataSource);

        // Set the default schema name
        configuration.set(new Settings().withRenderSchema(false).withRenderSchema(false)
                .withRenderMapping(new RenderMapping().withSchemata(new MappedSchema().withInput("public").withOutput("PUBLIC"))));

        return configuration;
    }

    @Bean(name = "defaultDslContext")
    public DefaultDSLContext dslContext() {
        return new DefaultDSLContext(jooqConfiguration());
    }
}

但是之后当我发送 POST 请求时,我收到了不同的错误:

org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "books" not found (candidates are: "BOOKS"); SQL statement:
select "book_id", "title", "author_last_name", "author_first_name", "rating" from final table (insert into "books" ("title", "author_last_name", "author_first_name", "rating") values (?, ?, ?, ?)) "books" [42103-214]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:502) ~[h2-2.1.214.jar:2.1.214]

有没有办法让flyway+jooq+h2整合在一起?

java h2 jooq flyway jooq-codegen
1个回答
0
投票

为什么会出现这种情况

您正在使用 PostgreSQL 生成代码,如果不区分大小写,其标识符默认为小写。对于 H2,默认大小写为大写。 jOOQ 默认情况下引用所有标识符,这就是生成的代码不能自动在两个 RDBMS 上运行的原因。

如何解决问题

您有多种选择:

  • 在 H2 中创建模式与在 PostgreSQL 中完全相同,使用小写标识符。为此,您必须在 DDL 中引用所有标识符
  • 使用
    Settings.renderQuotedNames
  • 关闭 jOOQ 中的引用
  • 使用
    Settings.renderNameCase
  • 将 jOOQ 中的所有标识符转换为大写

最后两个选项记录在此处

© www.soinside.com 2019 - 2024. All rights reserved.