在 Spring Boot 中配置多数据源可以满足一些复杂业务场景的需求,例如同时访问多个数据库。下面将详细介绍两种常见的配置多数据源的方法:使用 JdbcTemplate 和使用 Spring Data JPA。
方法一:使用 JdbcTemplate 配置多数据源
1. 添加依赖
在 pom.xml
中添加必要的依赖,以 MySQL 数据库为例:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
2. 配置数据源信息
在 application.properties
或 application.yml
中配置多个数据源的信息:
# 第一个数据源
spring.datasource.first.url=jdbc:mysql://localhost:3306/db1
spring.datasource.first.username=root
spring.datasource.first.password=password
spring.datasource.first.driver-class-name=com.mysql.cj.jdbc.Driver
# 第二个数据源
spring.datasource.second.url=jdbc:mysql://localhost:3306/db2
spring.datasource.second.username=root
spring.datasource.second.password=password
spring.datasource.second.driver-class-name=com.mysql.cj.jdbc.Driver
3. 配置数据源 Bean
创建一个配置类,用于配置多个数据源和对应的 JdbcTemplate
:
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
@Configuration
public class DataSourceConfig {
@Bean(name = "firstDataSource")
@ConfigurationProperties(prefix = "spring.datasource.first")
@Primary
public DataSource firstDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "secondDataSource")
@ConfigurationProperties(prefix = "spring.datasource.second")
public DataSource secondDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "firstJdbcTemplate")
public JdbcTemplate firstJdbcTemplate(@Qualifier("firstDataSource") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean(name = "secondJdbcTemplate")
public JdbcTemplate secondJdbcTemplate(@Qualifier("secondDataSource") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
在上述代码中,使用 @ConfigurationProperties
注解将配置文件中的数据源信息绑定到数据源 Bean 上,使用 @Primary
注解指定主数据源。同时,为每个数据源创建对应的 JdbcTemplate
Bean。
4. 使用多数据源
在服务类中注入不同的 JdbcTemplate
并使用:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
@Service
public class MultiDataSourceService {
@Autowired
@Qualifier("firstJdbcTemplate")
private JdbcTemplate firstJdbcTemplate;
@Autowired
@Qualifier("secondJdbcTemplate")
private JdbcTemplate secondJdbcTemplate;
public void useFirstDataSource() {
String sql = "SELECT COUNT(*) FROM table1";
Integer count = firstJdbcTemplate.queryForObject(sql, Integer.class);
System.out.println("第一个数据源的记录数: " + count);
}
public void useSecondDataSource() {
String sql = "SELECT COUNT(*) FROM table2";
Integer count = secondJdbcTemplate.queryForObject(sql, Integer.class);
System.out.println("第二个数据源的记录数: " + count);
}
}
方法二:使用 Spring Data JPA 配置多数据源
1. 添加依赖
在 pom.xml
中添加必要的依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
2. 配置数据源信息
同样在 application.properties
或 application.yml
中配置多个数据源的信息,与使用 JdbcTemplate
时的配置相同。
3. 配置数据源和 JPA 相关 Bean
创建两个配置类,分别配置两个数据源和对应的 JPA 相关 Bean:
第一个数据源配置类:
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
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.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
@Configuration
@EnableJpaRepositories(
entityManagerFactoryRef = "firstEntityManagerFactory",
transactionManagerRef = "firstTransactionManager",
basePackages = {"com.example.demo.repository.first"}
)
public class FirstDataSourceConfig {
@Bean(name = "firstDataSource")
@ConfigurationProperties(prefix = "spring.datasource.first")
@Primary
public DataSource firstDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "firstEntityManagerFactory")
@Primary
public LocalContainerEntityManagerFactoryBean firstEntityManagerFactory(
@Qualifier("firstDataSource") DataSource dataSource) {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource);
em.setPackagesToScan("com.example.demo.entity.first");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", "update");
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect");
em.setJpaPropertyMap(properties);
return em;
}
@Bean(name = "firstTransactionManager")
@Primary
public PlatformTransactionManager firstTransactionManager(
@Qualifier("firstEntityManagerFactory") LocalContainerEntityManagerFactoryBean entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory.getObject());
}
}
第二个数据源配置类:
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
@Configuration
@EnableJpaRepositories(
entityManagerFactoryRef = "secondEntityManagerFactory",
transactionManagerRef = "secondTransactionManager",
basePackages = {"com.example.demo.repository.second"}
)
public class SecondDataSourceConfig {
@Bean(name = "secondDataSource")
@ConfigurationProperties(prefix = "spring.datasource.second")
public DataSource secondDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "secondEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean secondEntityManagerFactory(
@Qualifier("secondDataSource") DataSource dataSource) {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource);
em.setPackagesToScan("com.example.demo.entity.second");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", "update");
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect");
em.setJpaPropertyMap(properties);
return em;
}
@Bean(name = "secondTransactionManager")
public PlatformTransactionManager secondTransactionManager(
@Qualifier("secondEntityManagerFactory") LocalContainerEntityManagerFactoryBean entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory.getObject());
}
}
4. 创建实体类和 Repository 接口
分别为两个数据源创建对应的实体类和 Repository 接口,并将它们放在不同的包下,与配置类中的 basePackages
对应。
第一个数据源的实体类和 Repository 接口示例:
// 实体类
package com.example.demo.entity.first;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class FirstEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// 省略 getter 和 setter 方法
}
// Repository 接口
package com.example.demo.repository.first;
import com.example.demo.entity.first.FirstEntity;
import org.springframework.data.jpa.repository.JpaRepository;
public interface FirstRepository extends JpaRepository<FirstEntity, Long> {
}
第二个数据源的实体类和 Repository 接口示例:
// 实体类
package com.example.demo.entity.second;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class SecondEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String description;
// 省略 getter 和 setter 方法
}
// Repository 接口
package com.example.demo.repository.second;
import com.example.demo.entity.second.SecondEntity;
import org.springframework.data.jpa.repository.JpaRepository;
public interface SecondRepository extends JpaRepository<SecondEntity, Long> {
}
5. 使用多数据源
在服务类中注入不同的 Repository 并使用:
import com.example.demo.repository.first.FirstRepository;
import com.example.demo.repository.second.SecondRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MultiDataSourceJpaService {
@Autowired
private FirstRepository firstRepository;
@Autowired
private SecondRepository secondRepository;
public void useFirstDataSource() {
long count = firstRepository.count();
System.out.println("第一个数据源的记录数: " + count);
}
public void useSecondDataSource() {
long count = secondRepository.count();
System.out.println("第二个数据源的记录数: " + count);
}
}
通过以上两种方法,你可以在 Spring Boot 中配置和使用多数据源。使用 JdbcTemplate
适用于简单的 SQL 操作,而使用 Spring Data JPA 则更适合于基于对象的持久化操作。