Kết nối Nhiều Cơ Sở Dữ Liệu trong JPA sử dụng Docker Compose

11 tháng 09, 2023 - 918 lượt xem

1. Giới thiệu

Trong quá trình phát triển ứng dụng, việc làm việc với nhiều cơ sở dữ liệu có thể là một yêu cầu thường gặp. Ví dụ, bạn có thể muốn lưu trữ dữ liệu bài viết trong MySQL và dữ liệu khách hàng trong PostgreSQL. Trong bài viết này, chúng ta sẽ tìm hiểu cách kết nối đến cả MySQL và PostgreSQL trong một ứng dụng Spring Boot sử dụng JPA. Chúng ta cũng sẽ sử dụng Docker Compose để quản lý môi trường phát triển, giúp dễ dàng triển khai cơ sở dữ liệu.

2. Cài đặt databases

Cài đặt Docker và Docker Compose

Trước khi bắt đầu, bạn cần cài đặt DockerDocker Compose.

  • Docker là một nền tảng cho phép bạn đóng gói và triển khai ứng dụng trong các container độc lập. Hãy cài đặt Docker bằng cách làm theo hướng dẫn tại đây.
  • Docker Compose là một công cụ cho phép bạn định nghĩa và quản lý một nhóm các container Docker sử dụng một tệp cấu hình duy nhất. Hãy cài đặt Docker Compose theo hướng dẫn tại đây.

Tạo tệp docker-compose.yml

Chúng ta sẽ sử dụng Docker Compose để quản lý các container cho cơ sở dữ liệu. Dưới đây là một tệp docker-compose.yml mẫu:

version: '3'
services:
  mysql-db:
    image: mysql:latest
    container_name: mysql-container
    environment:
      MYSQL_ROOT_PASSWORD: 123
    ports:
      - "3306:3306"
    networks:
      - db-network
    volumes:
      - mysql-data:/var/lib/mysql

  postgres-db:
    image: postgres:latest
    container_name: postgres-container
    environment:
      POSTGRES_PASSWORD: 123
    ports:
      - "5432:5432"
    networks:
      - db-network
    volumes:
      - postgres-data:/var/lib/postgresql/data

networks:
  db-network:
    driver: bridge

volumes:
  mysql-data:
  postgres-data:

Trong ví dụ trên, chúng ta định nghĩa hai container: một cho MySQL và một cho PostgreSQL, và cấu hình các biến môi trường cần thiết.

3. Thiết Lập Ứng Dụng Spring Boot

Cấu trúc folder của ứng dụng

.
├── HELP.md
├── docker-compose.yml
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
   └── main
        ├── java
        │   └── com
        │       └── example
        │           └── demo
        │               ├── DemoMutilpleDatabaseApplication.java
        │               ├── config
        │               │   ├── DB1Config.java
        │               │   └── DB2Config.java
        │               ├── db1
        │               │   ├── Post.java
        │               │   └── PostRepository.java
        │               └── db2
        │                   ├── Customer.java
        │                   └── CustomerRepository.java
        └── resources
            └── application.properties

Tạo Các Entity

Trong phần này, chúng ta sẽ tạo các Entity cho MySQL và PostgreSQL.

Entity cho MySQL

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Entity
@Table(name = "post")
public class Post {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    private Integer id;

    @Column(name = "name")
    private String title;

    public Post(String title) {
        this.title = title;
    }
}
Post.java

Entity cho PostgreSQL

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Entity
@Table(name = "customer")
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    private Integer id;

    @Column(name = "name")
    private String name;
    
    public Customer(String name) {
        this.name = name;
    }
}
Customer.java

4. Tạo Repository

Bạn có thể sử dụng các repository để thao tác với cơ sở dữ liệu.

Tạo Repository cho MySQL

public interface PostRepository extends JpaRepository<Post, Integer> {
}
PostRepository.java

Tạo Repository cho PostgreSQL

public interface CustomerRepository extends JpaRepository<Customer, Integer> {
}
CustomerRepository.java

5. Cấu Hình Multiple Data Sources

Cấu hình application.properties

Trong tệp application.properties, bạn cần cấu hình các thuộc tính kết nối cơ sở dữ liệu cho MySQL và PostgreSQL:

# MySQL Configuration
post.datasource.url=jdbc:mysql://localhost:3306/dbpost
post.datasource.username=root
post.datasource.password=123
post.datasource.driverClassName=com.mysql.cj.jdbc.Driver

# PostgreSQL Configuration
customer.datasource.url=jdbc:postgresql://localhost:5432/dbcustomer
customer.datasource.username=postgres
customer.datasource.password=123
customer.datasource.driverClassName=org.postgresql.Driver

Cấu hình Data Source

Bây giờ chúng ta sẽ đến phần cấu hình cho Database. Chúng ta sẽ thiết lập 2 lớp cấu hình - một Post và một Customer.

Trong mỗi lớp cấu hình, chúng ta cần định nghĩa các thành phần sau:

  • DataSource
  • EntityManagerFactory
  • TransactionManager

Trước tiên, chúng ta cấu hình database Mysql cho entity Post

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "postEntityManagerFactory",
        basePackages 	 = {"com.example.demo.db1"},
        transactionManagerRef = "postTransactionManager"
)
public class DB1Config {
    private final Environment env;

    public DB1Config(Environment env) {
        this.env = env;
    }

    @Primary
    @Bean(name= "postDataSource")
    public DataSource dataSource() {
        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setUrl(env.getProperty("post.datasource.url"));
        ds.setUsername(env.getProperty("post.datasource.username"));
        ds.setPassword(env.getProperty("post.datasource.password"));
        ds.setDriverClassName(env.getProperty("post.datasource.driverClassName"));
        return ds;
    }


    @Primary
    @Bean(name= "postEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManager() {
        LocalContainerEntityManagerFactoryBean bean = new LocalContainerEntityManagerFactoryBean();
        bean.setDataSource(dataSource());
        JpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
        bean.setJpaVendorAdapter(adapter);
        HashMap<String,Object> properties = new HashMap<>();
        properties.put("hibernate.show_sql", "true");
        properties.put("hibernate.hbm2ddl.auto", "update");
        properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
        bean.setJpaPropertyMap(properties);
        bean.setPackagesToScan("com.example.demo.db1");
        return bean;
    }

    @Primary
    @Bean("postTransactionManager")
    public PlatformTransactionManager transactionManager(@Qualifier("postEntityManagerFactory") EntityManagerFactory entityManagerFactory ) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}
DB1Config.java

Tiếp theo chúng ta tiến hành cấu hình tương tự với database Postgresql cho entity Customer

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "customerEntityManagerFactory",
        basePackages 	 = {"com.example.demo.db2"},
        transactionManagerRef = "customerTransactionManager"
)
public class DB2Config {
    private final Environment env;

    public DB2Config(Environment env) {
        this.env = env;
    }

    @Primary
    @Bean(name= "customerDataSource")
    public DataSource dataSource() {
        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setUrl(env.getProperty("customer.datasource.url"));
        ds.setUsername(env.getProperty("customer.datasource.username"));
        ds.setPassword(env.getProperty("customer.datasource.password"));
        ds.setDriverClassName(env.getProperty("customer.datasource.driverClassName"));
        return ds;
    }

    @Primary
    @Bean(name= "customerEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManager() {
        LocalContainerEntityManagerFactoryBean bean = new LocalContainerEntityManagerFactoryBean();
        bean.setDataSource(dataSource());
        JpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
        bean.setJpaVendorAdapter(adapter);
        HashMap<String,Object> properties = new HashMap<>();
        properties.put("hibernate.show_sql", "true");
        properties.put("hibernate.hbm2ddl.auto", "update");
        properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
        bean.setJpaPropertyMap(properties);
        bean.setPackagesToScan("com.example.demo.db2");
        return bean;
    }

    @Primary
    @Bean("customerTransactionManager")
    public PlatformTransactionManager transactionManager(@Qualifier("customerEntityManagerFactory") EntityManagerFactory entityManagerFactory ) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}
DB2Config.java

6. Kiểm Tra Kết Nối và Thử Nghiệm

Trong phần này, bạn có thể thực hiện các thao tác CRUD với cơ sở dữ liệu MySQL và PostgreSQL sử dụng repository.

@SpringBootApplication
public class DemoMutilpleDatabaseApplication implements CommandLineRunner {
    private final PostRepository postRepository;
    private final CustomerRepository customerRepository;

    public DemoMutilpleDatabaseApplication(PostRepository postRepository, CustomerRepository customerRepository) {
        this.postRepository = postRepository;
        this.customerRepository = customerRepository;
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoMutilpleDatabaseApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        // Lưu Post - MySQL
        Post post = new Post("Kết Nối Nhiều Cơ Sở Dữ Liệu trong JPA");
        postRepository.save(post);
        
        // Lưu Customer - Postgresql
        Customer customer = new Customer("Nguyễn Văn A");
        customerRepository.save(customer);
        
        // Thông tin Post
        List<Post> postList = postRepository.findAll();
        System.out.println("Danh sách Post");
        postList.forEach(System.out::println);

        // Thông tin customer
        List<Customer> customerList = customerRepository.findAll();
        System.out.println("Danh sách Customer");
        customerList.forEach(System.out::println);
    }
}

Kết quả in ra trong màn hình terminal

kết quả insert data

7. Kết Luận

Trong bài viết này, chúng ta đã thảo luận về cách kết nối nhiều cơ sở dữ liệu trong ứng dụng Spring Boot sử dụng JPA và Docker Compose. Chúng ta đã tạo cấu hình, entity, repository và thực hiện thao tác CRUD với cả MySQL và PostgreSQL.

Lợi Ích của Việc Kết Nối Nhiều Cơ Sở Dữ Liệu

  • Khả năng sử dụng nhiều cơ sở dữ liệu trong một ứng dụng.
  • Tích hợp dữ liệu từ các nguồn khác nhau.
  • Tối ưu hóa hiệu suất và quản lý dữ liệu hiệu quả.

8. Tài Liệu Tham Khảo

Link source code github : https://github.com/buihien0109/springboot-course/tree/main/demo-mutilple-database

Tài Liệu Tham Khảo

Lưu ý: Trong ví dụ này, mình đã sử dụng các giá trị cụ thể cho tên người dùng, mật khẩu và các thông số kết nối cơ sở dữ liệu. Bạn nên thay đổi chúng để phù hợp với môi trường của bạn.

Bình luận

avatar
Phạm Thị Mẫn 2023-09-11 03:55:32.334339 +0000 UTC

Bài viết hay quá

Avatar
* Vui lòng trước khi bình luận.
Ảnh đại diện
  +1 Thích
+1