How to disable Postgres auto-commit in Spring Data R2DBC - postgresql

I see that currently, you can disable auto-commit on Connection object. But when you work with Spring Data you don't have access to Connection object.
Also, Postgres doesn't have this feature as part of the connection URL.
Does anyone know how to turn off it permanently?

I do not know if there is a way to disable it permanently but you could go a bit low-level and use Connection object to set auto-commit feature:
#Autowired
private ConnectionFactory connectionFactory;
public Flux<Integer> insertSmth() {
return Mono.from(connectionFactory.create())
.flatMapMany(connection ->
Flux.from(connection.setAutoCommit(false))
.thenMany(connection.beginTransaction())
.thenMany(connection.createStatement("INSERT INTO ...").execute())
...
}
Edit:
I seems propagation and reset of Auto-Commit and Isolation Level control through TransactionDefinition is available in Spring Data R2DBC 1.0.0 RC1.
See this thread: https://github.com/r2dbc/r2dbc-spi/pull/95

Related

Issue connecting to SQL server using R2DBC and encrypted connection

Did anyone was able to connect to database using Spring boot, R2DBC and encrypted connection
I have a connection string:
jdbc:sqlserver://XXX.XX.XXXX:1433;encrypt=true;trustServerCertificate=true;databaseName=ABC
I am using connection factory builder class and parsed arguments as shown below:
public ConnectionFactory connectionFactory() {
final ConnectionFactoryOptions options = builder()
.option(DRIVER, "sqlserver")
.option(HOST, applicationDatabaseProperties.getHost())
.option(PORT, applicationDatabaseProperties.getPort())
.option(USER, applicationDatabaseProperties.getUsername())
.option(PASSWORD, applicationDatabaseProperties.getPassword())
.option(DATABASE, applicationDatabaseProperties.getDatabase())
.option(SSL, true)
.build()
return ConnectionFactories.get(options);
}
It gives me a runtime SSL error when I am trying to connect
I tried to add an option as shown below - I saw it in the documentation:
.option(Option.valueOf("[trustServerCertificate]","[true]"))
but compiler gives the error(using it from Kotlin code), I decompiled original class io.r2dbc.spi.ConnectionFactoryOptions
and trustServerCertificate is not listed as a constant
Any help would be greatly appreciated
Thanks, Sam
Tried adding the option .option(Option.valueOf("[trustServerCertificate]","[true]")) to the builder,
compiler returns the error

Not able to set keepAliveTime config for Hikari in SpringBoot

I have an spring-boot based application that connects to postgres DB. It uses the default HikariCP as JDBC connection pool. From the documentation I see that we can configure a property keepALiveTime which I think is useful to us but I am not able to set it in my yml file. It looks like this
datasource:
jdbc-url: jdbc:postgresql://x.x.x.x:5433/xxx?sslmode=require&sslcert=/file.crt&sslkey=/tmp/file.key
username: ${JDBC_USERNAME}
password: ${JDBC_PASSWORD}
keepaliveTime: 80000
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate.format_sql: true
hibernate.dialect: org.hibernate.dialect.PostgreSQL81Dialect
hikari:
idle-timeout: 500000
minimum-idle: 10
maximum-pool-size: 15
keepaliveTime: 80000
max-lifetime: 48000
connection-timeout: 180000
All other configs are auto suggested and are able to be used. But keepAliveTime option is not available for me to populate. Although I am providing it in the configs Hikari doesn't use it.
keepAliveTime parameter arrived in HikariCP 4.0.0. In order to use it with older version of spring boot - we can exclude the HikariCP dependency from where it is being read and explicitly the version that we want. Its not recommended but I found no issues using 4.0.0 version with spring boot version 2.3.0-Release
To remove the dependency
implementation('org.springframework.boot:spring-boot-starter-data-jpa') {
exclude group: 'com.zaxxer', module: 'HikariCP'
}
To add the dependency
implementation('com.zaxxer:HikariCP:4.0.3') {
force=true
}
I added the keepAliveTime in DataSource Configuration file
public HikariDataSource dataSource() {
HikariDataSource h = DataSourceBuilder.create().type(HikariDataSource.class).build();
System.out.println(h.getJdbcUrl());
h.setKeepaliveTime(100000l);
h.setJdbcUrl("yufuyfuyfu");
System.out.println(h.getJdbcUrl());
return h;
}
please notice that keepAliveTime should be less than maxLifeTime, from HikariCP docs:
This property controls how frequently HikariCP will attempt to keep a connection alive, in order to prevent it from being timed out by the database or network infrastructure. This value must be less than the maxLifetime value

Javers async commit into Mongo DB

Looking for some proper documentation on async commit for mongo db . We have a spring boot app where we are trying to generate audits for our domain objects , we would like to commit the audits generated by javers into mongo db asynchronously while our main SQL based transaction is fr of this mongodb call. Any pointers on this would be really helpful.
If you are using the Javers Spring Boot Mongo starter, you can simply put the #JaversAuditableAsync ann on a repository method.
There are limitations:
It works only with Mongo and there is no integration for magical-autogenerated ReactiveMongoRepository yet. So you have to put the #JaversAuditableAsync on an actual method which does the save.
#Repository
interface DummyObjectReactiveRepository
extends ReactiveMongoRepository<DummyObject, String> { }
...
#Repository
class MyRepository {
#Autowired DummyObjectReactiveRepository dummyObjectReactiveRepository;
#JaversAuditableAsync
void save(DummyObject d){
dummyObjectReactiveRepository.save(d)
}
}

How to specify the using mongo database in a MongoRepository when there are multiple databases

In my spring boot application i have configured two databases in my yml file. So now I want to specify which database is to use in each MongoRepository. Is this possible? If so, how to do it? Thanks in advance.
yml file :
spring:
data:
mongodb:
first:
host: 127.0.0.1
port: 27017
database: db_admin
rest:
base-path: /admin
second:
host: 127.0.0.1
port: 27018
database: `user_forms`
rest:
base-path: /users
So in User MongoRepository i want to use the user_forms database.
The user MongoRepository :
#RepositoryRestResource(collectionResourceRel = "users",path = "users")
public interface UserRepository extends MongoRepository<User, String> {
List<User> findByUserId(String id);
}
Spring Boot auto configuration provides a default MongoTemplate to facilitate generating MongoDB Repositories.
Nevertheless if you want to use multi MongoDB databases, you would need to
register MongoTemplates for every MongoDB databases
designate each of the MongoTemplates to base packages of MongoRepositories accordingly, so that Spring Data MongoDB is informed to use the right template when generating repositories.
For example, say you registered 2 MongoTemplates, namely templateAdmin and templateUser, configured explicitly to their MongoDB. Then you could use code like this to inform Spring Data MongoDB which repositories use which template:
#EnableMongoRepositories(
basePackages = "com.the.base.package.name.of.admin.repositories",
mongoTemplateRef = "adminTemplateBeanName")
#Configuration
public class AdminMongoConfig {
#Bean
public MongoTemplate adminTemplateBeanName() {
//...
}
}
Configure Multiple MongoDB repositories with Spring Data Mongo Basically explained almost all points what I have said. So my wild guess is that you may have a misconception that MongoTemplate is irrelevant to MongoRepository, which is not the case.
Adding an answer despite having marked the question as a duplicate, as there is some confusion whether MongoRepository uses MongoTemplate.
When you inject your MongoRepository, it is proxied by an instance of SimpleMongoRepository class. it has a field
private final MongoOperations mongoOperations;
MongoOperations is an interface, and MongoTemplate is its implementation.
Now, the question is where does this default mongo template come from in a Spring Boot application.
Look at MongoDataAutoConfiguration
#Bean
#ConditionalOnMissingBean
public MongoTemplate mongoTemplate(MongoDbFactory mongoDbFactory,
MongoConverter converter) {
return new MongoTemplate(mongoDbFactory, converter);
}
Therefore, I am still claiming it is a duplicate of: Configure Multiple MongoDB repositories with Spring Data Mongo

mongodb grails simple application times out

I'm having an issue with mongodb 2.6.5 and grails 2.4.4 that I can't resolve. For the sake of isolating the problem I created a simple 2.4.4 grails app, installed the grails mongodb plugin (compile ":mongodb:3.0.2"), commented out the hibernate dependencies, added my mongodb datasource, and set up a simple domain class (com.nerds.Nerd). When I generate-all and then start the app and navigate to the NerdController CRUD page I get the following error every time:
MongoTimeoutException occurred when processing request: [GET] /MONGO/nerd/index
Timed out while waiting to connect after 10000 ms. Stacktrace follows:
com.mongodb.MongoTimeoutException: Timed out while waiting to connect after 10000 ms
I can access mongo via http using http://localhost:28017/
I have also tested manually adding data and querying from mongo. This all works fine.
In the debug log prior to the timeout it looks like GORM aquired a mongo session and then tried rolling back a transaction.
DatastoreTransactionManager:128 - Found thread-bound Session [org.grails.datastore.mapping.mongo.MongoSession#e47ee6] for Datastore transaction
DatastoreTransactionManager:128 - Creating new transaction with name [null]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly
DatastoreTransactionManager:128 - Initiating transaction rollback
DatastoreTransactionManager:128 - Rolling back Datastore transaction on Session [org.grails.datastore.mapping.mongo.MongoSession#e47ee6]
DatastoreTransactionManager:128 - Resuming suspended transaction after completion of inner transaction
Any insight would be helpful. Thanks
edit: The mongo datasource is pretty simple. I'm using the correct port.
From the mongo log:
014-11-18T13:10:13.388-0900 [initandlisten] MongoDB starting : pid=17275 port=27017 dbpath=/var/lib/mongodb 32-bit host=enterprise
from DataSource.groovy
grails { mongo { host = 'localhost' port = 27017 databaseName = 'mydb' } }
I'm fairly certain the issue was on the mongod side. I stopped the mongo daemon, put it into high verbose debug mode (using mongod -vvvv command), and when I tried to replicate the issue while watching the console output, the issue did not happen. I'm not entirely sure what the exact cause of the timeout was, but its not happening now. Thanks for the responses.