Spring: Allow missing database connection - spring

I have a project connecting to multiple databases (Oracle & SQLServer), some of which are not always mandatory nor available when starting the application - especially on a dev environment.
I'm looking for a way to allow the application to start without a database connection right-on. We only require a connection to these DB when doing specific tasks, which use a Staging Database requiring a specific network access not always available on dev.
Here, with our Oracle connection (which is the one being under a specific network) :
We had a configuration that allowed the application to start, but was throwing errors when running the Tests because of the erroneous HikariDataSource cast :
#Configuration
#EnableJpaRepositories(
basePackages = "com.bar.foo.repository.oracle",
entityManagerFactoryRef = "oracleEntityManager",
transactionManagerRef = "oracleTransactionManager"
)
public class OracleConfiguration {
private final Logger log = LoggerFactory.getLogger(this.getClass());
#Inject
private Environment environment;
#Value("${spring.datasource.oracle.ddl-auto:none}")
private String hibernateddlAuto;
#Value("${spring.datasource.oracle.dialect:org.hibernate.dialect.Oracle10gDialect}")
private String hibernateDialect;
#Bean
#Primary
#ConfigurationProperties("spring.datasource.oracle")
public DataSourceProperties oracleDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#Primary
#ConfigurationProperties("spring.datasource.hikari")
public DataSource oracleDataSource() {
HikariDataSource ds = (HikariDataSource) oracleDataSourceProperties().initializeDataSourceBuilder().build();
ds.setPoolName(environment.getProperty("spring.datasource.oracle.poolName"));
return ds;
}
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean oracleEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setPackagesToScan("com.bar.foo.domain.oracle");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.ddl-auto", hibernateddlAuto);
properties.put("hibernate.dialect", hibernateDialect);
em.setJpaPropertyMap(properties);
em.setDataSource(oracleDataSource());
return em;
}
#Primary
#Bean
public PlatformTransactionManager oracleTransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
oracleEntityManager().getObject());
return transactionManager;
}
}
I moved this configuration to extend HikariConfig as following :
#Configuration
#EnableJpaRepositories(
basePackages = "com.bar.foo.repository.oracle",
entityManagerFactoryRef = "oracleEntityManager",
transactionManagerRef = "oracleTransactionManager"
)
#ConfigurationProperties("spring.datasource.oracle")
public class OracleConfiguration extends HikariConfig{
#Bean
#Primary
public DataSource oracleDataSource() {
return new HikariDataSource(this);
}
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean oracleEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setPackagesToScan("com.bar.foo.domain.oracle");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.ddl-auto", hibernateddlAuto);
properties.put("hibernate.dialect", hibernateDialect);
em.setJpaPropertyMap(properties);
em.setDataSource(oracleDataSource());
return em;
}
#Bean
#Primary
public PlatformTransactionManager oracleTransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
oracleEntityManager().getObject());
return transactionManager;
}
Which does not start if the Oracle DB is unavailable.
Using an embedded DB would not suit our use case, as we do not always need this connection, and when we do we need specific data replicated from Production.
Splitting this on multiple microservice/applications is also a no-go, as it would be a huge refacto, and does not really fit our use case (we aggregate data from multiple sources into a final one).
Is there a simple way to allow this ?

HikariCP provides some really nice configuration properties which may suit your needs. Specifically (the first one on that list) initializationFailTimeout:
This property controls whether the pool will "fail fast" if the pool
cannot be seeded with an initial connection successfully...
A value
less than zero will bypass any initial connection attempt, and the
pool will start immediately while trying to obtain connections in the
background. Consequently, later efforts to obtain a connection may
fail.
If you want to solve your problem this way, i.e. by hiding any initialization failures (by setting a negative initializationFailTimeout value), then you'll just have to make sure you have the right logic in case the DB is unaccesible/down when your getting a connection from the pool.

Well, after looking more at the HikariConfig class, I spotted the
initializationFailTimeout which states
* #param initializationFailTimeout the number of milliseconds before the
* pool initialization fails, or 0 to validate connection setup but continue with
* pool start, or less than zero to skip all initialization checks and start the
* pool without delay.
Setting it to zero or below allows the application to start, however it takes way much longer than it used to, and setting it below zero does not prevent it from waiting two connections timeouts.
I ended up also setting the connectionTimeout to the minimum 250ms on our dev configuration file, it seems to be working fine for now.

An alternative solution is to set the following parameter:
spring.jpa.database-platform=org.hibernate.dialect.Oracle10gDialect
Using that setting, I did not experience any slowness in application startup as I did when using the initializationFailTimeout setting.

Related

How can i connect to 2 different Schemas on one datasource in springboot

I am trying to extract data from multiple databases in different servers. This has been successful after configuring different Data sources as shown in my code however i cannot see to configure 2 different Data sources on the same connection.
I have tried to create 2 beans within the config file but i would still need to set the Data source.
#Configuration
#EnableJpaRepositories(basePackages = {"balances.Repository.World"},
entityManagerFactoryRef = "ASourceEntityManager",transactionManagerRef = "ASourceTransactionManager")
#EnableTransactionManagement
public class World{
#Autowired
private Environment env;
#Bean
public LocalContainerEntityManagerFactoryBean ASourceEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(ASourceDatasource());
em.setPackagesToScan(new String("balances.Repository.World"));
em.setPersistenceUnitName("ASourceEntityManager");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<String, Object>();
properties.put("hibernate.dialect",env.getProperty("app.datasource.ASource.hibernate.dialect"));
properties.put("hibernate.show-sql",env.getProperty("app.datasource.ASource.show-sql"));
em.setJpaPropertyMap(properties);
return em;
}
#Bean
#ConfigurationProperties(prefix = "app.datasource.ASource")
public DataSource ASourceDatasource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("app.datasource.ASource.driverClassName"));
dataSource.setUrl(env.getProperty("app.datasource.ASource.url"));
dataSource.setUsername(env.getProperty("app.datasource.ASource.username"));
dataSource.setPassword(env.getProperty("app.datasource.ASource.password"));
return dataSource;
}
#ConfigurationProperties(prefix = "app.datasource.ASourceB")
public DataSource ASourceDatasource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("app.datasource.ASourceB.driverClassName"));
dataSource.setUrl(env.getProperty("app.datasource.ASourceB.url"));
dataSource.setUsername(env.getProperty("app.datasource.ASourceB.username"));
dataSource.setPassword(env.getProperty("app.datasource.ASourceB.password"));
return dataSource;
}
#Bean
public PlatformTransactionManager ASourceTransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
ASourceEntityManager().getObject());
return transactionManager;
}
After some thought i have come up with a workaround that might be a bit hacky but gets the job done.
Instead of declaring a new database connection for the second schema in my app.properties i have used one connection. I placed all my entities in one model package and used a native query to access the other schema. In the native query i would then specify the schema eg:
select * from DATABASE1.Id;
This solution does not scale well as it would create a lot of work when dealing with a large number of entities so if there is a way of specifying the schema in the repository that would also help.
I tried using the entity attributes to define my schema but jpa seems to be ignoring it and prefixing the table with the wrong schema for example if
i annotate my class with the following
#Table(name = "Payment", schema = "DATABASE1", catalog = "")
The resulting query would be "select * from DATABASE2.Payment" instead of
select * from DATABASE1.Payment

Transaction Management across two data sources (ChainedTransactionManager) - SpringBoot

Why Spring ChainedTransactionManager is deprecated? Do spring provides any alternative lib to support multiple transaction managers?
My use-case:- We are building a spring boot application that is connected to two data sources let's say (db1 and db2), which performs insert operation on both databases (db1 and db2). And our requirement is something like this :
insert -> DB1 -> SUCCESSFUL
insert -> DB2 -> ERROR
ROLLBACK DB1
Currently, we are using ChaninedTransactionManager and it is working as expected, but I Can see that lib is deprecated? So, just wanted to make sure is it safe to use that, or does Spring provide any alternate lib which we can use as a replacement for this?
ChainedTransactionManager
The configured instances will start transactions in the order given and commit/rollback in reverse order, which means the PlatformTransactionManager most likely to break the transaction should be the last in the list configured.
If you chained transactions in this order : transaction1, transaction2
transaction1 begin
transaction2 begin
transaction2 commit -> error rollbacks, rollbacks transction1 too
transaction1 commit -> error, only rollbacks transaction1
The case insert -> DB1 -> SUCCESSFUL insert -> DB2 -> ERROR ROLLBACK DB1 is working.
But, if you had insert -> DB1 -> FAIL ROLLBAK DB1 -> DB2 -> SUCCESSFUL, the insert is commited for DB2 and not for DB1. More details in this article.
If your are OK with this, you can copy the class in your project et keep using it : https://github.com/spring-projects/spring-data-commons/issues/2232#issuecomment-1018473289
JtaTransactionManager with Atomikos
To have all transactions rollback if one fails, I changed my conf to use JtaTransactionManager (with spring boot and posgtres).
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
application.properties
my.datasource.one.unique-resource-name=
my.datasource.one.xa-properties.url=jdbc:postgresql://
my.datasource.one.xa-data-source-class-name=org.postgresql.xa.PGXADataSource
my.datasource.one.xa-properties.user=
my.datasource.one.xa-properties.password=
my.datasource.one.max-pool-size=
my.datasource.one.min-pool-size=
my.datasource.two.unique-resource-name=
my.datasource.two.xa-properties.url=jdbc:postgresql://
my.datasource.two.xa-data-source-class-name=org.postgresql.xa.PGXADataSource
my.datasource.two.xa-properties.user=
my.datasource.two.xa-properties.password=
my.datasource.two.max-pool-size=
my.datasource.two.min-pool-size=
#Bean
#Primary
#ConfigurationProperties("my.datasource.one")
public DataSource dataSourceOne() {
return new AtomikosDataSourceBean();
}
#Bean("entityManagerOne")
#DependsOn("transactionManager")
public LocalContainerEntityManagerFactoryBean entityManagerOne(#Autowired JpaVendorAdapter jpaVendorAdapter) {
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
properties.put("hibernate.default_schema", "public");
properties.put("hibernate.ddl-auto", "none");
LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
entityManager.setJtaDataSource(dataSourceOne());
entityManager.setJpaVendorAdapter(jpaVendorAdapter);
entityManager.setPackagesToScan("");
entityManager.setPersistenceUnitName("");
entityManager.setJpaPropertyMap(properties);
return entityManager;
}
#Bean
#Primary
#ConfigurationProperties("my.datasource.two")
public DataSource dataSourceTwo() {
return new AtomikosDataSourceBean();
}
#Bean("entityManagerTwo")
#DependsOn("transactionManager")
public LocalContainerEntityManagerFactoryBean entityManagerTwo(#Autowired JpaVendorAdapter jpaVendorAdapter) {
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
properties.put("hibernate.default_schema", "public");
properties.put("hibernate.ddl-auto", "none");
LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
entityManager.setJtaDataSource(dataSourceTwo());
entityManager.setJpaVendorAdapter(jpaVendorAdapter);
entityManager.setPackagesToScan("");
entityManager.setPersistenceUnitName("");
entityManager.setJpaPropertyMap(properties);
return entityManager;
}
jta.properties
com.atomikos.icatch.enable_logging=false
com.atomikos.icatch.default_jta_timeout=60000000
com.atomikos.icatch.max_timeout=100000000
com.atomikos.icatch.threaded_2pc=true
#Bean
public JpaVendorAdapter jpaVendorAdapter(#Autowired Environment env) {
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
hibernateJpaVendorAdapter.setShowSql(false);
return hibernateJpaVendorAdapter;
}
#Bean
public UserTransaction userTransaction() throws SystemException {
var userTransaction = new UserTransactionImp();
userTransaction.setTransactionTimeout(60000);
return userTransaction;
}
#Bean
public TransactionManager atomikosTransactionManager() throws SystemException {
var userTransactionManager = new UserTransactionManager();
userTransactionManager.setForceShutdown(true);
return userTransactionManager;
}
#Bean
public PlatformTransactionManager transactionManager(#Autowired UserTransaction userTransaction, #Autowired TransactionManager atomikosTransactionManager) throws Throwable {
return new JtaTransactionManager(userTransaction, atomikosTransactionManager);
}
Enable prepared transactions for postgres
postgresql.conf
max_prepared_transactions = 100 # zero disables the feature
Sources that helped me to get this :
https://www.baeldung.com/java-atomikos
http://www.thedevpiece.com/configuring-multiple-datasources-using-springboot-and-atomikos/
https://github.com/YihuaWanglv/spring-boot-jta-atomikos-sample
Because there is an API improvement. From the docs
https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/transaction/ChainedTransactionManager.html
Instead of using ChainedTransactionManager for attaching callbacks to transaction commit (pre commit/post commit), either register a TransactionSynchronization to explicitly follow transaction cleanup with simplified semantics in case of exceptions.
You are free to still use it, just keep in mind that at some point in the time that class will be removed in future versions of Spring and upgrading will not be possible without refactoring of that part.

Spring Boot - Use underscored table and column names for custom data source

I am trying to configure two data sources for a Spring Boot project. Here is my configuration file for primary data source.
#PropertySource({"classpath:application-local.properties"})
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "primaryEntityManager",
basePackages = {"portal.api.repository"}
)
public class PrimaryDbConfig {
#Autowired
private Environment env;
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean primaryEntityManager() {
LocalContainerEntityManagerFactoryBean em
= new LocalContainerEntityManagerFactoryBean();
em.setDataSource(primaryDataSource());
em.setPackagesToScan(
new String[]{"portal.api.model"});
HibernateJpaVendorAdapter vendorAdapter
= new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto",
env.getProperty("app.datasource.spring.jpa.hibernate.ddl"));
properties.put("hibernate.dialect",
env.getProperty("hibernate.dialect"));
em.setJpaPropertyMap(properties);
return em;
}
#Primary
#Bean
public DataSource primaryDataSource() {
DriverManagerDataSource dataSource
= new DriverManagerDataSource();
dataSource.setDriverClassName(
env.getProperty("app.datasource.driver-class-name"));
dataSource.setUrl(env.getProperty("app.datasource.url"));
dataSource.setUsername(env.getProperty("app.datasource.username"));
dataSource.setPassword(env.getProperty("app.datasource.password"));
return dataSource;
}
#Primary
#Bean
public PlatformTransactionManager userTransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
primaryEntityManager().getObject());
return transactionManager;
}
}
The tables are generated but their names and column names are in camel case. However I would like to have the underscore names which spring boot has by default. For example ApiKey entity would be changed to table name api_key.
How do I configure Spring Boot to use the underscored naming strategy?
I think if you use #Column(name = "api_key") in your instance variable for your domain model it'll work.
e.g.
#Column(name = "api_key")
private String apiKey;
Reference from Official doc
By default, Spring Boot configures the physical naming strategy with
SpringPhysicalNamingStrategy. This implementation provides the same
table structure as Hibernate 4: all dots are replaced by underscores
and camel casing is replaced by underscores as well.
You can set the following property in application.yml to tell springboot which naming strategy to use:
spring:
jpa:
hibernate:
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
Similar post for reference:
java.sql.SQLSyntaxErrorException: Unknown column .JPA Entity Issue?

Spring Boot Dual data configuration, unable to reconnect after connection lost

I am working on application written in spring Boot 1.5.3. I have two data source which are configured as below.
Main connection
spring.datasource.driverClassName = org.postgresql.Driver
spring.datasource.url = jdbc:postgresql://xxx.xxx.xxx.xx:5432/mydb
spring.datasource.username = xxxx
spring.datasource.password = xxxx
spring.jpa.properties.hibernate.default_schema=test
# Number of ms to wait before throwing an exception if no connection is available.
spring.datasource.tomcat.max-wait=10000
# Maximum number of active connections that can be allocated from this pool at the same time.
spring.datasource.tomcat.max-active=150
spring.datasource.tomcat.max-idle=30
spring.datasource.tomcat.min-idle=2
spring.datasource.tomcat.initial-size=3
# Validate the connection before borrowing it from the pool.
spring.datasource.tomcat.test-on-borrow=true
spring.datasource.tomcat.test-on-connect=true
spring.datasource.time-between-eviction-runs-millis=60000
#spring.datasource.tomcat.validation-query-timeout=1000
spring.datasource.tomcat.validation-query=SELECT 1
spring.datasource.tomcat.validation-interval=1000
spring.datasource.tomcat.remove-abandoned=true
spring.datasource.tomcat.remove-abandoned-timeout=55
spring.datasource.tomcat.test-while-idle=true
spring.datasource.tomcat.min-evictable-idle-time-millis = 55000
spring.datasource.tomcat.time-between-eviction-runs-millis = 34000
Second Connection
spring.rdatasource.driverClassName = org.postgresql.Driver
spring.rdatasource.url = jdbc:postgresql://xxx.xxx.xxx.xx:5432/mydb1
spring.rdatasource.username = xxxx
spring.rdatasource.password = xxxx
spring.jpa.properties.hibernate.default_schema=test
# Number of ms to wait before throwing an exception if no connection is available.
spring.rdatasource.tomcat.max-wait=10000
# Maximum number of active connections that can be allocated from this pool at the same time.
spring.rdatasource.tomcat.max-active=150
spring.rdatasource.tomcat.max-idle=30
spring.rdatasource.tomcat.min-idle=2
spring.rdatasource.tomcat.initial-size=3
# Validate the connection before borrowing it from the pool.
spring.rdatasource.tomcat.test-on-borrow=true
spring.rdatasource.tomcat.test-on-connect=true
spring.rdatasource.time-between-eviction-runs-millis=60000
#spring.rdatasource.tomcat.validation-query-timeout=1000
spring.rdatasource.tomcat.validation-query=SELECT 1
spring.rdatasource.tomcat.validation-interval=1000
spring.rdatasource.tomcat.remove-abandoned=true
spring.rdatasource.tomcat.remove-abandoned-timeout=55
spring.rdatasource.tomcat.test-while-idle=true
spring.rdatasource.tomcat.min-evictable-idle-time-millis = 55000
spring.rdatasource.tomcat.time-between-eviction-runs-millis = 34000
I am working in in VPN environment. When I run application, application is working fine. But the issue starts when I disconnect the VPN and reconnect the VPN.again, my application won't reconnect to data source again. Instead I always getting exception.
But working single database when leave connection handling to spring itself and I do not perform any database configuration.
Update
#Configuration
#PropertySource({ "classpath:application.properties" })
#EnableJpaRepositories(
basePackages = {"com.services.persistence"},
entityManagerFactoryRef = "entityManager",
transactionManagerRef = "transactionManager"
)
#ComponentScan("com.services.persistence")
#EnableTransactionManagement
public class DBConfig {
#Autowired private Environment env;
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean entityManager() {
LocalContainerEntityManagerFactoryBean em
= new LocalContainerEntityManagerFactoryBean();
em.setDataSource(userDataSource());
em.setPackagesToScan(
new String[] { "com.services.persistence", "com.services.persistence.pojo" });
HibernateJpaVendorAdapter vendorAdapter
= new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
// properties.put("hibernate.hbm2ddl.auto",
// env.getProperty("hibernate.hbm2ddl.auto"));
properties.put("hibernate.dialect",
env.getProperty("spring.jpa.database-platform"));
properties.put("hibernate.current_session_context_class",
env.getProperty("spring.jpa.properties.hibernate.current_session_context_class"));
em.setJpaPropertyMap(properties);
return em;
}
#Primary
#Bean
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource userDataSource() {
return DataSourceBuilder
.create()
.build();
}
#Primary
#Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
entityManager().getObject());
return transactionManager;
}
#Bean(name = "sessionFactory")
public SessionFactory getSessionFactory() {
SessionFactory sessionFactory = transactionManager().getEntityManagerFactory().unwrap(SessionFactory.class);
if (sessionFactory == null) {
throw new NullPointerException("factory is not a hibernate factory");
} else {
System.out.println(
"==================================== Transaction Enabled ========================================");
return sessionFactory;
}
}
I have also configured spring.rdatasource and it is same as above file, except it is not set as primary and other further details like pojo, transactionmanager etc.

what is the difference db configuration in spring boot

1)This is class level configuration (#configuration).why we need this boilerplate code
#Configuration
#EnableJpaRepositories(basePackages = {"xxx.xxx.xxx.core.dao"})
#EnableTransactionManagement
public class Repository {
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/xxxx");
dataSource.setUsername("xxxx");
dataSource.setPassword("xxxx");
return dataSource;
}
#Bean
public EntityManagerFactory entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("xx.xxxx.xxxx.xxxx.domain");
factory.setDataSource(dataSource());
factory.afterPropertiesSet();
return factory.getObject();
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory());
return txManager;
}
2) This option also working fine.spring boot will take rest of the code and it will take application.property file for configuration
#Configuration
#EnableJpaRepositories(basePackages = {"xxx.xxx.xxx.core.dao"})
#EnableTransactionManagement
#SpringBootApplication
#EnableCaching
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) {
ConfigurableApplicationContext app = SpringApplication.run(Application.class, args);
}
}
which one is good practice and why we need to create one class for database configuration(option 1)and how spring will take care all configuration (option 2)
This is class level configuration (#configuration).why we need this
boilerplate code
It is not mandatory to have these boilerplate code. You do this only in specific cases. For example, if you don't want spring-boot to do Autoconfiguration for you(with default values or values from application.properties).
Another example is when you have multiple datasbases to connect to in your application. In such cases, springboot's autoconfiguration is not of much help, and hence you would do like this. Not once, but as many times as the number of databases you have.
which one is good practice and why we need to create one class for
database configuration(option 1)and how spring will take care all
configuration (option 2)
As you might be knowing, spring-boot is primarily opinionated. Which means, it assumes a lot of things based on the dependencies you add in your pom. Even if you don't add anything in your properties file, it still tries to connect to database on your localhost and some predefined port as soon as it encounters and database dependencies in your pom.
So the answer is "It Depends". It depends on many things, whether you have one or multiple datasources, and also do you want complete control of how database configuration needs to be done... etc

Resources