How to disable automatic table modification in jHipster? - spring-boot

I'm trying connect my jhipster app with a custom mssql database. Right now it is connected to a fresh default MySQL db tied up with liquibase and has the default entites that come out-of-the-box with jhipster. I want to do 2 things :
Prevent any db modification scripts that liquibase may run on start up e.g. entity creation
Saftely move over to a different db with old applicaiton data and many custom tables than the one that is fresh and configured by default in jhipster .
To do '1' I tried to do the following in
public class DatabaseConfiguration {
liquibase.setDropFirst(liquibaseProperties.isDropFirst());
if (env.acceptsProfiles(Constants.SPRING_PROFILE_NO_LIQUIBASE)) {
liquibase.setShouldRun(false);
} else {
liquibaseProperties.setEnabled(false); // <<<<<< I DISABLED IT HERE
liquibase.setShouldRun(liquibaseProperties.isEnabled());
log.debug("Configuring Liquibase");
}
}
But still I can see that liquibase scripts are being run in start-up. Please advice if I'm doing this correct.

For #1, you could do it several ways, as you have both mssql and MySQL: you could either use the JDBC URL in DatabaseConfiguration or modify the Liquibase changelogs to add conditions on dbms to exclude them for mssql
For #2, you should look for existing tools to convert from one database engine to another.

Related

Spring boot native query and JPA Repository

I would like to share all my project Repository interfaces with different database implementation (PostgreSQL, MySQL, ...), but having also some specific Repository with native query, for every db platform.
How can I achieve it? Is it possible to annotate a Repository to be used only with a specific database?
if you can not do it with annotations you could find out the dialect of the database and act accordingly.
an example
private boolean isOracle() {
Session session = (Session) entityManager.getDelegate();
Dialect dialect = ((SessionFactoryImpl) session.getSessionFactory()).getJdbcServices().getDialect();
return dialect.getClass().getName().contains("Oracle");
}
so if (isOracle()) you would use your oracleJpaNativeRepository

How does springboot JPA knows which database will be used?

I got to know Java spring JPA a couple days ago and there is one question which really makes me confused.
As I create a repository and use 'save()' method to save some objects into it. How does it know what type of database I am using and which local location to save.
I know I can config database (h2) like:
spring.datasource.url=jdbc:h2:mem/mydb
Then JPA will know: ok you are using h2 database and url is "jdbc:h2:mem/mydb"
However, some people said this config is not mandatory. If without this config, how does JPA knows which database I gonna use?
From the spring-boot documentation:
You should at least specify the URL by setting the spring.datasource.url property. Otherwise, Spring Boot tries to auto-configure an embedded database.
The following class is responsible for providing default settings for embedded DB: org.springframework.boot.autoconfigure.jdbc.DataSourceProperties
public String determineDatabaseName() {
...
if (this.embeddedDatabaseConnection != EmbeddedDatabaseConnection.NONE) {
return "testdb";
}
...
}
This answer can also be helpful: Where does the default datasource url for h2 come from on Spring Boot?

Set default schema = SOMETHING in oracle using Spring Boot and Spring JDBC

I am working now with oracle and spring jdbc but I don't want to use the schema in my sql statements:
Example: Select * from SCHEMA.table
Is there any way to set default schema in application.properties or application.yml?
Assuming you define your database connections using spring datasources, you can set the default schema when defining the datasource configuration:
spring.datasource.schema = #value for your default schema to use in database
You can find more info here: Spring Boot Reference Guide. Appendix A. Common application properties
After doing some research, looks like Oracle driver doesn't let you set a default schema to work with, as noted here:
Default Schema in Oracle Connection URL
From that post, you have two options:
Execute this statement before executing your statements:
ALTER SESSION SET CURRENT_SCHEMA=yourSchema
Create synonyms for your tables/views/etc (which I find really cumbersome if we're talking about lots of elements in your database).
I would advice using the first option. From what I see, Spring boot doesn't offer a simple way to execute a statement when retrieving the connection, so the best bet will be to use an aspect around the getConnection method (or the method that retrieves the connection from the data source) and execute the statement there.
From your comment, an easier way to solve it is by using a script in spring.datasource.schema:
spring.datasource.schema = schema.sql
And then a file squema.sql with the following:
ALTER SESSION SET CURRENT_SCHEMA=mySchema
In spring boot, I've found another way of doing it,
#Bean
#ConfigurationProperties(prefix="spring.datasource")
public DataSource dataSource(#Value("${spring.datasource.schema}") String schema) {
DataSource datasource = DataSourceBuilder.create().build();
if(!schema.isEmpty() && datasource instanceof org.apache.tomcat.jdbc.pool.DataSource){
((org.apache.tomcat.jdbc.pool.DataSource) datasource).setInitSQL("ALTER SESSION SET CURRENT_SCHEMA=" + schema);
}
return datasource;
}
I found another way to get around this by updating entity class with
#Table(schema = "SCHEMA_NAME" ,name = "TABLE_NAME")
If you are using hikari, use spring.datasource.hikari.schema=YOUR_SCHEMA.
Works for me with SpringBoot + tomcat using Oracle.
I was having issues with the currently accepted answer; specifically, the schema would only be changed from the initial connection. If your app uses a connection pool, you need to configure the pool to apply SQL for each connection.
For instance, using the default jdbc pool in Spring Boot 1.5.x (Tomcat):
spring.datasource.tomcat.init-s-q-l = ALTER SESSION SET CURRENT_SCHEMA=mySchema
Connecting to the database as your user, you can create a trigger that will change the schema each time you login:
CREATE OR REPLACE TRIGGER LOGON_TRG
AFTER LOGON ON SCHEMA
BEGIN
EXECUTE IMMEDIATE 'ALTER SESSION SET CURRENT_SCHEMA = foo';
EXCEPTION
when others
then null;
END;
/
Another option is to create a datasource wrapper. Create the datasource as normal and then create the wrapper that forwards all methods except for the getConnection methods. For those I just added SQL to set the schema. We have multiple datasources and this allowed us to specify a different schema for each datasource. If anyone knows if there's an issue with this I'd love comments. Or if there's an alternative that uses the properties.

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()
}

Disabling prepared statements in dbcp+spring+hibernate+jdbc?

I am currently enhancing an application that uses spring and hibernate.There are multiple instances where the application communicates with the db (postgres) via prepared statements.
The application until now, communicated with postgres via dbcp.
Change:
The application now communicated to postgres via pgbouncer.
i.e.: application -> dbcp -> pgbouncer -> postgres
I understand this wouldn't be the most ideal solution i.e: having 2 poolers. But due to the current architecture we require both of them.
Requirement:
pgbouncer does not support prepared statements in transaction mode & therefore have to be eliminated.
Changes to eliminate prepared statement.
1) psql: VERSION = 9.2.6
no change
2) pgbouncer: In the config file set the following attribures
ignore_startup_parameters=extra_float_digits
pool_mode=transaction
server_reset_query=
3) jdbc : The prepared threshold has been set accordingly.
i.e. : jdbc:postgresql://localhost:6541/postgres?prepareThreshold=0
JAVA VERSION = 1.7.0_51
JDBC DRIVER = postgresql-9.3-1102.jdbc41-3.jar
4) dbcp :
poolPreparedStatements = false
maxOpenPreparedStatements = 0
5) hibernate : no changes
6) spring : no changes
Issue:
Inspite of all these changes I still see prepared statements trying to be created & transactions failing due to that.
"ERROR: prepared statement "S_21" does not exist; nested exception is org.postgresql.util.PSQLException: ERROR: prepared statement "S_21 " does not exist"
I have removed all logical changes that used a prepared statement.
How can I prevent the other prepared statements from being created?
Does spring or hibernate internally create prepared statements for their usage? If yes, how do I disable them?
I understand that this post is from a few years ago but I am still facing the same issues. Unfortunately the suggested changes are not working for my current use case.
Facing the following issue:
- "Error: Prepared statement xxx does not exist"
- "Error: prepared statement xxx already exists"
Tried following the proposed changed but still getting the same error:
Tech Stack:
Spring Boot (2.1.7.RELEASE)
Spring Data (JPA + Hibernate)
The application is deployed on Heorku using the Heroku Postgre
Client side PgBouncer.
Modified the DB url with the following properties: "?sslmode=disable&prepareThreshold=0&preparedStatementCacheQueries=0"
The following settings are added to Heroku config:
PGSSLMODE= disable
PGBOUNCER_POOL_MODE = transaction
PGBOUNCER_IGNORE_STARTUP_PARAMETERS = extra_float_digits
set PGBOUNCER_URLS config value to DB name Urls
Spring Data is set up to use two Databases for (Read/Write & Read).
Using the #Transactional(readOnly=true) with #Around("#annotation(transactional)")
public Object proceed(ProceedingJoinPoint proceedingJoinPoint, Transactional transactional) throws Throwable {
try {
if(transactional.readOnly()) {
RoutingDataSource.setReplicaRoute();
LOGGER.info("Routing database call to the read replica");
}
return proceedingJoinPoint.proceed();
} finally {
RoutingDataSource.clearReplicaRoute();
}
}
The following configuration ia working on my system without any ERROR: prepared statement "S_21" does not exist; errors. Hope it helps:
pgBouncer 1.6.1, pool_mode = transaction
Added to Hibernate db-connection string: prepareThreshold=0
Postgresql-JDBC 9.4-1203-jdbc41 driver
Disable Prepared statements in Hibernate 4.x
<property name="hibernate.cache.use_query_cache">false</property>

Resources