Introduction
In this blog post we will use ReactiveMongoTransactionManager class to manage the transaction. Along with that we shall use the mongo db.
Version
- Kotlin: 1.3.71
- Spring-boot: 2.2.6.RELEASEA
- Java: 11
- mongo db: 4.2.0-rc2-bionic
Dependencies
You can use Spring Initializer to initialize the project you need following dependencies -
- Spring Reactive Web
- Spring Data Reactive MongoDB
Create docker-compose.yml file
I use docker for running the mongo db the docker compose file looks like this -
version: '3.1'
services:
mongo:
container_name: spring-reactive
image: mongo:4.2.0-rc2-bionic
ports:
- 27017:27017
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: example Configure MongoDb to the application
Add the following configurartion in the application.yml file.
spring:
data:
mongodb:
uri: mongodb://root:example@localhost:27017
database: customer
authentication-database: adminCreate a User document
Create a User class that would have an age field. You shall not allow the user to create an account if the age of the user is below 18.
@Document
data class User(
@Id
val id: String,
val age: Int
)Create a data repository for User document
interface CustomerRepo : ReactiveCrudRepository<User, String>Create a service class
Now create a service class that would have a method called saveAll. The saveAll method will accept the list of an Int array, create the user object, validate the age and the save data to the database.
fun saveAll(vararg ages: Int): Flux<User> {
return Flux.fromIterable(ages.asIterable())
.map {
User(id = UUID.randomUUID().toString(),
age = it)
}
.doOnNext { Assert.isTrue(it.age >= 18, "Age should be greater or equal to 18") }
.flatMap { userRepo.save(it) }
}Make the service transactional
To add the transactional support to the application, provide two beans transactionManager and transactionOperator to enable the transactions.
Create a transaction manager
Create a ReactiveTransactionManager that will manages the client sessions for the given ReactiveMongoDatabaseFactory
@Bean
fun transactionManager(rdbf: ReactiveMongoDatabaseFactory): ReactiveMongoTransactionManager {
return ReactiveMongoTransactionManager(rdbf)
}Create a transaction operator
Operator class that simplifies programmatic transaction demarcation and transaction exception handling. Create a new TransactionalOperator using ReactiveTransactionManager, using a default transaction.
@Bean
fun transactionOperator(rtm: ReactiveTransactionManager): TransactionalOperator {
return TransactionalOperator.create(rtm)
}Add transaction to the service
You can add the transaction by wrapping the callback in the execute method of transactionOperator like below -
val data = Flux.fromIterable(ages.asIterable())
.map {
User(id = UUID.randomUUID().toString(),
age = it)
}
.doOnNext { Assert.isTrue(it.age >= 18, "Age should be greater or equal to 18") }
.flatMap { userRepo.save(it) }
return transactionalOperator.execute{ data} OR
You can use annotation @Transactional at the method, which you want to make transactional
@Transactional
fun saveAll(vararg ages: Int): Flux<User> {Source Code Full source is available at GitHub
Vikas Blogs