SoFunction
Updated on 2025-04-14

Summary of three implementation methods of Java multi-data source

1. When will multiple data sources be used?

In Java development, "multi-data source" refers to configuring and using multiple different database connections in one application. Typically, a Java application connects to a single database. However, in some complex application scenarios, multiple different databases may be required, and multiple data sources need to be configured.

1.1. Specific meaning of multiple data sources

  • Multiple database instances: Multiple data sources can refer to multiple database instances of the same type (such as MySQL). For example, an application may need to connect to two different MySQL databases simultaneously, one for storing user information and the other for storing order information.
  • Different types of databases: Multiple data sources can also refer to different types of databases. For example, an application may need to connect to a MySQL database to store user information, and also to an Oracle database to store financial data.
  • Different access policies: Multi-data source configuration may also be used to implement different database access policies, such as read-write separation (one data source is used for write operations and the other is used for read operations), or different tenants use different data sources under a multi-tenant architecture.

1.2. Why do you need multiple data sources?

  • Business Requirements: Different business modules may need to be stored in different databases. For example, financial data and user data may be stored in two separate databases separately for better management and security control.
  • System architecture: In large distributed systems, sub-stores and tables are usually used to deal with the challenge of massive data, and different database instances may be distributed on different servers.
  • Read and write separation: In order to improve the performance of the system, especially in high concurrency scenarios, it is common to separate the read and write operations of the database. Read operations can obtain data from multiple read-only slave libraries (Slaves), while write operations are written to the master library (Master).
  • Migration or compatibility: During the system migration or upgrade process, you may need to access both new and old database systems at the same time, or you may need to be compatible with different versions of the database.
  • Multi-tenant support: In SaaS applications, each tenant's data may be isolated and stored in a different database to ensure the independence and security of the data.

2. Three ways to implement multiple data sources in Java

2.1 Based on AbstractRoutingDataSource provided by Spring

Implementing multi-data source configuration using AbstractRoutingDataSource provided by Spring is an effective method for dynamic data source management. By inheriting AbstractRoutingDataSource, you can dynamically select the data source to use based on certain conditions (such as request context, current thread information, etc.). This method is very suitable for scenarios where data sources need to be switched dynamically according to business logic, such as read and write separation, library division and table division, etc.
The detailed steps for implementing multi-data source configuration based on AbstractRoutingDataSource are as follows:

2.1.1 Create a DynamicDataSource class

First, create a class that inherits AbstractRoutingDataSource to implement the dynamic switching logic of the data source.

@Component
@Primary
public class DynamicDataSource extends AbstractRoutingDataSource {
    // The data source identifier currently used    public static ThreadLocal<String> name=new ThreadLocal<>();
    // Write data source    @Autowired
    DataSource dataSource1;
    // Read data source    @Autowired
    DataSource dataSource2;

    @Override
    protected Object determineCurrentLookupKey() {
        return ();
    }
    @Override
    public void afterPropertiesSet() {
        // Initialize all data sources for targetDataSources        Map<Object, Object> targetDataSources=new HashMap<>();
        ("W",dataSource1);
        ("R",dataSource2);

        (targetDataSources);

        // Set the default data source for defaultTargetDataSource        (dataSource1);

        ();

    }

}

2.1.2 Configuring the data source

Next, we need to configure multiple data sources.

@Configuration
public class DataSourceConfig {
	/**
		database1Configuration
	/
    @Bean
    @ConfigurationProperties(prefix = ".datasource1")
    public DataSource dataSource1() {
        // The underlying layer will automatically get the configuration and create a DruidDataSource        return ().build();
    }

	/**
		database2Configuration
	/
    @Bean
    @ConfigurationProperties(prefix = ".datasource2")
    public DataSource dataSource2() {
        // The underlying layer will automatically get the configuration and create a DruidDataSource        return ().build();
    }
    @Bean
    public DataSourceTransactionManager transactionManager1(DynamicDataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        (dataSource);
        return dataSourceTransactionManager;
    }

    @Bean
    public DataSourceTransactionManager transactionManager2(DynamicDataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        (dataSource);
        return dataSourceTransactionManager;
    }
}

2.1.3 Custom annotations to facilitate the distinction between different data sources

At the business layer, we can set the identifier of the current data source to dynamically switch the data source by annotating.

@Target({,})
@Retention()
public @interface WR {
    String value() default "W";
}

At the business layer, we can set the identifier of the current data source to dynamically switch the data source by annotating. After registering the DynamicDataSource you implemented as the default DataSource instance, you only need to change the name ID in advance every time you use DataSource to quickly switch the data source.

@Component
@Aspect
public class DynamicDataSourceAspect implements Ordered {
    // Front    @Before("within(.dynamic_datasource..*) && @annotation(wr)")
    public void before(JoinPoint point, WR wr){
        String name = ();
        (name);
    }
    @Override
    public int getOrder() {
        return 0;
    }
}

2.1.4 Service sets data source through annotations

Add annotations to the specific usage methods of the business layer to realize data source switching

@Service
public class UserImplService implements UserService {

    @Autowired
    UserMapper userMapper;


    @Override
    @WR("R")        // Library 1    public List<User> list() {
        return ();
    }

    @Override
    @WR("W")        // Library 2    public void save(User friend) {
        (friend);
    }
}

2.2 Register multiple SqlSessionFactory using MyBatis

In a Spring environment, if there are multiple data sources and you need to configure separate SqlSessionFactory and SqlSessionTemplate for each data source, you can do this by configuring multiple SqlSessionFactory. If you want to register multiple data sources using the MyBatis framework, you need to manually register the core objects such as DataSource, SqlSessionFactory, and DataSourceTransactionManager under MyBatis.

The detailed steps for implementing multi-data source configuration based on MyBatis are as follows:

2.2.1 Registration of different data sources

Data source 1:

@Configuration
// Inherit mybatis:// 1. Specify the scanned mapper interface package (main library)// 2. Specify which sqlSessionFactory is used (main library)@MapperScan(basePackages = ".dynamic_datasource_mybatis.",
        sqlSessionFactoryRef="wSqlSessionFactory")
public class WMyBatisConfig {
    @Bean
    @ConfigurationProperties(prefix = ".datasource1")
    public DataSource dataSource1() {
        // The underlying layer will automatically get the configuration and create a DruidDataSource        return ().build();
    }

    @Bean
    @Primary
    public SqlSessionFactory wSqlSessionFactory()
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        // Specify the main library        (dataSource1());
        // You can manually specify the corresponding files of the main library        /*(new PathMatchingResourcePatternResolver()
                .getResources("classpath:mapper/order/*.xml"));*/
        return ();
    }

    @Bean
    @Primary
    public DataSourceTransactionManager wTransactionManager(){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        (dataSource1());
        return dataSourceTransactionManager;
    }


    @Bean
    public TransactionTemplate wTransactionTemplate(){
        return new TransactionTemplate(wTransactionManager());
    }
}

Data Source 2:

@Configuration
// Inherit mybatis:// 1. Specify the scanned mapper interface package (main library)// 2. Specify which sqlSessionFactory is used (main library)@MapperScan(basePackages = ".dynamic_datasource_mybatis.",
        sqlSessionFactoryRef="rSqlSessionFactory")
public class RMyBatisConfig {
    @Bean
    @ConfigurationProperties(prefix = ".datasource2")
    public DataSource dataSource2() {
        // The underlying layer will automatically get the configuration and create a DruidDataSource        return ().build();
    }

    @Bean
    @Primary
    public SqlSessionFactory rSqlSessionFactory()
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        // Specify the main library        (dataSource2());
        // You can manually specify the corresponding files of the main library        /*(new PathMatchingResourcePatternResolver()
                .getResources("classpath:mapper/r/*.xml"));*/
        return ();
    }



    @Bean
    public DataSourceTransactionManager rTransactionManager(){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        (dataSource2());
        return dataSourceTransactionManager;
    }

    @Bean
    public TransactionTemplate rTransactionTemplate(){
        return new TransactionTemplate(rTransactionManager());
    }

2.2.2 Specific use of the business layer

In an application, when the specific DAO layer uses SqlSessionFactory and SqlSessionTemplate, MyBatis will use the corresponding data source according to the package path specified by @MapperScan.

@Service
public class UserImplService implements UserService {

    @Autowired
    private RUserMapper rFriendMapper;

    @Autowired
    private WUserMapper wFriendMapper;
    // Read -- Read library    @Override
    public List<User> list() {
        return ();
    }

    // Save -- Write library    @Override
    public void save(User user) {
        (user);
    }


    // Save -- Write library    @Override
    public void saveW(User user) {
        ("xman11");
        (user);
    }

    // Save -- Read library    @Override
    public void saveR(User user) {
        ("xman");
        (user);
    }
}

2.3 Using dynamic-datasource framework

Multi-datasource configuration in Java projects is very convenient to use the dynamic-datasource-spring-boot-starter framework. This framework can support automatic switching of multiple data sources, configuration management of dynamic data sources and other functions.
The detailed steps for implementing multi-data source configuration based on the dynamic-datasource-spring-boot-starter framework are as follows:

2.3.1 Add dependencies

First, you need to add the dependency of dynamic-datasource-spring-boot-starter in the file.

<dependency>
    <groupId></groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>3.5.0</version> <!-- Please adjust the version according to the project needs -->
</dependency>

2.3.2 Configuring the data source

Configure multiple data sources in the file. Each data source can be given a unique name (such as master and slave)

spring:
  datasource:
    dynamic:
      primary: master # Default data source or data source group, which is used when no data source is specified      strict: false # Set to true to check whether the data source in the configuration file is valid      datasource:
        master: # Data Source 1          driver-class-name: 
          url: jdbc:mysql://localhost:3306/master_db
          username: master_user
          password: master_pass
        slave: # Data Source Two          driver-class-name: 
          url: jdbc:mysql://localhost:3306/slave_db
          username: slave_user
          password: slave_pass

2.3.3 Configuring the data source

Use the @DS annotation to specify that a method or class uses a specific data source.

@Service
public class UserImplService implements UserService {

    @Autowired
    UserMapper userMapper;

    @Override
    @DS("master")
    public void save(User user) {
        (user);
    }
    @Override
    @DS("slave_1")  // From the library, if multiple configurations are configured according to the underscore naming method, you can specify the prefix (group name)    public List<User> list() {
        return ();
    }
}

For MyBatis, dynamic-datasource also applies. Just configure MyBatis normally and use the @DS annotation on the Mapper method.

import ;
import ;
import ;

@Mapper
public interface UserMapper {

    @DS("master")
    @Select("SELECT * FROM user WHERE id = #{id}")
    User getUserFromMaster(int id);

    @DS("slave")
    @Select("SELECT * FROM user WHERE id = #{id}")
    User getUserFromSlave(int id);
}

The dynamic-datasource framework provides a simple and efficient way to implement multi-data source configuration and dynamic switching. Through annotation, you can easily switch data sources to meet the needs of multiple data sources in your business.

3 Summary

These three ways to implement multiple data sources have their own advantages and disadvantages and are suitable for different scenarios. The specific method to choose must be judged based on actual needs. In addition, the way to configure multiple data sources is more than that. For example, when using Spring Data JPA, you can also implement multiple data sources by configuring multiple EntityManagers. Each EntityManager can be associated with a specific DataSource, enabling operations on multiple databases. Therefore, in multi-data source configuration, it is crucial to flexibly choose the appropriate solution.

Source code address:/arkhamYJ/

This is the end of this article about the three implementation methods of Java multi-data source. For more related Java multi-data source content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!