springboot集成dynamic-datasource 多数据源手动切换 动态添加删除

文章目录

    • 1. 引入依赖
    • 2. 配置数据源
    • 3. 注解切换数据源
    • 4. 手动切换数据源
    • 5. 动态管理数据源

Spring Boot集成Dynamic-datasource实现多数据源切换与动态管理,动态数据源可以与配置文件的数据源合并管理,的步骤如下:

1. 引入依赖

在pom.xml文件中加入以下依赖:


    com.baomidou
    dynamic-datasource-spring-boot-starter
    3.2.0

2. 配置数据源

在application.yml或application.properties中配置数据源,如:

spring:
  datasource:
    dynamic:
      primary: master #设置默认的数据源或者数据源组,默认值即为master
      strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
      datasource:
        master:
          url: jdbc:mysql://xx.xx.xx.xx:3306/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
        slave_1:
          url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver
        slave_2:
          url: jdbc:mysql://xx.xx.xx.xx:3308/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver
       #......省略
       #以上会配置一个默认库master,一个组slave下有两个子库slave_1,slave_2

其中,spring.datasource.dynamic.primary为默认数据源,后面的配置为各个数据源的配置。

3. 注解切换数据源

在需要使用的地方使用@DS注解,指定使用的数据源,如:

//@DS("slave_1")
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @DS("slave_1")
    @Override
    public List listUsersBySlave1() {
        return userMapper.listUsers();
    }
      
    @Override
    public List listUsersByMaster() {
        return userMapper.listUsers();
    }
}

@DS 可以注解在方法上和类上,同时存在方法注解优先于类上注解,如果没有写@DS注解,则默认使用master数据源。

4. 手动切换数据源

有时候切换数据源需要根据业务动态切换,就不能使用注解,需要手动切换数据:

DynamicDataSourceContextHolder.push("slave_1");
//执行业务方法
DynamicDataSourceContextHolder.poll();

手动切换数据源会与springboot事务冲突,例如

	@Transactional(rollbackFor = Exception.class)
    public void add(DataSourceAddVo vo) {
        DynamicDataSourceContextHolder.push("slave_1");
		//执行业务方法
		selectList();
		handleAdd();
		DynamicDataSourceContextHolder.poll();
       

    }

上述代码中,执行handleAdd方法不能执行切换数据源,可以改造成:

	//@Transactional(rollbackFor = Exception.class)
    public void add(DataSourceAddVo vo) {
        DynamicDataSourceContextHolder.push("slave_1");
		//执行业务方法
		selectList();
		 
		DynamicDataSourceContextHolder.poll();
       
    }
 @Transactional(rollbackFor = Exception.class)
    public void handleAdd( ){
        this.save(bean);
        
    }
	

5. 动态管理数据源

以上切换的数据源都是在配置文件上定义好了,如果需要由用户从界面添加数据源则需要动态维护数据源。

数据源由:数据源唯一编码、用户名、密码、url和驱动4个元素组成,见下图:
springboot集成dynamic-datasource 多数据源手动切换 动态添加删除_第1张图片

编写数据源管理的工具类:

package org.bitnei.modules.ds;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.DataSourceCreator;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.util.Set;

/**
 * 功能描述:数据源管理工具类
 *
 * @author: zenghaiwen
 * @date: 2023年07月20日 10:05
 */
@Component
@Slf4j
public class DynamicDataSourcesUtil {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private DataSourceCreator dataSourceCreator;

    /**
     * 添加数据源
     */
    public Set<String> addDataSource(DataSourceDTO dto) {
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        if(!this.existsDataSource(dto.getPoolName())){
            new JdbcTemplate(dataSource);
            DataSourceProperty dataSourceProperty = new DataSourceProperty();
            BeanUtils.copyProperties(dto, dataSourceProperty);

            DataSource dataSource = dataSourceCreator.createDataSource(dataSourceProperty);
            ds.addDataSource(dto.getPoolName(), dataSource);
        }
        return ds.getCurrentDataSources().keySet();
    }

    public DataSource getDataSource(){
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        return  ds.getDataSource("master");
    }

    /**
     * 删除数据源
     * @param name
     */
    public void removeDataSource(String name){
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        ds.removeDataSource(name);
    }

    /**
     * 获取当前所有数据源
     * @return
     */
    public Set<String> allDataSource() {
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        return ds.getCurrentDataSources().keySet();
    }

    /**
     * 是否存在数据源
     * @param name
     * @return
     */
    public boolean existsDataSource(String name){

        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        return ds.getCurrentDataSources().containsKey(name);
    }


}

以下是调用工具类实现动态管理数据源的代码:

	public void add(DataSourceAddVo vo) {
         
        DataSource bean = BeanUtil.copyProperties(vo,DataSource.class);         

        //测试链接是否成功
        boolean isConnect = checkDataSource(bean);
        AssertUtils.assertIsTrue(isConnect,"无法链接数据库");

        //添加数据源
        Set<String> dbSet =  this.addDataSource(bean);
        //切换刚刚添加的数据源
        DynamicDataSourceContextHolder.push(bean.getCode());
        //执行业务方法
 
        DynamicDataSourceContextHolder.poll();

        handleAdd(bean,tableList,allVehicleList);

    }
	
	private Set<String> addDataSource(DataSource ds){
        DataSourceDTO dto = buildDataSourceDTO(ds);

        return dynamicDataSourcesUtil.addDataSource(dto);

    }
	private DataSourceDTO buildDataSourceDTO(DataSource ds){
        DataSourceDTO dto = new DataSourceDTO()
                .setPoolName(ds.getCode())
                .setUsername(ds.getUsername())
                .setPassword(ds.getPassword())
                .setUrl(ds.getDbUrl())
                .setDriverClassName(Constants.MYSQL_DRIVER);

        return dto;
    }

注:添加数据源必须检查数据源的连通性,否则会一直打印数据源错误。

你可能感兴趣的:(spirngBoot,java,多数据源动态管理,spring,boot,java,后端)