How to create tables from entity with respect to their datasource in JPA - spring

Suppose I have two datasources primarydb,secondarydb also having two entities
entity1 , entity2. So When I add spring.jpa.hibernate.ddl-auto = update .
Here entity1 should get created in primarydb and entity2 should created in secondarydb.
but this is not happening it's creating in primarydb only.
and second thing if I want to add onetomany on entity1 with entity2 it's also not works
#ManyToOne
private Entity2 entity2;
application.properties
#actuator
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
#server.servlet.context-path=/ajax
spring.datasource.url=jdbc:mysql://#datasource.server#:3306/primarydb?useSSL=false
spring.datasource.username=#datasource.username#
spring.datasource.password=#datasource.password#
spring.datasource.tomcat.initial-size=30
spring.datasource.tomcat.max-wait=30000
spring.datasource.tomcat.maxActive=50
spring.datasource.tomcat.maxIdle=30
spring.datasource.tomcat.minIdle=30
spring.datasource.tomcat.minEvictableIdleTimeMillis=300000
server.session.tracking-modes=cookie
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto = update
spring.jpa.show-sql=true
#another db
datasource.secondary.hikari.jdbcUrl=jdbc:mysql://#datasource.server#/secondarydb:3306?useSSL=false
datasource.secondary.hikari.username=#datasource.username#
datasource.secondary.hikari.password=#datasource.password#
datasource.secondary.hikari.driverClassName=com.mysql.cj.jdbc.Driver
datasource.secondary.hikari.type=com.zaxxer.hikari.HikariDataSource
datasource.secondary.hikari.minimum-idle=30
datasource.secondary.hikari.maximum-idle=30
datasource.secondary.hikari.idle-timeout=300000
datasource.secondary.hikari.max-lifetime=300000
datasource.secondary.hikari.pool-name=SecondaryPool
datasource.secondary.hikari.connection-timeout=30000
datasource.secondary.hikari.maximum-pool-size=70
configuration file
#Configuration
#Profile("dev")
public class ApplicationConfiguration {
#Bean
#ConfigurationProperties(prefix = "datasource.secondary.hikari")
public HikariConfig hikariConfigForSecondaryDatasource() {
return new HikariConfig();
}
#Bean(name = "secondaryDataSource")
public DataSource dataSourceForSecondaryDatasource() {
return new HikariDataSource(hikariConfigForSecondaryDatasource());
}
#Bean
#Primary
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSourceForPrimaryDatasource() {
return DataSourceBuilder.create().build();
}
}

Related

Spring Database configuration

I have faced with one problem that made me crazy in its resolution. The problem is following: when I configure connection with my database in java class - it works good i.e. tables in DB are created corresponding to my classes names. BUT. When I try to use application.properties file instead java class configuration, everything what names tables properly is ignored and I`m confused what can I do with this issue(
For instance: I have a class named as 'ATMResearcher'. When I use java class to configure, there is an 'ATMResearcher' table in my database. But when my configuration properties are described in app.properties file (without using configuration class), then there is an 'atm_researcher' table in DB
I hope, anybody helps me. I provide screenshots of my config class and application.properties file below.
application.properties:
spring.datasource.url=jdbc:mysql://localhost:3306/someDB
spring.datasource.username=name
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.ddl-auto=create
JpaConfig.java file:
#EnableJpaRepositories(basePackages = "repositories")
#Configuration
#EnableTransactionManagement
public class JpaConfig {
private LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em
= new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan("entities");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
private DataSource dataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/someDB");
dataSource.setUsername("name");
dataSource.setPassword("password");
return dataSource;
}
#Bean
public PlatformTransactionManager transactionManager(){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory((EntityManagerFactory) entityManagerFactory());
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
return new PersistenceExceptionTranslationPostProcessor();
}
private Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "create");
properties.setProperty(
"hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
return properties;
}
}
ATMResearcher.java
#Data
#Entity(name = "ATMResearcher")
#Table(name = "ATMResearcher")
#NamedQueries({
#NamedQuery(name = ATMResearcher.findByAtm, query = "from ATMResearcher i where i.atm=:name")})
public class ATMResearcher implements Serializable {
private static final long serialVersionUID = 2046903428407635527L;
public static final String findBy = "researcherAtm.findByAtm";
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String researcher;
#ColumnDefault(value = "1")
private float volume;
#OneToMany(mappedBy = "atmReseacher", cascade = CascadeType.MERGE, targetEntity = ATMEval.class)
private Set<ATMEval> atmEval;
public String getShortName() {
return Arrays.stream(researcher.split(" ")).filter(n -> n.length() > 2)
.map(n -> n.substring(0, 1).toUpperCase()).collect(Collectors.joining());
}
#Override
public String toString() {
return "ATMResearcher{" +
"id=" + id +
", researcher='" + discipline + '\'' +
'}';
}
}
I think, you are missing this :
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
If it works, your properties should look like this:
spring.datasource.driverClassName=
spring.datasource.url=
spring.datasource.username=
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
Sorry but I don't really get it what you mean by "when I configure connection with my database in java class - it works good".
But when looking at you code there is something that you might have not seen yet.
You are using camelcase in you table name. This results in table name "atm_reasearch".
#Data
#Entity(name = "ATMResearcher")
#Table(name = "ATMResearcher")
Hope this solves your problem.
Hello you need to declare the naming strategies in your application.yml or properties file
By default spring will have such behaviour:
Replace dots with underscores
Change camel case to snake case
Lower-case table names
You should use JPA compliant standart
For JPA 1.0
spring:
jpa:
hibernate:
naming:
implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
For JPA 2.0
spring:
jpa:
hibernate:
naming:
implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl
For having same names use physical strategy

Spring JPA - Single Repository class with multiple JNDIs

I am using Spring JPA Repository to connect to Oracle.
My Repository package is com.demo.infrastructure.repository;
Repository class is StoreRepo.java
#Repository
public interface StoreRepo extends JpaRepository<StoreAttribute, String> {
#Query("select storeAttributeName from StoreAttribute order by storeAttributeName asc")
List<String> fetchAllStoreAttributeNames();
List<StoreAttribute> findAllByOrderByStoreAttributeNameAsc();
}
Problem:
I am using JNDI config to configure data source. Currently it has only one JNDI entry. Now I want to use two user names for the same database, one with admin(read-write) access and the other with user(read-only) access. Both these users will access the same Repository and same entity.
I tried the solutions already available which uses two different repository packages for each data source. But I want the Repository "StoreRepo" to be the same.
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactoryAdmin",
basePackages = { "com.demo.infrastructure.repository" }
)
public class DataSourceAdminConfig {
#Primary
#Bean(name = "dataSourceAdmin")
public DataSource dataSource() {
return new JndiDataSourceLookup().getDataSource("jdbc/myds_admin");
}
#Primary
#Bean(name = "entityManagerFactoryAdmin")
public LocalContainerEntityManagerFactoryBean
entityManagerFactory(
EntityManagerFactoryBuilder builder,
#Qualifier("dataSourceAdmin") DataSource dataSource
) {
return builder.dataSource(dataSource).
packages("com.demo.domain.model.entities").
persistenceUnit("read-write").
build();
}
#Primary
#Bean(name = "transactionManagerAdmin")
public PlatformTransactionManager transactionManager(
#Qualifier("entityManagerFactoryAdmin") EntityManagerFactory
entityManagerFactory
) {
return new JpaTransactionManager(entityManagerFactory);
}
}
I should have two classes like this with different package (Refer basePackages). But I dont want this solution instead want to use single repository package and the same repository class.
Solution that worked for me.
1) Created separate config classes one for admin user and app user each
2) Created seprate entity manager references one for admin user and app user each
3) Instantiated the same Repositoy class (without using #Repository annotation) through java code and using respective entity manager
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactoryAdmin"
)
public class AdminUserConfig {
#Primary
#Bean(name = "dataSourceAdmin")
public DataSource dataSourceAdmin(#Value("${spring.datasource.admin-user.jndi-name}") String key) {
return new JndiDataSourceLookup().getDataSource(key);
}
#Primary
#Bean(name = "entityManagerFactoryAdmin")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryAdmin(
EntityManagerFactoryBuilder builder,
#Qualifier("dataSourceAdmin") DataSource dataSource
) {
return builder.dataSource(dataSource).
packages("com.demo.domain.model.entities").
persistenceUnit("read-write").
build();
}
#Bean(name = "entityManagerAdmin")
public EntityManager entityManagerAdmin(#Qualifier("entityManagerFactoryAdmin") EntityManagerFactory
entityManagerFactory) {
return SharedEntityManagerCreator.createSharedEntityManager(entityManagerFactory);
}
#Bean(name = "adminRepository")
public StoreRepo readWriteDimStoreRepository(#Qualifier("jpaRepositoryFactoryAdmin")
JpaRepositoryFactory repositoryFactory) {
return repositoryFactory.getRepository(StoreRepo.class);
}
}
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactoryApp"
)
public class AppUserConfig {
#Primary
#Bean(name = "dataSourceApp")
public DataSource dataSourceApp(#Value("${spring.datasource.App-user.jndi-name}") String key) {
return new JndiDataSourceLookup().getDataSource(key);
}
#Primary
#Bean(name = "entityManagerFactoryApp")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryApp(
EntityManagerFactoryBuilder builder,
#Qualifier("dataSourceApp") DataSource dataSource
) {
return builder.dataSource(dataSource).
packages("com.demo.domain.model.entities").
persistenceUnit("read-only").
build();
}
#Bean(name = "entityManagerAdmin")
public EntityManager entityManagerApp(#Qualifier("entityManagerFactoryApp") EntityManagerFactory
entityManagerFactory) {
return SharedEntityManagerCreator.createSharedEntityManager(entityManagerFactory);
}
#Bean(name = "AppRepository")
public StoreRepo readOnlyStoreRepository(#Qualifier("jpaRepositoryFactoryApp")
JpaRepositoryFactory repositoryFactory) {
return repositoryFactory.getRepository(StoreRepo.class);
}
}
//#Repository
public interface StoreRepo extends JpaRepository<StoreAttribute, String> {
#Query("select storeAttributeName from StoreAttribute order by
storeAttributeName asc")
List<String> fetchAllStoreAttributeNames();
List<StoreAttribute> findAllByOrderByStoreAttributeNameAsc();
}

Spring Boot - connecting to two schema per tenant

I am creating a Spring boot Multimodule application in which one of the module has unique requirement. The module should be able to connect to one fixed schema say S1 and there are two other schema S2 and S3.
Depending upon the region it will connect to S1 and S2 or S1 and S3.
Will I have to follow the multi tenancy approach here ?
If yes how do I use multi tenancy to connect to two schema for a particular request ?
As per my understanding you want to connect to different DB's based on country. I have similar kind of issue in my project.
My requirement is when there is a json request i need to fetch country code from that and based on that i'll connect to that country specific DB. Below is my code. Hope this helps you.
application.properties
spring.main.web-application-type=none
#spring.main.allow-bean-definition-overriding=true
#au DB connection
spring.datasource.au.url=
spring.datasource.au.username=
spring.datasource.au.password=
#cn DB connection
spring.datasource.cn.url=
spring.datasource.cn.username=
spring.datasource.cn.password=
spring.jpa.show-sql=true
spring.jpa.database=default
spring.jpa.hibernate.ddl-auto=none
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl
spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
DB configuration
For Au :
Here i'm using #Primary annotation for AU.
#Configuration
#EnableJpaRepositories(entityManagerFactoryRef = "auEntityManagerFactory", transactionManagerRef = "auTransactionManager", basePackages = "com.dbs.multiDb.au.repository")
#EnableTransactionManagement
public class auDsConfig {
Logger logger = LogManager.getLogger(this.getClass());
#Autowired
Environment env;
#Bean(name = "auEntityManagerFactory")
#Primary
public LocalContainerEntityManagerFactoryBean cnEntityManagerFactory(final EntityManagerFactoryBuilder builder,
final #Qualifier("au-db") DataSource dataSource) {
return builder.dataSource(dataSource).packages("com.dbs.multiDb.domain").persistenceUnit("auDb")
.properties(singletonMap("hibernate.hbm2ddl.auto", "none")).build();
}
#Bean(name = "auTransactionManager")
#Primary
public PlatformTransactionManager auTransactionManager(
#Qualifier("auEntityManagerFactory") EntityManagerFactory cnEntityManagerFactory) {
return new JpaTransactionManager(cnEntityManagerFactory);
}
#SuppressWarnings("unused")
#Bean(name = "au-db")
#Primary
#ConfigurationProperties(prefix = "spring.datasource.au")
public DataSource auDataSource() {
DriverManagerDataSource dbFinal = new DriverManagerDataSource();
dbFinal.setDriverClassName(env.getProperty("jdbc.driverClassName"));
dbFinal.setUrl(env.getProperty("spring.datasource.au.url"));
dbFinal.setUsername(env.getProperty("spring.datasource.au.username"));
dbFinal.setPassword(env.getProperty("spring.datasource.au.password"));
return dbFinal;
}
}
CN DB config :
#Configuration
#EnableJpaRepositories(entityManagerFactoryRef = "cnEntityManagerFactory", transactionManagerRef = "cnTransactionManager", basePackages = "com.dbs.multiDb.cn.repository")
#EnableTransactionManagement
public class cnDsConfig {
#Bean(name = "cnEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean cnEntityManagerFactory(final EntityManagerFactoryBuilder builder,
final #Qualifier("cn-db") DataSource dataSource) {
return builder.dataSource(dataSource).packages("com.dbs.multiDb.domain").persistenceUnit("cnDb")
.properties(singletonMap("hibernate.hbm2ddl.auto", "none")).build();
}
#Bean(name = "cnTransactionManager")
public PlatformTransactionManager cnTransactionManager(
#Qualifier("cnEntityManagerFactory") EntityManagerFactory cnEntityManagerFactory) {
return new JpaTransactionManager(cnEntityManagerFactory);
}
#Bean(name = "cn-db")
#ConfigurationProperties(prefix = "spring.datasource.cn")
public DataSource cnDataSource() {
DriverManagerDataSource dbFinal = new DriverManagerDataSource();
dbFinal.setDriverClassName(env.getProperty("jdbc.driverClassName"));
dbFinal.setUrl(env.getProperty("spring.datasource.cn.url"));
dbFinal.setUsername(env.getProperty("spring.datasource.cn.username"));
dbFinal.setPassword(env.getProperty("spring.datasource.cn.password"));
return dbFinal;
}
}
Created REPO's for both countries :
AU Repo :
#Repository
public interface AURepository extends CrudRepository<BeanName,String>{
}
CN Repo :
#Repository
public interface CNRepository extends CrudRepository<BeanName,String>{
}
Service class :
#Service
public class ServiceClass{
private AURepository auTxn;
private CNRepository cnTxn;
#Autowired
public ServiceClass(AURepository auTxn, CNRepository cnTxn) {
super();
this.auTxn = auTxn;
this.cnTxn = cnTxn;
}
public List<Bean> getData(String input, String country) {
List<Bean> data= new ArrayList<Bean>();
//If this is AU then it will connect to AU DB and retrieve data.
if (country.equals("AU")) {
data= auTxn.findall();
}
//If this is CN then it will connect to AU DB and retrieve data.
else if (country.equals("CN")) {
data= cnTxn.findall();
}
return data;
}
}

Why can't Service find my Repository bean?

I'm making a simple spring boot application and my service doesn't seem to notice my repository bean for some reason. I checked my configuration and it seems fine, I also basically just copied way that the repository is injected from a tutorial so i really don't even have an idea where might the problem be.
My Repository:
#Repository
public interface ProjectRepository extends CrudRepository<Trucks, Integer>
{
#Query("....")
List<Trucks> getTrucks();
}
My service:
#Service
#Transactional
public class ProjectServiceImpl implements ProjectService {
private ProjectRepository projectRepository;
#Autowired
public ProjectServiceImpl(ProjectRepository projectRepository) {
this.projectRepository = projectRepository;
}
#Override
public List<Trucks> getTrucks() {
return projectRepository.getTrucks();
}
}
Configuration:
#Configuration
#EnableJpaRepositories(basePackages = {
"com.javar.domain"
})
#PropertySource("classpath:application.properties")
#EnableTransactionManagement
public class PersistanceContext {
private static final String[] ENTITY_PACKAGES = {
"com.javar.domain"
};
private static final String PROPERTY_NAME_DB_DRIVER_CLASS
="spring.datasource.driver-class-name";
private String PROPERTY_NAME_DB_URL="app.datasource.url";
private String PROPERTY_NAME_DB_USER="app.datasource.username";
private String PROPERTY_NAME_DB_PASSWORD="app.datasource.password";
private String
PROPERTY_NAME_HIBERNATE_DIALECT="spring.jpa.properties.hibernate.dialect";
private String
PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO="spring.jpa.hibernate.ddl-auto";
private String
PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY="spring.jpa.hibernate.naming-
strategy";
private String PROPERTY_NAME_HIBERNATE_SHOW_SQL="spring.jpa.show-sql";
private String
PROPERTY_NAME_HIBERNATE_FORMAT_SQL=
"spring.jpa.properties.hibernate.format_sql";
#Bean(destroyMethod = "close")
DataSource dataSource(Environment env) {
HikariConfig dataSourceConfig = new HikariConfig();
dataSourceConfig.setDriverClassName(env.getRequiredProperty
(PROPERTY_NAME_DB_DRIVER_CLASS));
dataSourceConfig.setJdbcUrl(env.getRequiredPropert
(PROPERTY_NAME_DB_URL));
dataSourceConfig.setUsername(env.getRequiredProperty
(PROPERTY_NAME_DB_USER));
dataSourceConfig.setPassword(env.getRequiredProperty
(PROPERTY_NAME_DB_PASSWORD));
return new HikariDataSource(dataSourceConfig);
}
#Bean
LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource
dataSource, Environment env) {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new
LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource);
entityManagerFactoryBean.setJpaVendorAdapter(new
HibernateJpaVendorAdapter());
entityManagerFactoryBean.setPackagesToScan(ENTITY_PACKAGES);
Properties jpaProperties = new Properties();
//Configures the used database dialect. This allows Hibernate to create SQL
//that is optimized for the used database.
jpaProperties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
//Specifies the action that is invoked to the database when the Hibernate
//SessionFactory is created or closed.
jpaProperties.put(PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO));
//Configures the naming strategy that is used when Hibernate creates
//new database objects and schema elements
jpaProperties.put(PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY));
//If the value of this property is true, Hibernate writes all SQL
//statements to the console.
jpaProperties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
//If the value of this property is true, Hibernate will use prettyprint
//when it writes SQL to the console.
jpaProperties.put(PROPERTY_NAME_HIBERNATE_FORMAT_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_FORMAT_SQL));
entityManagerFactoryBean.setJpaProperties(jpaProperties);
return entityManagerFactoryBean;
}
#Bean
JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
Application.properties:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
app.datasource.url=jdbc:mysql://localhost:3306/zavrsni?useSSL=false
app.datasource.username=....
app.datasource.password=....
#Hibernate Configuration
spring.jpa.properties.hibernate.dialect =
org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.hibernate.naming-strategy =
org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
And the error report:
Description:
Parameter 0 of constructor in com.javar.serviceImpl.ProjectServiceImpl
required a bean of type 'com.javar.repositoryy.ProjectRepository' that
could not be found.
Action:
Consider defining a bean of type 'com.javar.repositoryy.ProjectRepository'
in your configuration.
}
You can try this:
#Autowired
private ProjectRepository projectRepository;
and remove this contructor with that annotation:
#Autowired
public ProjectServiceImpl(ProjectRepository projectRepository) {
this.projectRepository = projectRepository;
}
If this helps you or you have some questions, let me edit this answer later.
UPDATED
Make sure that the package is correct where repository is found.
#EnableJpaRepositories(basePackages = {"com.javar.domain"})
So update the package to "com.javar.repositories"
Found the answer finally, so i just needed to add #EnableJpaRepositories(basePackages = "com.javar.repositoryy") above my Application class. Hope this helps someone in the future.
Solved this error by adding (missing in my case) maven dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

about spring boot jdbctemple multi datasources reuse common config

I used spring boot + jdbctemplate, and in my business I have to access multi datasource, e.g.
application.properties
foo.datasource.url=jdbc:mysql://127.0.0.1/foo
foo.datasource.username=root
foo.datasource.password=12345678
bar.datasource.url=jdbc:mysql://127.0.0.1/bar
bar.datasource.username=root
bar.datasource.password=12345678
Java Config
#Bean(name = "fooDb")
#ConfigurationProperties(prefix = "foo.datasource")
public DataSource fooDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "fooJdbcTemplate")
public JdbcTemplate fooJdbcTemplate(#Qualifier("fooDb") DataSource ds) {
return new JdbcTemplate(ds);
}
and there are some common configuration for all datasources
spring.datasource.test-while-idle=true
spring.datasource.time-between-eviction-runs-millis=30000
spring.datasource.validation-query=select 1
How could I populate these common properties to every jdbctemplate, e.g.
#Bean(name = "commonDb")
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource commonDataSource() {
return DataSourceBuilder.create().build();
}
Now my way is
#Value("${spring.datasource.test-while-idle}")
private boolean testWhileIdle;
#Value("${spring.datasource.time-between-eviction-runs-millis}")
private int timeBetweenEvictionRunsMillis;
#Value("${spring.datasource.validation-query}")
private String validationQuery;
private DataSource commonProcess(DataSource build) {
org.apache.tomcat.jdbc.pool.DataSource ds = (org.apache.tomcat.jdbc.pool.DataSource) build;
ds.setTestWhileIdle(testWhileIdle);
ds.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
ds.setValidationQuery(validationQuery);
return build;
}
#Bean(name = "fooDb")
#ConfigurationProperties(prefix = "foo.datasource")
public DataSource fooDataSource() {
return commonProcess(DataSourceBuilder.create().build());
}

Resources