# How to Configure Multiple Database Sources with dynamic-datasource in ContiNew-Admin

> Easily configure multiple database sources in ContiNew-Admin with dynamic-datasource. Route operations using YAML and @DS annotation without touching DAO code.

- Repository: [OpenContiNew/continew-admin](https://github.com/continew-org/continew-admin)
- Tags: how-to-guide
- Published: 2026-02-27

---

**ContiNew-Admin ships with `dynamic-datasource-spring-boot-starter` v4.3.1, enabling you to route database operations to different JDBC sources using YAML configuration and the `@DS` annotation without modifying existing DAO code.**

The ContiNew-Admin repository already integrates the dynamic-datasource ecosystem, making it trivial to configure multiple database sources for read-write splitting or multi-tenant scenarios. This article explains how to configure additional data sources in the existing YAML structure and route SQL operations using declarative annotations or programmatic context switching.

## How dynamic-datasource Works in ContiNew-Admin

The starter registers a `DynamicRoutingDataSource` bean that extends Spring's `AbstractRoutingDataSource`. At runtime, this bean maintains a map of named `DataSource` objects configured under the `spring.datasource.dynamic.datasource` block.

When a service method executes, the `@DS` annotation triggers a `MethodInterceptor` that pushes the specified data source key onto a thread-local `DynamicDataSourceContextHolder` before the method runs and clears it afterward. If no annotation is present, the framework falls back to the **primary** data source defined in the configuration. All existing code using `JdbcTemplate`, MyBatis-Plus, or JPA receives the routed connection transparently.

## Step-by-Step Configuration Guide

### Verify the Starter Dependency

The `dynamic-datasource-spring-boot-starter` is already declared in the parent POM as part of the core technology stack. You do not need to add additional dependencies. According to the repository documentation in [`README.md`](https://github.com/continew-org/continew-admin/blob/main/README.md) (line 248), version 4.3.1 is the current bundled release.

### Define Data Sources in YAML

Extend the existing configuration in [`continew-server/src/main/resources/config/application-dev.yml`](https://github.com/continew-org/continew-admin/blob/main/continew-server/src/main/resources/config/application-dev.yml) (or [`application-prod.yml`](https://github.com/continew-org/continew-admin/blob/main/application-prod.yml)) with a `dynamic` block under `spring.datasource`. The `primary` key designates the default data source, while the `datasource` map contains named entries for each connection pool.

```yaml
spring:
  datasource:
    # Existing primary configuration

    type: com.zaxxer.hikari.HikariDataSource
    url: jdbc:p6spy:mysql://${DB_HOST:127.0.0.1}:${DB_PORT:3306}/${DB_NAME:continew_admin}
    username: ${DB_USER:root}
    password: ${DB_PWD:123456}
    driver-class-name: com.p6spy.engine.spy.P6SpyDriver

    # Dynamic multi-source configuration

    dynamic:
      primary: master
      datasource:
        master:
          url: jdbc:p6spy:mysql://${DB_HOST:127.0.0.1}:${DB_PORT:3306}/${DB_NAME:continew_admin}
          username: ${DB_USER:root}
          password: ${DB_PWD:123456}
          driver-class-name: com.p6spy.engine.spy.P6SpyDriver
          hikari:
            maximum-pool-size: 20
        
        slave:
          url: jdbc:p6spy:mysql://${SLAVE_DB_HOST:127.0.0.1}:${SLAVE_DB_PORT:3306}/${SLAVE_DB_NAME:continew_admin_slave}
          username: ${SLAVE_DB_USER:root}
          password: ${SLAVE_DB_PWD:123456}
          driver-class-name: com.p6spy.engine.spy.P6SpyDriver
          hikari:
            maximum-pool-size: 10

```

Each named entry supports standard HikariCP properties under the `hikari` key, allowing independent pool sizing for different database workloads.

### Annotate Service Methods with @DS

Import `com.baomidou.dynamic.datasource.annotation.DS` and apply it to service methods or classes that must execute against a non-primary source. For example, in [`continew-system/src/main/java/top/continew/admin/system/service/impl/DeptServiceImpl.java`](https://github.com/continew-org/continew-admin/blob/main/continew-system/src/main/java/top/continew/admin/system/service/impl/DeptServiceImpl.java), you can route read-only operations to the slave database:

```java
package top.continew.admin.system.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import org.springframework.stereotype.Service;
import top.continew.admin.system.service.DeptService;

@Service
public class DeptServiceImpl implements DeptService {

    @Override
    @DS("slave")
    public List<DeptVO> listAll() {
        // Executes against the slave data source
        return deptMapper.selectList(null);
    }

    @Override
    public void create(DeptCreateReq req) {
        // No annotation: uses the primary (master) data source
        deptMapper.insert(req);
    }
}

```

When placed at the class level, `@DS` applies to all public methods in that bean. Method-level annotations override class-level declarations.

## Programmatic Data Source Switching

For scenarios requiring runtime decision logic, use `DynamicDataSourceContextHolder` to push and pop data source keys manually. Always wrap the operation in a try-finally block to ensure the context is cleared and connections are returned to the correct pool.

```java
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;

public void exportHistoricalData() {
    DynamicDataSourceContextHolder.push("slave");
    try {
        List<Record> rows = recordMapper.selectAll();
        // Processing logic here
    } finally {
        DynamicDataSourceContextHolder.poll(); // Restores previous data source
    }
}

```

This approach is useful when the target data source cannot be determined statically, such as in multi-tenant applications where the tenant identifier drives the routing decision.

## Summary

- **ContiNew-Admin** pre-installs `dynamic-datasource-spring-boot-starter` v4.3.1; no additional Maven dependencies are required.
- Configure multiple sources under `spring.datasource.dynamic.datasource` in [`application-dev.yml`](https://github.com/continew-org/continew-admin/blob/main/application-dev.yml) or [`application-prod.yml`](https://github.com/continew-org/continew-admin/blob/main/application-prod.yml), specifying a `primary` default.
- Use the `@DS("name")` annotation from `com.baomidou.dynamic.datasource.annotation.DS` on service methods to route queries to specific databases.
- Implement programmatic switching with `DynamicDataSourceContextHolder.push()` and `poll()` for dynamic runtime routing.
- Existing MyBatis-Plus mappers and JDBC templates work without modification because the routing happens at the `DataSource` proxy level.

## Frequently Asked Questions

### Is dynamic-datasource already included in ContiNew-Admin?

Yes. The starter is listed in the Core Technology Stack table in [`README.md`](https://github.com/continew-org/continew-admin/blob/main/README.md) and is inherited by all modules through the parent POM. You can begin configuring additional sources immediately without adding new dependencies to your [`pom.xml`](https://github.com/continew-org/continew-admin/blob/main/pom.xml).

### How do I switch data sources without using annotations?

Use `DynamicDataSourceContextHolder.push("datasourceName")` to set the current thread's data source key before executing database operations. Call `DynamicDataSourceContextHolder.poll()` in a finally block to restore the previous context. This is implemented in the `com.baomidou.dynamic.datasource.toolkit` package provided by the starter.

### Can I configure more than two data sources?

Absolutely. The `spring.datasource.dynamic.datasource` map accepts any number of named entries. Simply add additional keys (e.g., `tenant_a`, `tenant_b`, `reporting_db`) with their respective JDBC URLs and credentials. Each operates as an independent HikariCP pool managed by the `DynamicRoutingDataSource`.

### Does this integration work with MyBatis-Plus and JPA?

Yes. The routing logic sits at the `DataSource` level, below the ORM layer. Whether you use MyBatis-Plus mappers (as seen in [`DeptServiceImpl.java`](https://github.com/continew-org/continew-admin/blob/main/DeptServiceImpl.java)), Spring Data JPA repositories, or raw `JdbcTemplate`, all database connections are automatically routed according to the current context holder key or `@DS` annotation.