In this blog post, we'll explore the configuration and setup for a Spring Boot 3 application with Java 21 that uses multiple data sources. This setup is useful when dealing with databases of different types, such as MySQL, Oracle, and PostgreSQL.
Technology
- Spring Boot 3.2.0
- Java 21 (Zulu)
- Docker Compose
- Maven
- IntelliJ IDEA 2023.3.1 Community
- Postman
Project Structure
multiple-data-sources-jpa |-- src | |-- main | |-- java | |-- com | |-- henry | |-- configuration | |-- model | |-- repository | |-- service | |-- controller |-- src | |-- test | |-- java | |-- com | |-- henry | |-- ... |-- pom.xml
Application.yaml Configuration
The application file contains configuration deatils for each data source, including URLs, usernames, passowrds, and driver class names.
server:
port: 9000
servlet:
context-path: /
spring:
datasource:
mysql:
url: jdbc:mysql://localhost:3306/test_db?allowPublicKeyRetrieval=true
username: test
password: test_pass
driverClassName: com.mysql.cj.jdbc.Driver
ddlAuto: create-drop
postgres:
url: jdbc:postgresql:postgre_test
username: postgre_test
password: postgre_test
driverClassName: org.postgresql.Driver
ddlAuto: create-drop
oracle:
url: jdbc:oracle:thin:@//localhost:1521/xe
username: system
password: oracle
driverClassName: oracle.jdbc.OracleDriver
ddlAuto: update
Configuration Classes
We've created configuration classes for each data source - MysqlConfig, PostgreConfig, and OracleConfig:
package com.henry.configuration; import com.henry.record.OracleRecord; import com.henry.record.PostgreRecord; import com.henry.record.MysqlRecord; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import lombok.Data; @Component @ConfigurationProperties("spring.datasource") @Data public class DataSourceProperties { private MysqlRecord mysql; private PostgreRecord postgres; private OracleRecord oracle; }
package com.henry.configuration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.JpaVendorAdapter; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import org.springframework.transaction.PlatformTransactionManager; import javax.naming.NamingException; import javax.sql.DataSource; import java.util.Properties; @Configuration @EnableJpaRepositories( basePackages = "com.henry.repository.user", entityManagerFactoryRef = "userEntityManager", transactionManagerRef = "userTransactionManager" ) public class MysqlConfig { @Autowired private DataSourceProperties dsProperties; @Bean @Primary public LocalContainerEntityManagerFactoryBean userEntityManager() throws NamingException { LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(userDataSource()); em.setPackagesToScan("com.henry.model.user"); JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); em.setJpaVendorAdapter(vendorAdapter); em.setJpaProperties(userHibernateProperties()); return em; } @Bean @Primary public DataSource userDataSource() throws IllegalArgumentException, NamingException { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName(dsProperties.getMysql().driverClassName()); dataSource.setUrl(dsProperties.getMysql().url()); dataSource.setUsername(dsProperties.getMysql().username()); dataSource.setPassword(dsProperties.getMysql().password()); return dataSource; } private Properties userHibernateProperties() { Properties properties = new Properties(); properties.put("hibernate.hbm2ddl.auto",dsProperties.getMysql().ddlAuto()); return properties; } @Primary @Bean public PlatformTransactionManager userTransactionManager() throws NamingException { final JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(userEntityManager().getObject()); return transactionManager; } }
package com.henry.configuration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.JpaVendorAdapter; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import org.springframework.transaction.PlatformTransactionManager; import javax.naming.NamingException; import javax.sql.DataSource; import java.util.Properties; @Configuration @EnableJpaRepositories( basePackages = "com.henry.repository.brand", entityManagerFactoryRef = "brandEntityManager", transactionManagerRef = "brandTransactionManager" ) public class OracleConfig { @Autowired private DataSourceProperties dsProperties; @Bean public LocalContainerEntityManagerFactoryBean brandEntityManager() throws NamingException { LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(brandDataSource()); em.setPackagesToScan("com.henry.model.brand"); JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); em.setJpaVendorAdapter(vendorAdapter); em.setJpaProperties(brandHibernateProperties()); return em; } @Bean public DataSource brandDataSource() throws IllegalArgumentException, NamingException { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName(dsProperties.getOracle().driverClassName()); dataSource.setUrl(dsProperties.getOracle().url()); dataSource.setUsername(dsProperties.getOracle().username()); dataSource.setPassword(dsProperties.getOracle().password()); return dataSource; } private Properties brandHibernateProperties() { Properties properties = new Properties(); properties.put("hibernate.hbm2ddl.auto", dsProperties.getOracle().ddlAuto()); return properties; } @Bean public PlatformTransactionManager brandTransactionManager() throws NamingException { final JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(brandEntityManager().getObject()); return transactionManager; } }
package com.henry.configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import javax.naming.NamingException;
import javax.sql.DataSource;
import java.util.Properties;
@Configuration
@EnableJpaRepositories(
basePackages = "com.henry.repository.company",
entityManagerFactoryRef = "companyEntityManager",
transactionManagerRef = "companyTransactionManager"
)
public class PostgreConfig {
@Autowired
private DataSourceProperties dsProperties;
@Bean
public LocalContainerEntityManagerFactoryBean companyEntityManager()
throws NamingException {
LocalContainerEntityManagerFactoryBean em
= new LocalContainerEntityManagerFactoryBean();
em.setDataSource(companyDataSource());
em.setPackagesToScan("com.henry.model.company");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(companyHibernateProperties());
return em;
}
@Bean
public DataSource companyDataSource() throws IllegalArgumentException, NamingException {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(dsProperties.getPostgres().driverClassName());
dataSource.setUrl(dsProperties.getPostgres().url());
dataSource.setUsername(dsProperties.getPostgres().username());
dataSource.setPassword(dsProperties.getPostgres().password());
return dataSource;
}
private Properties companyHibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.hbm2ddl.auto", dsProperties.getPostgres().ddlAuto());
return properties;
}
@Bean
public PlatformTransactionManager companyTransactionManager() throws NamingException {
final JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(companyEntityManager().getObject());
return transactionManager;
}
}
Record Classes
To encapsulate the configuration properties for each data source, we've defined record classes - MysqlRecord, PostgreRecord, and OracleRecord:
package com.henry.record; public record MysqlRecord(String url, String username, String password, String driverClassName,String ddlAuto) { }
package com.henry.record; public record OracleRecord(String url, String username, String password, String driverClassName,String ddlAuto) { }
package com.henry.record;
public record PostgreRecord(String url, String username, String password, String driverClassName,String ddlAuto) {
}
Repositories
Repository interfaces extend the CrudRepository for each entity (Brand, Company, User):
package com.henry.repository.brand;
import com.henry.model.brand.Brand;
import org.springframework.data.repository.CrudRepository;
public interface BrandRepository extends CrudRepository<Brand,Long> {
}
package com.henry.repository.company;
import com.henry.model.company.Company;
import org.springframework.data.repository.CrudRepository;
public interface CompanyRepository extends CrudRepository<Company,Long> {
}
package com.henry.repository.user;
import com.henry.model.user.User;
import org.springframework.data.repository.CrudRepository;
public interface UserRepository extends CrudRepository<User,Long> {
}
Services
Service classes (BrandServiceImpl, CompanyServiceImpl, UserServiceImpl) implement a common interface (DefaultService) for generic CRUD operations:
package com.henry.service;
public sealed interface DefaultService<T, G> permits UserServiceImpl, CompanyServiceImpl, BrandServiceImpl {
T save(T obj);
Iterable<T> findAll();
T findById(G id);
}
Services
Service classes (BrandServiceImpl, CompanyServiceImpl, UserServiceImpl) implement a common interface (DefaultService) for generic CRUD operations:
package com.henry.service;
public sealed interface DefaultService<T, G> permits UserServiceImpl, CompanyServiceImpl, BrandServiceImpl {
T save(T obj);
Iterable<T> findAll();
T findById(G id);
}
package com.henry.service; import com.henry.model.brand.Brand; import com.henry.repository.brand.BrandRepository; import org.springframework.stereotype.Service; @Service public final class BrandServiceImpl implements DefaultService<Brand, Long> { private final BrandRepository brandRepository; public BrandServiceImpl(BrandRepository brandRepository) { this.brandRepository = brandRepository; } @Override public Brand save(Brand obj) { return brandRepository.save(obj); } @Override public Iterable<Brand> findAll() { return brandRepository.findAll(); } @Override public Brand findById(Long id) { return brandRepository.findById(id).get(); } }
package com.henry.service; import com.henry.model.company.Company; import com.henry.repository.company.CompanyRepository; import org.springframework.stereotype.Service; @Service public final class CompanyServiceImpl implements DefaultService<Company, Long> { private final CompanyRepository companyRepository; public CompanyServiceImpl(CompanyRepository companyRepository) { this.companyRepository = companyRepository; } @Override public Company save(Company obj) { return companyRepository.save(obj); } @Override public Iterable<Company> findAll() { return companyRepository.findAll(); } @Override public Company findById(Long id) { return companyRepository.findById(id).get(); } }
package com.henry.service; import com.henry.model.user.User; import com.henry.repository.user.UserRepository; import org.springframework.stereotype.Service; @Service public final class UserServiceImpl implements DefaultService<User,Long> { private final UserRepository userRepository; public UserServiceImpl(UserRepository userRepository) { this.userRepository = userRepository; } @Override public User save(User obj) { return userRepository.save(obj); } @Override public Iterable<User> findAll() { return userRepository.findAll(); } @Override public User findById(Long id) { return userRepository.findById(id).get(); } }
REST Controllers
REST controllers (BrandController, CompanyController, UserController) handle HTTP requests for creating entities:
package com.henry.controller; import com.henry.model.brand.Brand; import com.henry.service.DefaultService; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api/v3") public class BrandController { private final DefaultService<Brand, Long> defaultService; public BrandController(DefaultService<Brand, Long> defaultService) { this.defaultService = defaultService; } @PostMapping("/brands") public Brand createEmployee(@RequestBody Brand brand) { return defaultService.save(brand); } }
package com.henry.controller; import com.henry.model.company.Company; import com.henry.service.DefaultService; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api/v2") public class CompanyController { private final DefaultService<Company,Long> defaultService; public CompanyController(DefaultService<Company, Long> defaultService) { this.defaultService = defaultService; } @PostMapping("/companies") public Company createEmployee(@RequestBody Company company) { return defaultService.save(company); } }
package com.henry.controller;
import com.henry.model.user.User;
import com.henry.service.DefaultService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/v1")
public class UserController {
private final DefaultService<User,Long> defaultService;
public UserController(DefaultService<User, Long> defaultService) {
this.defaultService = defaultService;
}
@PostMapping("/users")
public User createEmployee(@RequestBody User user) {
return defaultService.save(user);
}
}
Test Classes
JUnit test classes (BrandServiceTest, CompanyServiceTest, UserServiceTest) use Mockito for mocking dependencies:
package com.henry;
import com.google.common.collect.Iterables;
import com.henry.model.brand.Brand;
import com.henry.repository.brand.BrandRepository;
import com.henry.service.BrandServiceImpl;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Arrays;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class BrandServiceTest {
@Mock
private BrandRepository brandRepository;
@InjectMocks
private BrandServiceImpl brandService;
@Test
void testSaveBrand() {
Brand brand = Brand.builder()
.id(1L)
.name("Test Brand")
.build();
when(brandRepository.save(any())).thenReturn(brand);
Brand saved = brandService.save(brand);
assertEquals(brand, saved);
verify(brandRepository).save(any());
}
@Test
void testFindAllBrands() {
Brand brand1 = Brand.builder()
.id(1L)
.name("Test Brand")
.build();
Brand brand2 = Brand.builder()
.id(2L)
.name("Demo Brand")
.build();
when(brandRepository.findAll()).thenReturn(Arrays.asList(brand1, brand2));
Iterable<Brand> result = brandService.findAll();
assertEquals(2, Iterables.size(result));
verify(brandRepository).findAll();
}
@Test
void testFindBrandById() {
Brand brand = Brand.builder()
.id(1L)
.name("Demo Brand")
.build();
when(brandRepository.findById(1L)).thenReturn(Optional.of(brand));
Brand result = brandService.findById(1L);
assertEquals(brand, result);
verify(brandRepository).findById(1L);
}
}
package com.henry;
import com.google.common.collect.Iterables;
import com.henry.model.company.Company;
import com.henry.repository.company.CompanyRepository;
import com.henry.service.CompanyServiceImpl;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Arrays;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class CompanyServiceTest {
@Mock
private CompanyRepository companyRepository;
@InjectMocks
private CompanyServiceImpl companyService;
@Test
void testSaveCompany() {
Company company =
Company.builder()
.id(1L)
.name("Test Corp")
.build();
when(companyRepository.save(any())).thenReturn(company);
Company saved = companyService.save(company);
assertEquals(company, saved);
verify(companyRepository).save(any());
}
@Test
void testFindAllCompanies() {
Company comp1 = Company.builder()
.id(1L)
.name("Test Corp")
.build();
Company comp2 = Company.builder()
.id(2L)
.name("Demo Corp")
.build();
when(companyRepository.findAll()).thenReturn(Arrays.asList(comp1, comp2));
Iterable<Company> result = companyService.findAll();
assertEquals(2, Iterables.size(result));
verify(companyRepository).findAll();
}
@Test
void testFindCompanyById() {
Company company = Company.builder()
.id(1L)
.name("Test Corp")
.build();
when(companyRepository.findById(1L)).thenReturn(Optional.of(company));
Company result = companyService.findById(1L);
assertEquals(company, result);
verify(companyRepository).findById(1L);
}
}
package com.henry;
import com.google.common.collect.Iterables;
import com.henry.model.user.User;
import com.henry.repository.user.UserRepository;
import com.henry.service.UserServiceImpl;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Arrays;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
public class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserServiceImpl userService;
@Test
public void saveUser_shouldPersistUser() {
/**
int x = 10;
int y = 20;
String result = STR."\{x} + \{y} = \{x + y}";
string templates are a preview feature and are disabled by default.
Are string templates supported yet? - IntelliJ support - JetBrains
https://intellij-support.jetbrains.com/hc/en-us/community/posts/13451540436114-Are-string-templates-supported-yet-
**/
// Create a User
User user = User.builder()
.id(1L)
.name("John")
.lastName("Doe")
.build();
when(userRepository.save(any())).thenReturn(user);
User saved = userService.save(user);
assertEquals(user, saved);
verify(userRepository).save(any());
}
@Test
void testFindAllUsers() {
User user1 = User.builder()
.id(1L)
.name("John")
.lastName("Doe")
.build();
User user2 = User.builder()
.id(2L)
.name("John")
.lastName("Doe")
.build();
when(userRepository.findAll()).thenReturn(Arrays.asList(user1, user2));
Iterable<User> result = userService.findAll();
assertEquals(2, Iterables.size(result));
verify(userRepository).findAll();
}
@Test
void testFindUserById() {
User user = User.builder()
.id(1L)
.name("John")
.lastName("Doe")
.build();
when(userRepository.findById(1L)).thenReturn(Optional.of(user));
User result = userService.findById(1L);
assertEquals(user, result);
verify(userRepository).findById(1L);
}
}
Maven Configuration
The pom.xml file manages project dependencies and build configuration:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.henry</groupId>
<artifactId>multiple-data-sources-jpa</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>multiple-data-sources-jpa</name>
<description>Demo project multiple data sources jpa</description>
<properties>
<java.version>21</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!-- Exclude the Tomcat dependency -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Use Jetty instead -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- MARIADB Connector -->
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
</dependency>
<!-- Mysql Connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<!-- ORACLE database driver -->
<!-- https://mvnrepository.com/artifact/oracle/ojdbc6 -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.4</version>
</dependency>
<!-- POSTGRESQL database driver -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.antlr/stringtemplate
<dependency>
<groupId>org.antlr</groupId>
<artifactId>stringtemplate</artifactId>
<version>4.0.2</version>
</dependency>
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>21</source>
<target>21</target>
<compilerArgs>--enable-preview</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>
Environment Setup with Docker Compose
To simplify the setup of your application's environment, you can use Docker Compose. Below is a docker-compose-multiple-db.yml file that defines services for Oracle, PostgreSQL, and MySQL databases:
version: '3'
services:
oracle:
image: pengbai/docker-oracle-xe-11g-r2
ports:
- "1521:1521"
- "8080:8080"
shm_size: 1g
postgres:
image: postgres:14.1
container_name: postgre_test
environment:
POSTGRES_USER: postgre_test
POSTGRES_PASSWORD: postgre_test
POSTGRES_DB: postgre_test
ports:
- "5432:5432"
mysql:
image: mysql/mysql-server:latest
container_name: mysql-docker-container
environment:
MYSQL_ROOT_PASSWORD: mypass
MYSQL_DATABASE: test_db
MYSQL_USER: test
MYSQL_PASSWORD: test_pass
ports:
- "3306:3306"
Run command:
docker-compose -f docker-compose-multiple-db.yml up -d
Only for oracle:
mvn install:install-file "-Dfile=path/to/your/ojdbc6.jar" "-DgroupId=com.oracle" "-DartifactId=ojdbc6" "-Dversion=11.2.0.4" "-Dpackaging=jar" "-DgeneratePom=true"
Run & Test
Run Spring Boot application with command: by console, IntelliJ etc.
mvn test -Dtest=UserServiceTest
mvn test -Dtest=BrandServiceTest
mvn test -Dtest=CompanyServiceTest
Run locally: mvn spring-boot:run
POST
http://localhost:9000/api/v1/users
POST
http://localhost:9000/api/v2/companies
POST
http://localhost:9000/api/v3/brands