我使用 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整合在一起?
您正在使用 PostgreSQL 生成代码,如果不区分大小写,其标识符默认为小写。对于 H2,默认大小写为大写。 jOOQ 默认情况下引用所有标识符,这就是生成的代码不能自动在两个 RDBMS 上运行的原因。
您有多种选择:
Settings.renderQuotedNames
Settings.renderNameCase