diff --git a/spring-boot-modules/flyway-multidb-springboot/pom.xml b/spring-boot-modules/flyway-multidb-springboot/pom.xml new file mode 100644 index 000000000000..ddec01826dc3 --- /dev/null +++ b/spring-boot-modules/flyway-multidb-springboot/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + flyway-multidb-springboot + 0.0.1-SNAPSHOT + flyway-multidb-springboot + This is simple boot application for Spring boot multiple flyway database + + + com.baeldung.spring-boot-modules + spring-boot-modules + 1.0.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter-data-jpa + 3.2.3 + + + org.flywaydb + flyway-core + 9.22.3 + + + com.h2database + h2 + 2.2.224 + runtime + + + org.springframework.boot + spring-boot-starter-test + 3.2.3 + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + \ No newline at end of file diff --git a/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/FlywayMultidbApplication.java b/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/FlywayMultidbApplication.java new file mode 100644 index 000000000000..cd411268b4d4 --- /dev/null +++ b/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/FlywayMultidbApplication.java @@ -0,0 +1,13 @@ +package com.baeldung; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication(scanBasePackages = "com.baeldung") +public class FlywayMultidbApplication { + + public static void main(String[] args) { + SpringApplication.run(FlywayMultidbApplication.class, args); + } + +} diff --git a/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/config/ProductDbConfig.java b/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/config/ProductDbConfig.java new file mode 100644 index 000000000000..63d9a299192a --- /dev/null +++ b/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/config/ProductDbConfig.java @@ -0,0 +1,62 @@ +package com.baeldung.config; + +import jakarta.annotation.PostConstruct; +import javax.sql.DataSource; +import java.util.Map; +import jakarta.persistence.EntityManagerFactory; +import org.flywaydb.core.Flyway; +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; +import org.springframework.context.annotation.*; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.orm.jpa.*; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@Configuration +@EnableTransactionManagement +@EnableJpaRepositories( + basePackages = "com.baeldung.repository.product", + entityManagerFactoryRef = "productEntityManagerFactory", + transactionManagerRef = "productTransactionManager" +) +public class ProductDbConfig { + + @Bean + public DataSource productDataSource() { + return DataSourceBuilder.create() + .url("jdbc:h2:mem:productdb") + .username("sa") + .password("") + .driverClassName("org.h2.Driver") + .build(); + } + + @Bean + public LocalContainerEntityManagerFactoryBean productEntityManagerFactory( + EntityManagerFactoryBuilder builder) { + + return builder + .dataSource(productDataSource()) + .packages("com.baeldung.entity") + .persistenceUnit("productPU") + .properties(Map.of("hibernate.hbm2ddl.auto", "none")) + .build(); + } + + @Bean + public PlatformTransactionManager productTransactionManager( + EntityManagerFactory productEntityManagerFactory) { + + return new JpaTransactionManager(productEntityManagerFactory); + } + + @PostConstruct + public void migrateProductDb() { + Flyway.configure() + .dataSource(productDataSource()) + .locations("classpath:db/migration/productdb") + .load() + .migrate(); + } +} diff --git a/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/config/UserDbConfig.java b/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/config/UserDbConfig.java new file mode 100644 index 000000000000..ca9148e6f7f1 --- /dev/null +++ b/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/config/UserDbConfig.java @@ -0,0 +1,69 @@ +package com.baeldung.config; + +import jakarta.annotation.PostConstruct; +import jakarta.persistence.EntityManagerFactory; +import org.flywaydb.core.Flyway; +import java.util.Map; +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; +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.orm.jpa.JpaTransactionManager; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import javax.sql.DataSource; + +@Configuration +@EnableTransactionManagement +@EnableJpaRepositories( + basePackages = "com.baeldung.repository.user", + entityManagerFactoryRef = "userEntityManagerFactory", + transactionManagerRef = "userTransactionManager" +) +public class UserDbConfig { + + @Bean + @Primary + public DataSource userDataSource() { + return DataSourceBuilder.create() + .url("jdbc:h2:mem:userdb") + .username("sa") + .password("") + .driverClassName("org.h2.Driver") + .build(); + } + + @Bean + @Primary + public LocalContainerEntityManagerFactoryBean userEntityManagerFactory( + EntityManagerFactoryBuilder builder) { + + return builder + .dataSource(userDataSource()) + .packages("com.baeldung.entity") + .persistenceUnit("userPU") + .properties(Map.of("hibernate.hbm2ddl.auto", "none")) + .build(); + } + + @Bean + @Primary + public PlatformTransactionManager userTransactionManager( + EntityManagerFactory userEntityManagerFactory) { + + return new JpaTransactionManager(userEntityManagerFactory); + } + + @PostConstruct + public void migrateUserDb() { + Flyway.configure() + .dataSource(userDataSource()) + .locations("classpath:db/migration/userdb") + .load() + .migrate(); + } +} diff --git a/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/entity/Product.java b/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/entity/Product.java new file mode 100644 index 000000000000..3e98de0f5a53 --- /dev/null +++ b/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/entity/Product.java @@ -0,0 +1,30 @@ +package com.baeldung.entity; + +import jakarta.persistence.*; + +@Entity +@Table(name = "products") +public class Product { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "product_seq") + private Long id; + + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/entity/User.java b/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/entity/User.java new file mode 100644 index 000000000000..b240ac0e0130 --- /dev/null +++ b/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/entity/User.java @@ -0,0 +1,31 @@ +package com.baeldung.entity; + +import jakarta.persistence.*; + +@Entity +@Table(name = "users") +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String name; + + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/repository/product/ProductRepository.java b/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/repository/product/ProductRepository.java new file mode 100644 index 000000000000..8d31199fecfd --- /dev/null +++ b/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/repository/product/ProductRepository.java @@ -0,0 +1,7 @@ +package com.baeldung.repository.product; + +import com.baeldung.entity.Product; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ProductRepository extends JpaRepository { +} diff --git a/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/repository/user/UserRepository.java b/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/repository/user/UserRepository.java new file mode 100644 index 000000000000..649bd3706d5f --- /dev/null +++ b/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/repository/user/UserRepository.java @@ -0,0 +1,7 @@ +package com.baeldung.repository.user; + +import com.baeldung.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface UserRepository extends JpaRepository { +} diff --git a/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/service/ProductService.java b/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/service/ProductService.java new file mode 100644 index 000000000000..a9cd0d947825 --- /dev/null +++ b/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/service/ProductService.java @@ -0,0 +1,27 @@ +package com.baeldung.service; + +import com.baeldung.entity.Product; +import com.baeldung.repository.product.ProductRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; + +@Service +public class ProductService { + + private final ProductRepository repo; + + public ProductService(ProductRepository repo) { + this.repo = repo; + } + + @Transactional("productTransactionManager") + public Product save(Product product) { + return repo.save(product); + } + + public Optional findById(Long id) { + return repo.findById(id); + } +} diff --git a/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/service/UserService.java b/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/service/UserService.java new file mode 100644 index 000000000000..a929380aca51 --- /dev/null +++ b/spring-boot-modules/flyway-multidb-springboot/src/main/java/com/baeldung/service/UserService.java @@ -0,0 +1,27 @@ +package com.baeldung.service; + +import com.baeldung.entity.User; +import com.baeldung.repository.user.UserRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; + +@Service +public class UserService { + + private final UserRepository repo; + + public UserService(UserRepository repo) { + this.repo = repo; + } + + @Transactional("userTransactionManager") + public User save(User user) { + return repo.save(user); + } + + public Optional findById(Long id) { + return repo.findById(id); + } +} diff --git a/spring-boot-modules/flyway-multidb-springboot/src/main/resources/application.yml b/spring-boot-modules/flyway-multidb-springboot/src/main/resources/application.yml new file mode 100644 index 000000000000..88eadb7d893d --- /dev/null +++ b/spring-boot-modules/flyway-multidb-springboot/src/main/resources/application.yml @@ -0,0 +1,27 @@ +spring: + datasource: + userdb: + url: jdbc:h2:mem:userdb + username: sa + password: + driver-class-name: org.h2.Driver + productdb: + url: jdbc:h2:mem:productdb + username: sa + password: + driver-class-name: org.h2.Driver + application: + name: flyway-multidb-springboot + + flyway: + enabled: false + jpa: + defer-datasource-initialization: false + hibernate: + ddl-auto: none + main: + allow-circular-references: true + h2: + console: + enabled: true + path: /h2-console \ No newline at end of file diff --git a/spring-boot-modules/flyway-multidb-springboot/src/main/resources/db.migration/productdb/V1__create_products_table.sql b/spring-boot-modules/flyway-multidb-springboot/src/main/resources/db.migration/productdb/V1__create_products_table.sql new file mode 100644 index 000000000000..3b317f23f059 --- /dev/null +++ b/spring-boot-modules/flyway-multidb-springboot/src/main/resources/db.migration/productdb/V1__create_products_table.sql @@ -0,0 +1,4 @@ +CREATE TABLE products ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) +); diff --git a/spring-boot-modules/flyway-multidb-springboot/src/main/resources/db.migration/userdb/V1__create_users_table.sql b/spring-boot-modules/flyway-multidb-springboot/src/main/resources/db.migration/userdb/V1__create_users_table.sql new file mode 100644 index 000000000000..8b0f2b19d25b --- /dev/null +++ b/spring-boot-modules/flyway-multidb-springboot/src/main/resources/db.migration/userdb/V1__create_users_table.sql @@ -0,0 +1,4 @@ +CREATE TABLE users ( + id BIGINT PRIMARY KEY, + name VARCHAR(255) +); \ No newline at end of file diff --git a/spring-boot-modules/flyway-multidb-springboot/src/test/java/com/baeldung/flyway_multidb/FlywayMultidbApplicationTests.java b/spring-boot-modules/flyway-multidb-springboot/src/test/java/com/baeldung/flyway_multidb/FlywayMultidbApplicationTests.java new file mode 100644 index 000000000000..9e83fb54d685 --- /dev/null +++ b/spring-boot-modules/flyway-multidb-springboot/src/test/java/com/baeldung/flyway_multidb/FlywayMultidbApplicationTests.java @@ -0,0 +1,13 @@ +package com.baeldung; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class FlywayMultidbApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/spring-boot-modules/flyway-multidb-springboot/src/test/java/com/baeldung/service/MultiDbServiceLiveTest.java b/spring-boot-modules/flyway-multidb-springboot/src/test/java/com/baeldung/service/MultiDbServiceLiveTest.java new file mode 100644 index 000000000000..7933daf37305 --- /dev/null +++ b/spring-boot-modules/flyway-multidb-springboot/src/test/java/com/baeldung/service/MultiDbServiceLiveTest.java @@ -0,0 +1,40 @@ +package com.baeldung.service; + +import com.baeldung.entity.User; +import com.baeldung.entity.Product; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.transaction.annotation.Transactional; +import com.baeldung.repository.user.UserRepository; +import com.baeldung.repository.product.ProductRepository; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +class MultiDbServiceLiveTest { + + @Autowired + private UserRepository userRepository; + + @Autowired + private ProductRepository productRepository; + + @Transactional("productTransactionManager") + @Test + void givenUsersAndProducts_whenSaved_thenFoundById() { + User user = new User(); + user.setName("John"); + userRepository.save(user); + + Product product = new Product(); + product.setName("Laptop"); + productRepository.save(product); + + assertTrue(userRepository.findById(user.getId()).isPresent()); + assertTrue(productRepository.findById(product.getId()).isPresent()); + } +} diff --git a/spring-boot-modules/pom.xml b/spring-boot-modules/pom.xml index 838b856b8814..0c6caab2ce93 100644 --- a/spring-boot-modules/pom.xml +++ b/spring-boot-modules/pom.xml @@ -17,6 +17,7 @@ + flyway-multidb-springboot spring-boot-admin spring-boot-angular spring-boot-annotations