2024-07-31
不合理的事物,未必都是显而易见的 --- 《惊悚乐园》 · 2879824237
JOOQ
在 JOOQ 中,数据库的时间类型会自动映射到相应的 Java 类型。具体映射关系如下:
- DATE:数据库中的
DATE
类型映射到 Java 的java.sql.Date
或java.time.LocalDate
。 - TIME:数据库中的
TIME
类型映射到 Java 的java.sql.Time
或java.time.LocalTime
。 - TIMESTAMP:数据库中的
TIMESTAMP
类型映射到 Java 的java.sql.Timestamp
或java.time.LocalDateTime
。 - TIMESTAMP WITH TIME ZONE:数据库中的
TIMESTAMP WITH TIME ZONE
类型映射到 Java 的java.time.OffsetDateTime
或java.time.ZonedDateTime
。 - TIME WITH TIME ZONE:数据库中的
TIME WITH TIME ZONE
类型映射到 Java 的java.time.OffsetTime
。
可以通过配置 JOOQ 来选择是使用 java.sql
包下的类还是 java.time
包下的类。例如,在 JOOQ 配置文件中,可以这样指定:
<configuration>
<generator>
<database>
<dateAsTimestamp>true</dateAsTimestamp>
</database>
<generate>
<javaTimeTypes>true</javaTimeTypes>
</generate>
</generator>
</configuration>
其中 javaTimeTypes
属性设置为 true
时,JOOQ 会使用 java.time
包下的类。如果设置为 false
,则会使用 java.sql
包下的类。
要在 Gradle 项目中配置 JOOQ,使其生成的代码可以使用自定义的 dateConverter
类来处理 SQL 时间类型到 Java 时间类型的转换,可以按照以下步骤进行配置:
-
定义 DateConverter 类: 首先 ,确保你的
DateConverter
类已定义,并且实现了 JOOQ 的Converter
接口。例如:import org.jooq.Converter;
import java.sql.Date;
import java.time.LocalDate;
public class DateConverter implements Converter<Date, LocalDate> {
@Override
public LocalDate from(Date databaseObject) {
return databaseObject == null ? null : databaseObject.toLocalDate();
}
@Override
public Date to(LocalDate userObject) {
return userObject == null ? null : Date.valueOf(userObject);
}
@Override
public Class<Date> fromType() {
return Date.class;
}
@Override
public Class<LocalDate> toType() {
return LocalDate.class;
}
} -
配置 JOOQ 代码生成器: 在
build.gradle
文件中配置 JOOQ,使其使用自定义的DateConverter
。你需要在 JOOQ 的生成配置中指定转换器。plugins {
id 'nu.studer.jooq' version '8.0'
id 'java'
}
dependencies {
implementation 'org.jooq:jooq'
jooqGenerator 'org.jooq:jooq-meta'
jooqGenerator 'org.jooq:jooq-codegen'
jooqGenerator 'com.h2database:h2' // 根据你使用的数据库替换
}
jooq {
version = '3.15.4' // 替换为你使用的 JOOQ 版本
configurations {
main {
generateSchemaSourceOnCompilation = true
generator {
name = 'org.jooq.codegen.DefaultGenerator'
database {
name = 'org.jooq.meta.h2.H2Database' // 根据你使用的数据库替换
inputSchema = 'PUBLIC'
}
target {
packageName = 'com.example.jooq'
directory = 'src/generated/java'
}
strategy {
name = 'org.jooq.codegen.DefaultGeneratorStrategy'
converters {
converter {
fromTypes = ['java.sql.Date']
toTypes = ['java.time.LocalDate']
converter = 'com.example.DateConverter'
}
// 添加其他转换器配置
}
}
}
}
}
}
// 其他配置 -
确保 DateConverter 在类路径上: 确保你的
DateConverter
类被正确编译,并且在生成 JOOQ 类时能够被找到。你可以将DateConverter
类放在src/main/java/com/example
目录下。 -
运行代码生成: 运行以下命令生成 JOOQ 代码:
./gradlew generateMainJooqSchemaSource
这将生成包含自定义转换器的 JOOQ 代码,你的数据库时间类型将自动使用 DateConverter
进行转换。
在 JOOQ 中,默认情况下会使用 JOOQ 自带的转换类来处理 SQL 时间类型到 Java 时间类型的转换。这些默认的转换类主要是针对 java.sql
和 java.time
包下的时间类型。具体来说,JOOQ 默认的转换类包括:
-
Date to LocalDate:
- 使用
org.jooq.impl.DefaultConverterProvider
提供的默认转换器。 - 具体实现为:
org.jooq.impl.DateToLocalDateConverter
。
- 使用
-
Time to LocalTime:
- 使用
org.jooq.impl.DefaultConverterProvider
提供的默认转换器。 - 具体实现为:
org.jooq.impl.TimeToLocalTimeConverter
。
- 使用
-
Timestamp to LocalDateTime:
- 使用
org.jooq.impl.DefaultConverterProvider
提供的默认转换器。 - 具体实现为:
org.jooq.impl.TimestampToLocalDateTimeConverter
。
- 使用
-
Timestamp with Time Zone to OffsetDateTime:
- 使用
org.jooq.impl.DefaultConverterProvider
提供的默认转换器。 - 具体实现为:
org.jooq.impl.TimestampWithTimeZoneToOffsetDateTimeConverter
。
- 使用
-
Time with Time Zone to OffsetTime:
- 使用
org.jooq.impl.DefaultConverterProvider
提供的默认转换器。 - 具体实现为:
org.jooq.impl.TimeWithTimeZoneToOffsetTimeConverter
。
- 使用
这些默认转换器位于 org.jooq.impl
包下,JOOQ 会根据配置自动选择合适的转换器。例如,当你在 JOOQ 配置中设置 javaTimeTypes
为 true
时,JOOQ 会使用这些默认的 Java 8 时间类型转换器。
如果你希望使用这些默认的转换器,只需确保在 JOOQ 配置中启用 javaTimeTypes
选项即可。例如:
<configuration>
<generator>
<database>
<dateAsTimestamp>true</dateAsTimestamp>
</database>
<generate>
<javaTimeTypes>true</javaTimeTypes>
</generate>
</generator>
</configuration>
这样,JOOQ 生成的代码将自动使用 java.time
包下的时间类型,并应用默认的转换器。
要在 Gradle 项目中配置 JOOQ,使其使用默认的转换器将 TIMESTAMPTZ
类型转换为 Instant
,可以通过配置 forcedType
来实现。以下是一个具体的配置示例:
-
配置 JOOQ 代码生成器: 在
build.gradle
文件中配置 JOOQ,使其使用默认的 转换器将TIMESTAMPTZ
类型映射到Instant
。plugins {
id 'nu.studer.jooq' version '8.0'
id 'java'
}
dependencies {
implementation 'org.jooq:jooq'
jooqGenerator 'org.jooq:jooq-meta'
jooqGenerator 'org.jooq:jooq-codegen'
jooqGenerator 'com.h2database:h2' // 根据你使用的数据库替换
}
jooq {
version = '3.15.4' // 替换为你使用的 JOOQ 版本
configurations {
main {
generateSchemaSourceOnCompilation = true
generator {
name = 'org.jooq.codegen.DefaultGenerator'
database {
name = 'org.jooq.meta.h2.H2Database' // 根据你使用的数据库替换
inputSchema = 'PUBLIC'
forcedTypes {
forcedType {
name = 'INSTANT'
includeTypes = 'TIMESTAMPTZ'
}
}
}
target {
packageName = 'com.example.jooq'
directory = 'src/generated/java'
}
generate {
javaTimeTypes = true
}
}
}
}
}
// 其他配置 -
强制类型映射: 在上面的配置中,
forcedTypes
部分强制将数据库中的TIMESTAMPTZ
类型映射为INSTANT
。JOOQ 将会使用默认的转换器将TIMESTAMPTZ
类型转换为java.time.Instant
。 -
运行代码生成: 运行以下命令生成 JOOQ 代码:
./gradlew generateMainJooqSchemaSource
这将生成包含自定义类型映射的 JOOQ 代码,数据库中的 TIMESTAMPTZ
类型将自动使用默认的转换器转换为 Instant
。
在 JOOQ 中,forcedType
和 strategy.converter
都可以用来处理数据库类型到 Java 类型的转换,但它们的用法和目的有所不同。以下是它们的区别:
forcedType
forcedType
用于强制将特定的数据库类型映射到特定的 Java 类型。它主要用于覆盖默认的类型映射规则。例如,当你想将数据库中的 TIMESTAMPTZ
类型映射到 java.time.Instant
时,可以使用 forcedType
来实现。
jooq {
version = '3.15.4' // 替换为你使用的 JOOQ 版本
configurations {
main {
generateSchemaSourceOnCompilation = true
generator {
name = 'org.jooq.codegen.DefaultGenerator'
database {
name = 'org.jooq.meta.h2.H2Database' // 根据你使用的数据库替换
inputSchema = 'PUBLIC'
forcedTypes {
forcedType {
name = 'INSTANT'
includeTypes = 'TIMESTAMPTZ'
}
}
}
target {
packageName = 'com.example.jooq'
directory = 'src/generated/java'
}
generate {
javaTimeTypes = true
}
}
}
}
}
strategy.converter
strategy.converter
用于在生成代码时指定自定义的转换器,以处理从数据库类型到 Java 类型的转换。它允许你提供一个自定义的转换器类,覆盖默认的转换行为。
如果你有自定义的 Converter
类,可以在 JOOQ 配置中使用 strategy.converter
来指定。例如, 你有一个自定义的 DateConverter
类,可以按如下方式配置:
jooq {
version = '3.15.4' // 替换为你使用的 JOOQ 版本
configurations {
main {
generateSchemaSourceOnCompilation = true
generator {
name = 'org.jooq.codegen.DefaultGenerator'
database {
name = 'org.jooq.meta.h2.H2Database' // 根据你使用的数据库替换
inputSchema = 'PUBLIC'
}
target {
packageName = 'com.example.jooq'
directory = 'src/generated/java'
}
strategy {
name = 'org.jooq.codegen.DefaultGeneratorStrategy'
converters {
converter {
fromTypes = ['java.sql.Timestamp']
toTypes = ['java.time.Instant']
converter = 'com.example.DateConverter'
}
}
}
generate {
javaTimeTypes = true
}
}
}
}
}
区别总结
forcedType
: 用于将数据库类型强制映射到特定的 Java 类型。主要用于覆盖默认的类型映射。strategy.converter
: 用于指定自定义的转换器类,以处理从数据库类型到 Java 类型的转换。可以更灵活 地控制转换逻辑。
在你的情况下,如果你只需要将 TIMESTAMPTZ
类型映射到 java.time.Instant
,并且可以使用 JOOQ 默认的转换器,那么使用 forcedType
即可。如果需要自定义转换逻辑,则可以使用 strategy.converter
配置自定义的转换器。
在 JOOQ 的配置中,forcedType
的 name
属性实际上是指定的目标 Java 类型,而不是 SQL 类型。这意味着你希望将特定的数据库类型映射到特定的 Java 类型。在你的例子中,name
是 varchar
,这表示目标 Java 类型是 String
,因为 varchar
在 Java 中通常对应 String
。
forcedType
配置示例解释
forcedTypes {
forcedType {
name = 'varchar'
includeExpression = '.*'
includeTypes = 'JSONB?'
}
forcedType {
name = 'varchar'
includeExpression = '.*'
includeTypes = 'INET'
}
}
name
: 这里的varchar
表示目标 Java 类型是String
。includeExpression
: 正则表达式,表示哪些表或列名称应包含在此映射规则中。.*
表示所有表和列。includeTypes
: 需要映射的数据库类型。在这个例子中,JSONB?
和INET
类型将映射为String
。
配置 TIMESTAMPTZ 到 Instant 的示例
按照你提供的例子格式,将 TIMESTAMPTZ
类型映射为 java.time.Instant
的配置如下:
jooq {
version = '3.15.4' // 替换为你使用的 JOOQ 版本
configurations {
main {
generateSchemaSourceOnCompilation = true
generator {
name = 'org.jooq.codegen.DefaultGenerator'
database {
name = 'org.jooq.meta.h2.H2Database' // 根据你使用的数据库替换
inputSchema = 'PUBLIC'
forcedTypes {
forcedType {
name = 'INSTANT' // 目标 Java 类型
includeExpression = '.*' // 包含所有表和列
includeTypes = 'TIMESTAMPTZ' // 数据库类型
}
}
}
target {
packageName = 'com.example.jooq'
directory = 'src/generated/java'
}
generate {
javaTimeTypes = true
}
}
}
}
}
总结
name
是目标 Java 类型,而不是 SQL 类型。includeExpression
是正则表达式,表示哪些表或列名称应包含在此映射规则中。includeTypes
是数据库类型,表示需要映射的数据库列类型。
通过这样的配置,JOOQ 会自动将数据库中的 TIMESTAMPTZ
类型映射为 java.time.Instant
,并使用默认的转换器进行处理。
Stream.toList()
stream.toList()
是 Java 16 引入的一个新方法,用于将流(Stream)中的元素收集到一个不可变的列表(List)中。它的功能类似于 Collectors.toList()
,但它返回的是一个不可变的列表,而不是一个可变的列表。
示例代码
以下是一个使用 stream.toList()
的示例:
import java.util.List;
import java.util.stream.Stream;
public class StreamToListExample {
public static void main(String[] args) {
Stream<String> stream = Stream.of("a", "b", "c", "d");
List<String> list = stream.toList();
System.out.println(list); // 输出: [a, b, c, d]
// list.add("e"); // 这将抛出 UnsupportedOperationException,因为返回的列表是不可变的
}
}
在这个示例中:
Stream.of("a", "b", "c", "d")
创建了一个包含"a"
,"b"
,"c"
和"d"
元素的流。stream.toList()
将流中的元素收集到一个不可变的列表中。System.out.println(list)
打印列表中的元素。
特点
- 不可变:
stream.toList()
返回的列表是不可变的,尝试修改它会抛出UnsupportedOperationException
。 - 简洁:与使用
Collectors.toList()
相比,stream.toList()
更简洁和易于使用。 - 性能:在某些情况下,
stream.toList()
可能具有更好的性能,因为它可以对一些特定的流进行优化。
版本要求
stream.toList()
是在 Java 16 中引入的,因此你需要使用 Java 16 或更高版本才能使用这个方法。
与 Collectors.toList()
的区别
Collectors.toList()
:返回一个可变的列表。stream.toList()
:返回一个不可变的列表。
根据你的需求,选择合适的方法来收集流中的元素。如果需要一个不可变的列表,可以使用 stream.toList()
;如果需要一个可变的列表,可以使用 Collectors.toList()
。
希望这个解释对你有所帮助!
JOOQ 的生成配置包含许多选项,用于控制代码生成器的行为。以下是这些选项及其功能解释:
-
indexes
:是否生成索引。<indexes>true</indexes>
-
relations
:是否生成关系。<relations>true</relations>
-
sequenceFlags
:是否生成序列标志。<sequenceFlags>true</sequenceFlags>
-
udtPaths
:是否生成 UDT 路径。<udtPaths>true</udtPaths>
-
implicitJoinPathsToOne
:是否生成单向隐式连接路径。<implicitJoinPathsToOne>true</implicitJoinPathsToOne>
-
implicitJoinPathsToMany
:是否生成多向隐式连接路径。<implicitJoinPathsToMany>true</implicitJoinPathsToMany>
-
implicitJoinPathTableSubtypes
:是否生成表子类型的隐式连接路径。<implicitJoinPathTableSubtypes>true</implicitJoinPathTableSubtypes>
-
implicitJoinPathUnusedConstructors
:是否生成未使用的隐式连接路径构造函数。<implicitJoinPathUnusedConstructors>false</implicitJoinPathUnusedConstructors>
-
implicitJoinPathsUseTableNameForUnambiguousFKs
:是否使用表名作为无歧义外键的隐式连接路径。<implicitJoinPathsUseTableNameForUnambiguousFKs>true</implicitJoinPathsUseTableNameForUnambiguousFKs>
-
implicitJoinPathsAsKotlinProperties
:是否将隐式连接路径生成为 Kotlin 属性。<implicitJoinPathsAsKotlinProperties>true</implicitJoinPathsAsKotlinProperties>
-
deprecated
:是否生成弃用注解。<deprecated>true</deprecated>
-
deprecationOnUnknownTypes
:是否在未知类型上生成弃用注解。<deprecationOnUnknownTypes>true</deprecationOnUnknownTypes>
-
instanceFields
:是否生成实例字段。<instanceFields>true</instanceFields>
-
visibilityModifier
:生成的字段和方法的可见性修饰符。<visibilityModifier>DEFAULT</visibilityModifier>
-
generatedAnnotation
:是否生成@Generated
注解。<generatedAnnotation>false</generatedAnnotation>
-
generatedAnnotationType
:生成的@Generated
注解类型。<generatedAnnotationType>DETECT_FROM_JDK</generatedAnnotationType>
-
generatedAnnotationDate
:是否在@Generated
注解中包含日期。<generatedAnnotationDate>false</generatedAnnotationDate>
-
generatedAnnotationJooqVersion
:是否在@Generated
注解中包含 JOOQ 版本。<generatedAnnotationJooqVersion>true</generatedAnnotationJooqVersion>
-
nonnullAnnotation
:是否生成非空注解。<nonnullAnnotation>false</nonnullAnnotation>
-
nonnullAnnotationType
:非空注解的类型。<nonnullAnnotationType>javax.annotation.Nonnull</nonnullAnnotationType>
-
nullableAnnotation
:是否生成可空注解。<nullableAnnotation>false</nullableAnnotation>
-
nullableAnnotationType
:可空注解的类型。<nullableAnnotationType>javax.annotation.Nullable</nullableAnnotationType>
-
constructorPropertiesAnnotation
:是否生成构造函数属性注解。<constructorPropertiesAnnotation>false</constructorPropertiesAnnotation>
-
constructorPropertiesAnnotationOnPojos
:是否在 POJO 上生成构造函数属性注解。<constructorPropertiesAnnotationOnPojos>false</constructorPropertiesAnnotationOnPojos>
-
constructorPropertiesAnnotationOnRecords
:是否在记录上生成构造函数属性注解。<constructorPropertiesAnnotationOnRecords>false</constructorPropertiesAnnotationOnRecords>
-
routines
:是否生成存储过程和函数。<routines>true</routines>
-
sequences
:是否生成序列。<sequences>true</sequences>
-
triggers
:是否生成触发器。<triggers>true</triggers>
-
udts
:是否生成 UDT(用户定义类型)。<udts>true</udts>
-
queues
:是否生成队列。<queues>true</queues>
-
links
:是否生成链接。<links>true</links>
-
keys
:是否生成主键和外键。<keys>true</keys>
-
tables
:是否生成表。<tables>true</tables>
-
embeddables
:是否生成嵌入对象。<embeddables>true</embeddables>
-
records
:是否生成记录类型。<records>true</records>
-
recordsImplementingRecordN
:是否生成实现RecordN
接口的记录类型。<recordsImplementingRecordN>false</recordsImplementingRecordN>
-
enumsAsScalaSealedTraits
:是否将枚举生成为 Scala 密封特质。<enumsAsScalaSealedTraits>false</enumsAsScalaSealedTraits>
-
pojos
:是否生成 POJO(普通旧 Java 对象)。<pojos>false</pojos>
-
pojosEqualsAndHashCode
:是否生成 POJO 的equals
和hashCode
方法。<pojosEqualsAndHashCode>true</pojosEqualsAndHashCode>
-
pojosToString
:是否生成 POJO 的toString
方法。<pojosToString>true</pojosToString>
-
pojosAsJavaRecordClasses
:是否将 POJO 生成为 Java 记录类。<pojosAsJavaRecordClasses>false</pojosAsJavaRecordClasses>
-
pojosAsScalaCaseClasses
:是否将 POJO 生成为 Scala 案例类。<pojosAsScalaCaseClasses>true</pojosAsScalaCaseClasses>
-
pojosAsKotlinDataClasses
:是否将 POJO 生成为 Kotlin 数据类。<pojosAsKotlinDataClasses>true</pojosAsKotlinDataClasses>
-
immutablePojos
:是否生成不可变的 POJO。<immutablePojos>false</immutablePojos>
-
serializablePojos
:是否生成可序列化的 POJO。<serializablePojos>true</serializablePojos>
-
interfaces
:是否生成接口。<interfaces>false</interfaces>
-
immutableInterfaces
:是否生成不可变的接口。<immutableInterfaces>false</immutableInterfaces>
-
serializableInterfaces
:是否生成可序列化的接口。<serializableInterfaces>true</serializableInterfaces>