5. Micronaut Data Hibernate Reactive
Hibernate Reactive 为传统的JPA带来了响应性。
通过将 Hibernate Reactive 与 Micronaut Data 结合使用,你可以使用与仓库、JPA 标准等相同的功能,但却是以一种响应的方式。
有关 Hibernate Reactive 的更多信息,参阅官方文档。
包括 Hibernate Reactive Micronaut Data 支持:
- Gradle
- Maven
implementation("io.micronaut.data:micronaut-data-hibernate-reactive")
<dependency>
<groupId>io.micronaut.data</groupId>
<artifactId>micronaut-data-hibernate-reactive</artifactId>
</dependency>
提示
Micronaut Data 中的 Hibernate Reactive 需要 Hibernate 6。
配置与普通的 Hibernate 快速入门不同,因为 Hibernate Reactive 使用的不是传统的 JDBC 驱动,而是 Vertx 项目提供的自定义驱动。你需要为你的数据库选择一个合适的驱动:
对于 MySQL:
- Gradle
- Maven
implementation("io.vertx:vertx-mysql-client")
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-mysql-client</artifactId>
</dependency>
对于 Postgres:
- Gradle
- Maven
implementation("io.vertx:vertx-pg-client")
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-pg-client</artifactId>
</dependency>
对于 Microsoft SQLServer:
- Gradle
- Maven
implementation("io.vertx:vertx-mssql-client")
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-mssql-client</artifactId>
</dependency>
对于 Oracle:
- Gradle
- Maven
implementation("io.vertx:vertx-oracle-client")
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-oracle-client</artifactId>
</dependency>
并基于 Micronaut SQL Hibernate Reactive 支持进行配置。
- Properties
- Yaml
- Toml
- Groovy
- Hoon
- JSON
jpa.default.reactive=true
jpa.default.properties.hibernate.hbm2ddl.auto=create-drop
jpa.default.properties.hibernate.show_sql=true
jpa.default.properties.hibernate.connection.url=jdbc:mysql://localhost:3307/my_db
jpa.default.properties.hibernate.connection.username=myUser
jpa.default.properties.hibernate.connection.password=myPassword
jpa:
default:
reactive: true
properties:
hibernate:
hbm2ddl:
auto: create-drop
show_sql: true
connection:
url: jdbc:mysql://localhost:3307/my_db
username: myUser
password: myPassword
[jpa]
[jpa.default]
reactive=true
[jpa.default.properties]
[jpa.default.properties.hibernate]
[jpa.default.properties.hibernate.hbm2ddl]
auto="create-drop"
show_sql=true
[jpa.default.properties.hibernate.connection]
url="jdbc:mysql://localhost:3307/my_db"
username="myUser"
password="myPassword"
jpa {
'default' {
reactive = true
properties {
hibernate {
hbm2ddl {
auto = "create-drop"
}
show_sql = true
connection {
url = "jdbc:mysql://localhost:3307/my_db"
username = "myUser"
password = "myPassword"
}
}
}
}
}
{
jpa {
default {
reactive = true
properties {
hibernate {
hbm2ddl {
auto = "create-drop"
}
show_sql = true
connection {
url = "jdbc:mysql://localhost:3307/my_db"
username = "myUser"
password = "myPassword"
}
}
}
}
}
}
{
"jpa": {
"default": {
"reactive": true,
"properties": {
"hibernate": {
"hbm2ddl": {
"auto": "create-drop"
},
"show_sql": true,
"connection": {
"url": "jdbc:mysql://localhost:3307/my_db",
"username": "myUser",
"password": "myPassword"
}
}
}
}
}
}
Hibernate 反应式是非阻塞的,你定义的仓资源库接口和类都会扩展其中一个响应式仓库:
表 1. 内置响应式仓库接口
接口 | 描述 |
---|---|
ReactiveStreamsCrudRepository | 扩展了 GenericRepository,并添加了返回 Publisher 的 CRUD 方法 |
ReactorCrudRepository | 扩展了 ReactiveStreamsCrudRepository,并使用了 Reactor 返回类型 |
RxJavaCrudRepository | 扩展 GenericRepository 并添加可返回 RxJava 2 类型的 CRUD 方法 |
CoroutineCrudRepository | 扩展了 GenericRepository,并使用 Kotlin 例程进行反应式 CRUD 操作 |
ReactiveStreamsJpaSpecificationExecutor | 响应式 JPA 标准执行器 |
ReactorJpaSpecificationExecutor | 使用 Reactor Flux /Mono 类公开方法的响应式 JPA 标准执行器 |
下面是一个 Hibernate Reactive 仓库示例:
- Java
- Groovy
- Kotlin
@Repository // (1)
interface BookRepository extends ReactorCrudRepository<Book, Long> { // (2)
Mono<Book> find(String title);
Mono<BookDTO> findOne(String title);
Flux<Book> findByPagesGreaterThan(int pageCount, Pageable pageable);
Mono<Page<Book>> findByTitleLike(String title, Pageable pageable);
Mono<Slice<Book>> list(Pageable pageable);
@Transactional
default Mono<Void> findByIdAndUpdate(Long id, Consumer<Book> bookConsumer) {
return findById(id).map(book -> {
bookConsumer.accept(book);
return book;
}).then();
}
Mono<Book> save(Book entity);
Mono<Book> update(Book newBook);
Mono<Void> update(@Id Long id, int pages);
@Override
Mono<Long> deleteAll();
Mono<Void> delete(String title);
}
@Repository // (1)
abstract class BookRepository implements ReactorCrudRepository<Book, Long> { // (2)
abstract Mono<Book> find(String title);
abstract Mono<Page<Book>> findByTitleLike(String title, Pageable pageable);
abstract Mono<BookDTO> findOne(String title);
abstract Flux<Book> findByPagesGreaterThan(int pageCount, Pageable pageable);
abstract Mono<Slice<Book>> list(Pageable pageable);
abstract Mono<Book> save(Book entity);
@Transactional
Mono<Void> findByIdAndUpdate(Long id, Consumer<Book> bookConsumer) {
return findById(id).map(book -> {
bookConsumer.accept(book)
return book
}).then()
}
abstract Mono<Book> update(Book newBook);
abstract Mono<Void> update(@Id Long id, int pages);
@Override
abstract Mono<Long> deleteAll();
abstract Mono<Void> delete(String title);
}
@Repository // (1)
interface BookRepository : CoroutineCrudRepository<Book, Long> { // (2)
suspend fun find(title: String): Book
suspend fun findOne(title: String): BookDTO
suspend fun findByPagesGreaterThan(pageCount: Int, pageable: Pageable): List<Book>
suspend fun findByTitleLike(title: String, pageable: Pageable): Page<Book>
suspend fun list(pageable: Pageable): Slice<Book>
suspend fun save(entity: Book): Book
@Query("INSERT INTO Book(title, pages) VALUES (:title, :pages)")
suspend fun insert(title: String, pages: Int)
@Transactional
suspend fun findByIdAndUpdate(id: Long, bookConsumer: Consumer<Book?>) {
bookConsumer.accept(findById(id))
}
suspend fun update(newBook: Book): Book
suspend fun update(@Id id: Long?, pages: Int)
suspend fun delete(title: String)
}
- 接口使用 @Repository 进行注解
ReactorCrudRepository
接口接受 2 个通用参数,即实体类型(此处为Book
)和 ID 类型(此处为Long
)。
保存实例(创建)
要保存实例,请使用 ReactorCrudRepository
接口的 save
方法:
- Java
- Groovy
- Kotlin
Book book = new Book();
book.setTitle("The Stand");
book.setPages(1000);
bookRepository.save(book).block();
Book book = new Book(title:"The Stand", pages:1000)
bookRepository.save(book).block()
var book = Book(0, "The Stand", 1000)
bookRepository.save(book)
检索实例(读取)
要回读一个 book,请使用 findById
:
- Java
- Groovy
- Kotlin
book = bookRepository.findById(id).block();
book = bookRepository.findById(id).block()
book = bookRepository.findById(id)!!
更新实例(更新)
要更新实例,我们使用自定义方法在事务中进行更新:
- Java
- Groovy
- Kotlin
bookRepository.findByIdAndUpdate(id) {
it.title = "Changed"
}.block()
bookRepository.findByIdAndUpdate(id) {
it.title = "Changed"
}.block()
bookRepository.findByIdAndUpdate(id) {
it!!.title = "Changed"
}
删除实例(删除)
要删除一个实例,请使用 deleteById
:
- Java
- Groovy
- Kotlin
bookRepository.deleteById(id).block();
bookRepository.deleteById(id).block()
bookRepository.deleteById(id).block()
注意
这些示例使用 block
来检索结果,在您的应用程序中,您绝对不应该阻塞反应式存储库,因为这可能会导致性能问题,而且后盾实现可能也不支持这种阻塞。