(help to create multiple databases in spring boot in my answer)
I want to make a spring boot application for different games. The data of each game is placed in a separate database. I have been trying to connect a secondary database to my existing application, but the controller/repository keeps using the primary database.
This is what the controller for the second database looks like:
#RestController
#RequestMapping("/valorant")
#CrossOrigin
public class UserController {
#Autowired
private UserRepository userRepository;
#Autowired
#Qualifier("valorantDataSource")
private DataSource valorantDataSource;
#GetMapping("/users")
public Iterable<User> getUsers() {
return userRepository.findAll();
}
}
This is the repository that should take the data from the second database:
#Repository
#Qualifier("valorantDataSource")
public interface UserRepository extends JpaRepository<User, Long> {
}
I have defined the datasources in a different file. (Adding .url(), .username() and .password() to the datasourcebuilder did not help)
#Configuration
public class DatasourceConfig {
#Primary
#Bean(name = "apexDataSource")
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "valorantDataSource")
#ConfigurationProperties(prefix = "spring.second-datasource")
public DataSource valorantDataSource() {
return DataSourceBuilder.create()
.build();
}
}
# First database
spring.datasource.jdbc-url=jdbc:mysql://localhost:3306/apex
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# Second database
spring.second-datasource.jdbc-url=jdbc:mysql://localhost:3306/valorant
spring.second-datasource.username=root
spring.second-datasource.password=
spring.second-datasource.driver-class-name=com.mysql.cj.jdbc.Driver
When I used postman to go to http://localhost:8080/valorant/users, i got the error:
java.sql.SQLSyntaxErrorException: Table 'apex.user' doesn't exist
So it seems like the application is trying to look in the wrong database.
Thanks in advance.
You should not use #Primary annotation in this case.
When you mark bean with #Primary, it will be selected for dependency injection
Marking your beans with #Qualifier would be enough to select concrete bean.
I ended up using an existing project. I cloned this repo, changed some names and values and it was ready to use in my own project.
Related
I´m working on some legacy code, where we have 2 different datasources for our application.
There is one class that defines the configuration for both, and I don't want to separate them into two classes because things will probably break. This is the configuration class
#Configuration
public class DataSourceConfig {
#Bean(name="dataSource")
#Primary
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name="merchantsDataSource")
#ConfigurationProperties(prefix = "merchants.datasource")
public DataSource merchantsDataSource() {
return DataSourceBuilder.create().build();
}
}
Being structured this way, I don't think I can use #EnableJpaRepositories as suggested in many places to be able to define Repositories from different Data Sources.
So my question is: is there a way that I can create a Repository for the non-primary Data Source, without having to refactor all legacy code to use new classes?
Use Case
I want to implement Spring Security ACL in Spring Boot multi tenancy system.
Approach
In order to achieve this, I need to change datasource bean which is created on application bootstrap. I need to connect to datasource after the tenant user logs in.
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
[...]
// data source
#Bean
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
}
Prerequisites:
ACL is working fine in single tenant environment.
Multi tenancy is working also.
Question:
How can I refresh datasource in MethodSecurityConfiguration after system startup?
Thanks for your help!
I have a task application with its own database that I'd like to run in Spring Cloud Data Flow.
My problem is that SCDF overwrites the datasource configuration in the task with the datasource configuration for SCDF. (Both databases are Oracle DBs.)
My task should write to a different database (but I also want to know its status in SCDF database).
How is it possible to configure my task to connect to its own database as well as to SCDF's database?
I found the solution.
I defined both data sources in a configuration class (one for JPA and one for SCDF) following this as an example: https://www.baeldung.com/spring-data-jpa-multiple-databases
However this wasn't enough because the Data Flow Server accepts only one data source by default. To overcome this, one needs to extend the DefaultTaskConfigurer and set the Data Flow Server's data source in the constructor.
#Component
public class GeneratorTaskConfigurer extends DefaultTaskConfigurer {
public GeneratorTaskConfigurer(#Qualifier("dataflowDataSource") DataSource dataSource) {
super(dataSource);
}
}
You can have one config class with SCDF datasource code like this
#Configuration
#Profile("cloud")
public class MySqlConfiguration {
#Bean
public Cloud cloud() {
return new CloudFactory().getCloud();
}
#Bean
#Primary
public DataSource dataSource() {
return cloud().getSingletonServiceConnector(DataSource.class, null);
}
#Bean
#Primary
public PlatformTransactionManager getTransactionManager() {
return new DataSourceTransactionManager(dataSource());
}
#Bean
public JobRepository jobRepositoryFactoryBean() throws Exception{
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(dataSource());
factory.setTransactionManager(getTransactionManager());
factory.afterPropertiesSet();
return factory.getObject();
}
#Bean
#Primary
public DefaultTaskConfigurer defaultTaskConfigurer() {
return new DefaultTaskConfigurer(dataSource());
}
}
And then have your other datasource configuration in a separate class for the database you want to write to.
Make sure you mark the SCDF one #Primary, otherwise you get multiple datasource error.
Hope this helps.
Here is the problem, I need to configure additional datasource in my project.
There was only one datasource before, so I just configured one single datasource in application.properties, and then i coded like this:
#Repository
public class DrClusterManagerImpl implements DrClusterManager {
private final SqlSession sqlSession;
public DrClusterManagerImpl(SqlSession sqlSession) {
this.sqlSession = sqlSession;
}
}
it works fine, thanks to springboot, but now I'm puzzled that how can i inject a specific sqlsession into this bean?
I've checked springboot reference, but it's not helpful.
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-two-datasources
I am just learning how to use springboot as a java backend framework and I currently have applications.properties configured to use 1 database.
I am thinking of adding an additional database to store different information instead of saving everything on a single database so I was wondering how (if possible) can i do that?
My application.properties file contains data like this:
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://database:3306...
Any ideas?
You can create two datasources, one bean of them mark as #Primary
#Bean
#ConfigurationProperties(prefix = "datasource.mysql")
public DataSource mysqlDataSource() {
return DataSourceBuilder.create().build();
}
#ConfigurationProperties(prefix = "datasource.postgres")
#Bean
#Primary
public DataSource postgresDataSource() {
return DataSourceBuilder.create().
build();
}
Your application.properties should looks like this:
datasource.mysql.url=jdbc:mysql://localhost:3306/mysql_demo
datasource.mysql.username=root
datasource.mysql.password=root
datasource.mysql.driverClassName=com.mysql.jdbc.Driver
datasource.postgres.url=jdbc:postgresql://localhost:5432/postgres_demo
datasource.postgres.username=postgres
datasource.postgres.password=postgres
datasource.postgres.driverClassName=org.postgresql.Driver