Is there a way to avoid index creation on application startup using Mongo repository? - javers

JaversBuilder.build() always calls MongoRepository.ensureSchema() to execute createIndex() for jv_snapshots, even when the indexes already exists.
Particularly, the createIndex permission was revoked because this command blocks all other operations on the Mongo instance (not only the database, like in MongoDB documentation) when executed in foreground.
Maybe ensureSchema could be called when configuring Javers for the application, outside JaversBuilder.build(). Example:
#Bean
public Javers javers() {
MongoRepository repository = new MongoRepository(mongoClient.getDatabase(databaseName));
Javers javers = JaversBuilder.javers().registerJaversRepository(repository).build();
repository.ensureSchema();
return javers;
}
It is appropriate to suggest the removal of the call to ensureSchema from JaversBuilder.build() or is there another way to avoid index creation on startup in a non Spring Boot application?

Related

WebSphere insert/update statements with SQL-SERVER hangs with REQUIRES_NEW propagation

We are facing an issue in our spring batch application when we are deploying the application on WebSphere.
Example: One class contains parent() method and Second class contains child() method, where child method requires a new transaction. After execution of the methods when transaction is committed the commit routine hangs and nothing happens further.
#Transactional //using current transaction
public void parent(){
child();
}
#Transactional(propagation=REQUIRES_NEW) //creates new transaction
public void child(){
//Database save statements including update, insert and deletes
}
This issue only persists in WebSphere and code works fine on our local machine where we are using tomcat as web container.
WebSphere logs/stacktrace shows that the WebSphere prepared statement keeps on waiting for the response from the database. At the same time update and inserts are locked out on the affected tables i.e. if we run an insert or update query manually on the affected table the query doesn't execute.
We are using Spring JPA for data persistence and Spring’s JpaTransactionManager for transaction management and MSSQLServer database.
Is it that WebSphere does not support creating new transaction from existing transaction?
Yes, the pattern you are describing is supported by WebSphere Application Server. Given that this involved locked entries within the database, you might be running into a difference between the application servers in which transaction isolation level is used by default. In WebSphere Application Server, you get a default of java.sql.Connection.TRANSACTION_REPEATABLE_READ for SQL Server, whereas I think in most other cases you end up with a default of java.sql.Connection.TRANSACTION_READ_COMMITTED (less locking). If the default value is the problem, you can change it on the data source configuration.
If you are using WebSphere Application Server Liberty, then the default isolation level can be configured in server.xml as a property of the dataSource element, like this,
<dataSource isolationLevel="TRANSACTION_READ_COMMITTED" jndiName=...
If you are using WebSphere Application Server traditional, then the default isolation level can be configured as the webSphereDefaultIsolationLevel custom property, which can be set to the numeric value of the isolation level constant on java.sql.Connection (value for TRANSACTION_READ_COMMITTED is 2).
See this linked article for the steps of doing so via the admin console.

Retrieve DataStax Session from CassandraOperations

Spring Boot Data Cassandra has removed the ability to retrieve a com.datastax.driver.core.Session from org.springframework.data.cassandra.core.CassandraOperations. I'm trying to rectify old code that has these usages. Is there a simply way to retrieving the cassandra session? I'm looking for a way to create a prepared statement from an Insert, with only access to an instance of CassandraOperations, e.g.
cassandraOperations.getSession().prepare(insert);
We've removed getSession() from CassandraOperations because of two reasons:
Interface split into CassandraOperations and CqlOperations. CassandraTemplate (which implements CassandraOperations) now uses CqlOperations as lower-level API.
We introduced SessionFactory to be able to route CQL calls into various Cassandra Sessions. CQL execution obtains a session from the configured SessionFactory. A session is considered valid during the execute call as the next command could be executed on a different session.
You can still obtain a Session. Either call:
CqlTemplate cqlTemplate = (CqlTemplate) cassandraTemplate.getCqlOperations();
cqlTemplate.getSession();
or obtain Session through Spring's context (autowiring, lookup via context.getBean(Session.class), …).

Spring Boot: Retrieve config via rest call upon application startup

I d like to make a REST call once on application startup to retrieve some configuration parameters.
For example, we need to retrieve an entity called FleetConfiguration from another server. I d like to do a GET once and save the keep the data in memory for the rest of the runtime.
What s the best way of doing this in Spring? using Bean, Config annotations ..?
I found this for example : https://stackoverflow.com/a/44923402/494659
I might as well use POJOs handle the lifecycle of it myself but I am sure there s a way to do it in Spring without re-inventing the wheel.
Thanks in advance.
The following method will run once the application starts, call the remote server and return a FleetConfiguration object which will be available throughout your app. The FleetConfiguration object will be a singleton and won't change.
#Bean
#EventListener(ApplicationReadyEvent.class)
public FleetConfiguration getFleetConfiguration(){
RestTemplate rest = new RestTemplate();
String url = "http://remoteserver/fleetConfiguration";
return rest.getForObject(url, FleetConfiguration.class);
}
The method should be declared in a #Configuration class or #Service class.
Ideally the call should test for the response code from the remote server and act accordingly.
Better approach is to use Spring Cloud Config to externalize every application's configuration here and it can be updated at runtime for any config change so no downtime either around same.

How to turn off JPA for SpringBatch under SpringBoot

We have a Spring Boot application that uses Spring Integration and Spring Batch. We drop a file in the poller and it processes. This process inserts records into a database and then reads them back out does some processing and writes a file. Let's say there are 10 records. The first time we get 10 records read and 10 written. Without stopping the server, we delete all the records through a SQL client on the database, run the same file again and we get 10 records read with 20 written. I believe there is some JPA or caching going on with the datasource. We've tried turning off several auto configuration options for JPA and caching but we haven't found the right configuration option to turn off caching.
Adding a bit more detail to the question.
Basically we have cron scheduler that has a FileHandler. This the handleFile methods we have the following.
public File handleFile(File file) throws Throwable {
JobParametersBuilder jobParametersBuilder = new JobParametersBuilder();
Job job = (Job) appContext.getBean("processInitialFileJob");
JobExecution jb = jobLauncher.run(job, jobParametersBuilder.toJobParameters());
....
}
What can we do to the code above to ensure that it has a new JPA session or not use the JPA session at all? This job needs to read from the database each time and not a cached representation of the database.
Are u using Hibernate. Hibernate First Level cache may be creating the problem for u. Hibernate manages a First Level cache which is local to your Session. So once u create a session and do any transactions in that hibernate syncs that within. But when u do any changes to the table outside hibernate then hibernate wont sync that until flush is called on the session and session is closed.
To make sure this is not happening, inside your poller logic try creating new Session(or EntityManager in case of JPA) and close the session for every read/process/write cycle.
Also make sure this hibernate.current_session_context_class is not set to Thread. Since thread can be reused by the poller so the same Hibernate Session may be injected again.
This ended up not being an issue with Hibernate or JPA, but an issue of a StringBuilder holding on to data from previous runs. I believe this will need to be setup as #JobScope so that it is not reused across different executions of the job.

Completely auto DB upgradable Spring boot application

I am trying to use flyway for DB migrations and Spring boot's flyway support for auto-upgrading DB upon application start-up and subsequently this database will be used by my JPA layer
However this requires that schema be present in the DB so that primary datasource initialization is successful. What are the options available to run a SQL script that will create the required schema before flyway migrations happen.
Note that If I use flyway gradle plugin (and give the URL as jdbc:mysql://localhost/mysql. It does create the schema for me. Am wondering if I could make this happen from Java code on application startup.
Flyway does not support full installation when schema is empty, just migration-by-migration execution.
You could though add schema/user creation scripts in the first migration, though then your migration scripts need to be executed with sysdba/root/admin user and you need to set current schema at the beginning of each migration.
If using Flyway, the least problematic way is to install schema for the first time manually and do a baseline Flyway task (also manually). Then you are ready for next migrations to be done automatically.
Although Flyway is a great tool for database migrations it does not cover this particular use case well (installing schema for the first time).
"Am wondering if I could make this happen from Java code on application startup."
The simple answer is yes as Flyway supports programmatic configuration from with java applications. The starting point in the flyway documentation can be found here
https://flywaydb.org/documentation/api/
flyway works with a standard JDBC DataSource and so you can code the database creation process in Java and then have flyway handle the schema management. In many environment you are likely to require 2 steps anyway as the database/schema creation will need admin rights to the database, while the ongoing schema management will need an account with reduced access rights.
what you need is to implement the interface FlywayCallback
in order to kick start the migration manually from you code you can use the migrate() method on the flyway class
tracking the migration process can be done through the MigrationInfoService() method of the flyway class
Unfortunately if your app has a single datasource that expects the schema to exist, Flyway will not be able to use that datasource to create the scheme. You must create another datasource that is not bound to the schema and use the unbounded datasource by way of a FlywayMigrationStrategy.
In your properties file:
spring:
datasource:
url: jdbc:mysql://localhost:3306/myschema
bootstrapDatasource:
url: jdbc:mysql://localhost:3306
In your config file:
#Bean
#Primary
#ConfigurationProperties("spring.datasource")
public DataSourceProperties primaryDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#Primary
#ConfigurationProperties("spring.datasource")
public DataSource primaryDataSource() {
return primaryDataSourceProperties().initializeDataSourceBuilder().build();
}
#Bean
#ConfigurationProperties("spring.bootstrapDatasource")
public DataSource bootstrapDataSource() {
return DataSourceBuilder.create().build();
}
And in your FlywayMigrationStrategy file:
#Inject
#Qualifier("bootstrapDataSource")
public void setBootstrapDataSource(DataSource bootstrapDataSource) {
this.bootstrapDataSource = bootstrapDataSource;
}
#Override
public void migrate(Flyway flyway) {
flyway.setDataSource(bootstrapDataSource);
...
flyway.migrate()
}

Resources