跳到主要内容

Micronaut SQL 库

在 Micronaut 中支持 SQL 数据库访问的项目

1. 简介​

本项目包括在 Micronaut 中支持 SQL 数据库访问的模块。

2. 发布历史​

你可以在这里找到这个项目的发布列表(包含发布说明):

https://github.com/micronaut-projects/micronaut-sql/releases

3. 配置 JDBC​

Java 数据源可配置为当前提供的三种实现之一。默认支持 Apache DBCP2、Hikari 和 Tomcat。

提示

使用 CLI

如果使用 Micronaut CLI 创建项目,请提供 jdbc-tomcat、jdbc-hikari、jdbc-dbcp 或 jdbc-ucp 功能之一,以便在项目中预先配置简单的 JDBC 连接和默认的 H2 数据库驱动:

如果使用 Micronaut CLI 创建项目,请提供 jdbc-tomcat、jdbc-hikari、jdbc-dbcp 或 jdbc-ucp 功能之一,以便在项目中预先配置简单的 JDBC 连接和默认的 H2 数据库驱动程序:

要开始使用,只需在与要使用的实现相对应的 JDBC 配置中添加一个依赖即可。请选择以下之一:

runtimeOnly("io.micronaut.sql:micronaut-jdbc-tomcat")
runtimeOnly("io.micronaut.sql:micronaut-jdbc-hikari")
runtimeOnly("io.micronaut.sql:micronaut-jdbc-dbcp")
runtimeOnly("io.micronaut.sql:micronaut-jdbc-ucp")

你还需要在类路径中添加 JDBC 驱动程序依赖关系。例如,添加 H2 内存数据库:

runtimeOnly("com.h2database:h2")

3.1 配置 JDBC 连接池​

可以配置所有具体实现参数。我们努力使基本配置在不同实现之间保持一致。

  • Hikari:除了 jdbcUrl 之外,还可以通过 url 配置 URL。除 dataSourceJNDI 外,还可通过 jndiName 配置 JNDI 名称。
  • Tomcat:除了 dataSourceJNDI 外,还可通过 jndiName 配置 JNDI 名称。

如果未提供配置选项,将计算多个配置选项。

URL将在 class path 中搜索嵌入式数据库驱动程序。如果找到,URL 将设置为该驱动的默认值。
Driver Class如果配置了 URL,驱动程序类将从 URL 派生,否则将在类路径中搜索嵌入式数据库驱动。如果找到,将使用该驱动的默认类名。
Username如果配置的数据库驱动是嵌入式的,则用户名将设置为 "sa"。
Password如果配置的数据库驱动是嵌入式的,密码将设置为空字符串。

例如:

datasources.default.url=jdbc:h2:mem:default;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
datasources.default.username=sa
datasources.default.password=
datasources.default.driverClassName=org.h2.Driver

要使用 Oracle UCP,请提供与下面类似的配置:

datasources.default.url=null
datasources.default.connectionFactoryClassName=oracle.jdbc.pool.OracleDataSource
datasources.default.username=null
datasources.default.password=null
datasources.default.minPoolSize=1
datasources.default.maxPoolSize=10

Oracle UCP 由 UniversalConnectionPoolManager 管理。可以通过将 ucp-manager.enabled 设置为 false 来禁用该管理器。此外,还可以通过将 ucp-manager.jmx.enabled 设置为 true 并提供 ojdbc8dms.jar 和 dms.jardependencies 来启用基于 JMX 的管理。

有关可配置的其他属性列表,参考正在使用的实现。所有设置方法都可进行配置。

TomcatPoolProperties
HikariHikariConfig
Apache DBCPBasicDataSource
Oracle UCPPoolDataSource

3.2 配置多个数据源​

要注册多个数据源,只需将它们配置为不同的名称即可。

datasources.default=...
datasources.warehouse=...

在注入 DataSource Bean 时,将注入名称为 "default "的 Bean,除非注入时限定了配置名称。如果没有名为 "default "的配置,那么所有的 Bean 都不会是主要的,因此所有注入都必须加以限定。例如:

@Inject DataSource dataSource // "default" will be injected
@Inject @Named("warehouse") DataSource dataSource // "warehouse" will be injected

3.3 JDBC 健康检查​

一旦配置了 JDBC DataSource,JdbcIndicator 就会被激活,从而产生 /health 端点和 CurrentHealthStatus 接口,解析 JDBC 连接的健康状况。

有关详细信息,参阅健康端点部分。

4. 配置 Hibernate​

设置 Hibernate/JPA EntityManager

提示

使用 CLI

如果使用 Micronaut CLI 创建项目,请提供 hibernate-jpa 特性,以便在项目中包含 Hibernate JPA 配置:

$ mn create-app my-app --features hibernate-jpa

Micronaut 内置了对配置 Hibernate/JPA EntityManager 的支持,它建立在对 SQL 数据源支持的基础之上。

一旦配置了一个或多个数据源以使用 Hibernate,就需要在构建配置中添加 hibernate-jpa 依赖:

implementation("io.micronaut.sql:micronaut-hibernate-jpa")

以及 Micronaut 数据事务 Hibernate 依赖:

[dependency:micronaut-data-tx-hibernate="io.micronaut.data"]。

就是这样。对于每个注册的 SQL DataSource,Micronaut 将使用 EntityManagerFactoryBean 配置以下 Bean:

4.1 禁用 Micronaut Hibernate JPA​

你可以禁用 Micronaut Hibernate JPA,例如在测试中,设置 jpa.enabled 为 false。

4.2 注入 EntityManager 或 Hibernate 会话​

你可以使用 javax.persistence.PersistenceContext 注解来注入 EntityManager(或 Hibernate Session)。为此,你需要确保 JPA 注解位于构建中的 annotationProcessor 路径上:

在 Gradle 中为 annotationProcessor 添加 JPA 依赖

annotationProcessor "jakarta.persistence:jakarta.persistence-api:2.2"

使用 @PersistenceContext

@PersistenceContext
EntityManager entityManager;

@PersistenceContext(name = "other")
EntityManager otherManager;

当使用 @Transactional 时,Micronaut 将注入一个编译时作用域的代理,以检索与当前事务相关联的 EntityManager(请参阅下面的 "使用 Spring 事务管理")。

请注意,上述示例使用的是字段注入,因为 @PersistenceContext 注解不支持构造函数或方法参数的参数声明。因此,如果想使用构造函数或方法注入,就必须使用 @CurrentSession 注解:

使用 @CurrentSession 进行构造函数注入

public MyService(@CurrentSession EntityManager entityManager) {
this.entityManager = entityManager;
}

4.3 定制 Hibernate/JPA 配置​

定制和配置会话工厂(SessionFactory)有几种不同的方法。最简单的方法是通过配置。下面的配置演示了一个例子:

配置 Hibernate 属性

datasources.default.name=mydb
jpa.default.entity-scan.packages[0]=foo.bar
jpa.default.entity-scan.packages[1]=foo.baz
jpa.default.properties.hibernate.hbm2ddl.auto=update
jpa.default.properties.hibernate.show_sql=true

上面的示例配置了要扫描的包,并设置了要传递给 Hibernate 的属性。正如你所看到的,这些都是以每个 DataSource 为基础完成的。有关可用的选项,请参阅 JpaConfiguration 配置类。

如果需要进一步控制 SessionFactory 的创建方式,可以注册 BeanCreatedEventListener Bean,监听会话 SessionFactoryBuilder、 MetadataSources 等的创建,并在监听器中应用自定义配置。

你还可以选择创建 Integrator 和 Interceptor 类型的 Bean,这些 Bean 将被自动接收和注入。

4.4 实体扫描配置​

自本库 1.2 版起,实体扫描配置变得更加灵活,可以在 GraalVM 底层上进行无反射扫描。

默认配置将查找 Micronaut 编译的所有包含 @Entity 注解的类。

如果你想限制包含在特定 JPA 实体管理器中的包,可以使用 entity-scan 配置选项:

限制实体扫描

datasources.default.url=jdbc:h2:mem:default;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
datasources.default.username=sa
datasources.default.password=
datasources.default.driverClassName=org.h2.Driver

要使用 Oracle UCP,请提供与下面类似的配置:

jpa.default.entity-scan.packages[0]=foo.bar

上述配置将搜索范围限制在 foo.bar 包中的类。请注意,如果类没有被 Micronaut 编译,它们将不会被找到。有两种方法可以解决这个问题,一种是为外部类生成自省元数据。例如,你可以在 Application 类中加入这个元数据:

为外部类生成自省元数据

@Introspected(packages="foo.bar")

这将为 foo.bar 包中的所有类生成自省元数据。

如果此选项不适合你,你也可以使用 classpath 属性启用全类路径扫描:

启用全类路径扫描

datasources.default.url=jdbc:h2:mem:default;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
datasources.default.username=sa
datasources.default.password=
datasources.default.driverClassName=org.h2.Driver

要使用 Oracle UCP,请提供与下面类似的配置:

jpa.default.entity-scan.classpath=true
jpa.default.entity-scan.packages[0]=foo.bar

请注意,这种方法有以下缺点:

  • 速度较慢,因为 Micronaut 必须搜索 JAR 文件并使用 ASM 扫描类文件
  • 无法在 GraalVM 底层运行。

4.5 配置 Hibernate 响应式​

通过添加以下依赖,可以使用 Hibernate Reactive:

implementation("io.micronaut.sql:micronaut-hibernate-reactive")

以及 Micronaut 数据事务 Hibernate 依赖:

[dependency:micronaut-data-tx-hibernate="io.micronaut.data"]。

注意

Hibernate Reactive 需要 Java 11

要启用响应式会话工厂,JPA 配置需要将 reactive 属性设为 true。响应式实现不使用传统的 JDBC 驱动,而是使用 Vertx 驱动。

你可以添加以下选项之一:

implementation("io.vertx:vertx-mysql-client")
implementation("io.vertx:vertx-pg-client")
implementation("io.vertx:vertx-mssql-client")
implementation("io.vertx:vertx-oracle-client")

并使用属性对其进行配置:

jpa.default.reactive=true
jpa.default.properties.hibernate.connection.url=jdbc:postgresql:database
jpa.default.properties.hibernate.connection.username=myUsername
jpa.default.properties.hibernate.connection.password=myPassword

另一种方法是加入现有的 Micronaut SQL 支持库:

implementation("io.micronaut.sql:micronaut-vertx-mysql-client")
implementation("io.micronaut.sql:micronaut-vertx-pg-client")

并配置客户端:

vertx.pg.client.port=5432
vertx.pg.client.host=the-host
vertx.pg.client.database=the-db
vertx.pg.client.user=user
vertx.pg.client.password=secret
vertx.pg.client.max-size=10

集成将自动集成在 bean 上下文中找到的 io.vertx.sqlclient.Pool 的 Vertx 驱动实例。

4.6 使用编译时 Hibernate 代理​

Hibernate 使用代理对象来实现懒加载,默认实现是在运行时生成一个代理。

这样做有几个缺点:

  • 运行时类生成会影响启动和运行性能
  • 不支持 GraalVM 等环境

如果希望使用懒实体关联并避免运行时代理,可以启用编译时代理:

jpa:
default:
compile-time-hibernate-proxies: true

编译时代理要求需要代理的实体使用 @GenerateProxy 注解:

例如:

@Entity
public class Pet {

@ManyToOne(fetch = FetchType.LAZY)
private Owner owner;

//...
}

实体 Owner 需要注解 @GenerateProxy 才能在编译时生成代理。

@Entity
@GenerateProxy
public class Owner {
//...
}

GraalVM 环境默认启用编译时代理。

4.7 理解 LazyInitializationException​

Micronaut 基于 Netty 构建,而 Netty 基于非阻塞的事件循环模型。JDBC 和 Hibernate 是阻塞式 API,因此在 Micronaut 应用程序中使用它们时,工作会转移到阻塞式 I/O 线程池中。

当使用 @Transactional 时,Hibernate 会话将只在该方法执行期间打开,然后自动关闭。这样可以确保阻塞操作尽可能短。

Micronau t中没有 OpenSessionInView(OSIV)的概念,以后也不会有,因为它是次优的且不推荐使用。你应该通过使用适当的连接查询或数据传输对象(DTO)来优化你编写的查询,以返回 Micronaut 将对象编码为 JSON 所需的所有必要数据。

如果在从方法返回 Hibernate 实体时遇到 LazyInitializationException,这表明你的查询是次优的,你应该执行 join。

5. 配置 JAsync SQL​

Micronaut 支持使用 jasync-sql 异步访问 PostgreSQL 和 MySQL,允许使用单线程处理多个数据库连接。

5.1 配置 jasync-sql 客户端​

提示

使用 CLI

如果使用 Micronaut CLI 创建项目,请使用 jasync-sql 特性在项目中配置 Jasync PostgreSQL 和 MySQL 客户端:

$ mn create-app my-app --features jasync-sql

要配置 Jasync 客户端,首先应在 classpath 中添加 jasync-sql 模块:

implementation("io.micronaut.sql:micronaut-jasync-sql")

然后,应配置希望与之通信的数据库服务器的 PoolOptions:

jasync.client.port=5432
jasync.client.host=the-host
jasync.client.database=the-db
jasync.client.username=test
jasync.client.password=test
jasync.client.maxActiveConnections=5

完成上述配置后,就可以注入 com.github.jasync.sql.db.Connection Bean。下面是最简单的连接方法:

result = client.sendQuery('SELECT * FROM pg_stat_database').thenApply({ QueryResult resultSet -> (1)
return "Size: ${resultSet.rows.size()}"
}).get()
  1. 客户端是 com.github.jasync.sql.db.Connection bean 的实例。

有关使用客户端运行查询的更多信息,阅读 jasync-sql 文档中的 "运行查询 "部分。

要使用 Jasync 查询拦截器,请注册 com.github.jasync.sql.db.interceptor.QueryInterceptor 类型的 Bean。

5.2 数据库健康检查​

当 jasync-sql 模块被激活时,JasyncHealthIndicator 会被激活,导致 /health 端点和 CurrentHealthStatus 接口解析连接的健康状况。

唯一支持的配置选项是通过 endpoints.health.jasync.enabled 关键字启用或禁用指示器。

更多信息,参阅健康端点部分。

6. 配置 jOOQ​

Micronaut 支持为流畅、类型安全的 SQL 查询构造自动配置 jOOQ 库。

要配置 jOOQ 库,首先应在类路径中添加 jooq 模块:

implementation("io.micronaut.sql:micronaut-jooq")

然后,你应该配置一个或多个数据源。对于每个注册的数据源,Micronaut 将使用 JooqConfigurationFactory 配置以下 jOOQ Bean:

如果使用了 Spring 事务管理,它将额外创建以下 Bean:

6.1 配置 SQL 方言​

Micronaut 将尝试自动检测数据库 SQLDialect。

如果效果不佳,可以通过配置属性手动提供 SQL 方言。下面的示例为默认数据源配置了方言:

配置 SQL 方言

jooq.datasources.default.sql-dialect=POSTGRES

6.2 配置其他提供程序 Bean​

你可以定义附加 Bean,这些 Bean 将在创建 jOOQ Configuration 时使用。只有与数据源名称限定符相同的 bean 才会被使用。

Micronaut 将查找以下 Bean 类型:

6.3 使用 ObjectMapper 转换 JSON(B) 类型​

如果你没有注册 ConverterProvider 类型的 bean 并提供以下配置,JacksonConverterProvider 将被使用,它使用 Micronaut 配置的 ObjectMapper 转换 JSON 和 JSONB 类型。

配置 Micronaut Jackson 转换器

jooq:
datasources:
default:
jackson-converter-enabled: true

6.4 GraalVM 本地镜像​

要在本地镜像中使用 JOOQ,就必须为反射声明 Record 类。最简单的方法是配置 jOOQ,启用 jpaAnnotations 选项,用 JPA 注解来注解生成的类。这样 Micronaut 就能检测到它们,并自动生成 GraalVM 所需的反射配置。

例如,如果使用此 gradle 插件,可以添加以下内容:

jooq {
devDb(sourceSets.main) {
...
generator {
...
generate {
jpaAnnotations = true (1)
}
}
}
}
  1. 配置 jOOQ 以生成 JPA 注解。

在本地镜像中使用 SimpleFlatMapper 和 jOOQ 时也有内置支持。无需额外配置,只需添加 SimpleFlatMapper 依赖即可:

implementation("org.simpleflatmapper:sfm-jdbc:8.2.3")

更多信息,参阅 jOOQ 文档。

7. 配置 Jdbi​

Micronaut 支持自动配置 Jdbi 库,以方便、习惯性地访问关系数据。

要配置 Jdbi 库,首先应将 jdbi 模块添加到类路径中:

implementation("io.micronaut.sql:micronaut-jdbi")

然后,你应该配置一个或多个数据源。对于每个注册的 DataSource,Micronaut 将使用 JdbiFactory 配置以下 Jdbi bean:

  • Jdbi —— Jdbi 实例

如果使用的是 Spring 事务管理,它将额外创建以下 bean :

7.1 配置其他提供程序 Bean​

你可以定义其他 Bean,这些 Bean 将在创建 Jdbi 对象时使用。只有名称限定符名称与数据源名称相同的 Bean 才会被使用。

Micronaut 将查找以下 bean 类型:

8. 配置响应式 MySQL 客户端​

Micronaut 支持使用 vertx-mysql-client 连接到 MySQL 的响应式和非阻塞客户端,允许使用单线程处理多个数据库连接。

提示

使用 CLI

如果使用 Micronaut CLI 创建项目,请使用 vertx-mysql-client 特性在项目中配置 MySQL Vertx 客户端:

$ mn create-app my-app --features vertx-mysql-client

要配置 MySQL Vertx 客户端,首先应在类路径中添加 vertx-mysql-client 模块:

implementation("io.micronaut.sql:micronaut-vertx-mysql-client")

然后,应在 application.yml 中配置要与之通信的 MySQL 服务器的 URI 或 MySQLConnectOptions、PoolOptions:

application.yml

vertx:
mysql:
client:
port: 3306
host: the-host
database: the-db
user: test
password: test
maxSize: 5
提示

你也可以使用 uri 而不是其他属性来连接 MySQL。

完成上述配置后,就可以注入 io.vertx.reactivex.mysqlclient.MySQLPool bean。下面是最简单的连接方法:

result = client.query('SELECT * FROM foo').rxExecute().map({ RowSet<Row> rowSet -> (1)
RowIterator<Row> iterator = rowSet.iterator()
int id = iterator.next().getInteger("id")
return "id: ${id}"
}).blockingGet()
  1. client 是 io.vertx.reactivex.mysqlclient.MySQLPool bean 的实例。

有关使用响应式客户端在 MySQL 上运行查询的更多信息,阅读 vertx-mysql-client 文档中的"运行查询"部分。

8.1 MySQL 健康检查​

激活 vertx-mysql-client 模块后,MySQLClientPoolHealthIndicator 将被激活,从而通过 /health 端点和 CurrentHealthStatus 接口解析 MySQL 连接的健康状况。

支持的唯一配置选项是通过 endpoints.health.vertx.mysql.client.enabled 关键字启用或禁用指示器。

更多信息,参阅健康端点章节。

9. 配置响应式 PostgreSQL 客户端​

Micronaut 支持使用 vertx-pg-client 连接 PostgreSQL 的响应式非阻塞客户端,允许使用单线程处理多个数据库连接。

提示

使用 CLI

如果使用 Micronaut CLI 创建项目,请使用 vertx-pg-client 特性在项目中配置 PostgreSQL Vertx 客户端:

$ mn create-app my-app --features vertx-pg-client

要配置 PostgreSQL Vertx 客户端,应首先在类路径中添加 vertx-pg-client 模块:

implementation("io.micronaut.sql:micronaut-vertx-pg-client")

然后,应配置希望与之通信的 PostgreSQL 服务器的 URI 或 PgConnectOptions、PoolOptions:

vertx.pg.client.port=3306
vertx.pg.client.host=the-host
vertx.pg.client.database=the-db
vertx.pg.client.user=test
vertx.pg.client.password=test
vertx.pg.client.maxSize=5
提示

你也可以使用 uri 而不是其他属性来连接 PostgreSQL。

完成上述配置后,就可以注入 io.vertx.reactivex.pgclient.PgPool bean。下面是最简单的连接方法:

result = client.query('SELECT * FROM pg_stat_database').rxExecute().map({ RowSet<Row> rowSet -> (1)
int size = 0
RowIterator<Row> iterator = rowSet.iterator()
while (iterator.hasNext()) {
iterator.next()
size++
}
return "Size: ${size}"
}).blockingGet()
  1. client 是 io.vertx.reactivex.pgclient.PgPool bean 的实例。

有关使用响应式客户端在 Postgres 上运行查询的更多信息,阅读 vertx-pg-client 文档中的"运行查询"部分。

9.1 PostgreSQL 健康检查​

当 vertx-pg-client 模块被激活时,PgClientPoolHealthIndicator 会被激活,导致 /health 端点和 CurrentHealthStatus 接口解析 Postgres 连接的健康状况。

唯一支持的配置选项是通过 endpoints.health.vertx.pg.client.enabled 关键字启用或禁用该指示器。

更多信息,参阅健康端点章节。

10. 仓库​

你可以在此仓库中找到此项目的源代码:

https://github.com/micronaut-projects/micronaut-sql

英文链接