mybatis-plus 从数据库加载多数据源,以及往spring动态添加数据源

mybatis-plus 从数据库加载多数据源,以及往spring动态添加数据源

import com.baomidou.dynamic.datasource.provider.AbstractJdbcDataSourceProvider;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.util.security.JdbcSecurityUtil;
import org.jeecg.modules.system.util.SecurityUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.sql.*;
import java.util.Map;

/**
 * 从数据库加载数据源
 * @author Yun.GUO
 * @description
 * @date 2023-08-31 10:41
 **/


@Configuration
@Slf4j
public class DatasourceConfig {

    /**
     * 数据源自定义加载
     *
     * @param properties 数据源配置
     * @return  DynamicDataSourceProvider
     */
    @Bean
    public DynamicDataSourceProvider dynamicDataSourceProvider(DynamicDataSourceProperties properties) {
        Map<String, DataSourceProperty> datasourceMap = properties.getDatasource();
        DataSourceProperty masterDataSourceProperty = datasourceMap.get(properties.getPrimary());
        return new AbstractJdbcDataSourceProvider(masterDataSourceProperty.getDriverClassName(), masterDataSourceProperty.getUrl(), masterDataSourceProperty.getUsername(), masterDataSourceProperty.getPassword()) {
            @Override
            protected Map<String, DataSourceProperty> executeStmt(Statement statement) throws SQLException {
                // 该地方只能使用statement操作数据库(数据源未加载,注入service操作数据库会出现循环依赖问题)
                // 从数据库表记录读取数据库连接
                ResultSet resultSet = statement.executeQuery("select code, db_username username,db_password password,db_url url, db_driver driver from sys_data_source ");
                while (resultSet.next()){
                    String code = resultSet.getString("code");
                    String username = resultSet.getString("username");
                    String password = resultSet.getString("password");
                    try {
                        password = SecurityUtil.jiemi(password);
                    } catch (Exception e) {
                        log.warn("SecurityUtil.jiemi error, code:{}", code, e);
                        continue;
                    }
                    String url = resultSet.getString("url");
                    String driver = resultSet.getString("driver");
                    addDatasource(code, username, password, url, driver, datasourceMap);
                }

                return datasourceMap;
            }
        };
    }

    private static void addDatasource(String code, String username, String password, String url, String driver, Map<String, DataSourceProperty> datasourceMap) {
        if (!testConnection(code, username, password, url, driver)) return;
        DataSourceProperty property = new DataSourceProperty();
        property.setUsername(username);
        property.setUrl(url);
        property.setDriverClassName(driver);
        property.setPassword(password);
        datasourceMap.put(code, property);
    }

    private static boolean testConnection(String code, String username, String password, String url, String driver) {
        log.info("test connection start. code:{}", code);
        Connection var2 = null;
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            log.warn("class not found. code: {}", code, e);
            return false;
        }
        try {
            JdbcSecurityUtil.validate(url);
            DriverManager.setLoginTimeout(3);
            var2 = DriverManager.getConnection(url, username, password);
            if (var2 == null) {
                log.warn("connection fail. code: {}", code);
                return false;
            }
            log.info("test connection success. code:{}", code);
        } catch (Exception e) {
            log.warn("connection error. code: {}", code, e);
            return false;
        } finally {
            try {
                if (var2 != null && !var2.isClosed()) {
                    var2.close();
                }
            } catch (SQLException e) {
                log.warn(e.toString());
            }
        }
        return true;
    }
}

/**
     * 动态添加数据源 【注册mybatis动态数据源】
     *
     * @param sysDataSource 添加数据源数据对象
     * @param dbPassword    未加密的密码
     */
    private void addDynamicDataSource(SysDataSource sysDataSource, String dbPassword) {
        DataSourceProperty dataSourceProperty = new DataSourceProperty();
        dataSourceProperty.setUrl(sysDataSource.getDbUrl());
        dataSourceProperty.setPassword(dbPassword);
        dataSourceProperty.setDriverClassName(sysDataSource.getDbDriver());
        dataSourceProperty.setUsername(sysDataSource.getDbUsername());
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        DataSource dataSource = dataSourceCreator.createDataSource(dataSourceProperty);
        try {
            ds.addDataSource(sysDataSource.getCode(), dataSource);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除数据源
     * @param code
     */
    private void removeDynamicDataSource(String code) {
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        ds.removeDataSource(code);
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Springboot+MyBatis-Plus实现多租户动态数据源模式是一种在Spring Boot框架下使用MyBatis-Plus插件实现多租户数据隔离的方法。它可以根据不同的租户动态切换数据源,实现不同租户之间的数据隔离。 实现多租户动态数据源模式的关键是配置多个数据源,并在运行时根据租户信息动态选择使用哪个数据源。以下是一个简单的示例代码: 1. 首先,需要在pom.xml文件中添加Druid数据源的依赖: ```xml <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.21</version> </dependency> ``` 2. 在application.properties或application.yml文件中配置多个数据源的连接信息,例如: ```yaml spring.datasource.master.url=jdbc:mysql://localhost:3306/master_db spring.datasource.master.username=root spring.datasource.master.password=123456 spring.datasource.tenant1.url=jdbc:mysql://localhost:3306/tenant1_db spring.datasource.tenant1.username=root spring.datasource.tenant1.password=123456 spring.datasource.tenant2.url=jdbc:mysql://localhost:3306/tenant2_db spring.datasource.tenant2.username=root spring.datasource.tenant2.password=123456 ``` 3. 创建一个多租户数据源配置类,用于动态选择数据源。可以使用ThreadLocal来保存当前租户的标识,然后根据标识选择对应的数据源。以下是一个简单的示例: ```java @Configuration public class MultiTenantDataSourceConfig { @Autowired private DataSourceProperties dataSourceProperties; @Bean @ConfigurationProperties(prefix = "spring.datasource.master") public DataSource masterDataSource() { return DataSourceBuilder.create().build(); } @Bean @ConfigurationProperties(prefix = "spring.datasource.tenant1") public DataSource tenant1DataSource() { return DataSourceBuilder.create().build(); } @Bean @ConfigurationProperties(prefix = "spring.datasource.tenant2") public DataSource tenant2DataSource() { return DataSourceBuilder.create().build(); } @Bean @Primary public DataSource dynamicDataSource() { DynamicDataSource dynamicDataSource = new DynamicDataSource(); Map<Object, Object> dataSourceMap = new HashMap<>(); dataSourceMap.put("master", masterDataSource()); dataSourceMap.put("tenant1", tenant1DataSource()); dataSourceMap.put("tenant2", tenant2DataSource()); dynamicDataSource.setTargetDataSources(dataSourceMap); dynamicDataSource.setDefaultTargetDataSource(masterDataSource()); return dynamicDataSource; } @Bean public SqlSessionFactory sqlSessionFactory(DataSource dynamicDataSource) throws Exception { SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(dynamicDataSource); return sessionFactory.getObject(); } @Bean public PlatformTransactionManager transactionManager(DataSource dynamicDataSource) { return new DataSourceTransactionManager(dynamicDataSource); } } ``` 4. 创建一个多租户数据源切换器,用于在每次数据库操作前切换数据源。以下是一个简单的示例: ```java public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return TenantContext.getTenantId(); } } ``` 5. 创建一个租户上下文类,用于保存当前租户的标识。以下是一个简单的示例: ```java public class TenantContext { private static final ThreadLocal<String> CONTEXT = new ThreadLocal<>(); public static void setTenantId(String tenantId) { CONTEXT.set(tenantId); } public static String getTenantId() { return CONTEXT.get(); } public static void clear() { CONTEXT.remove(); } } ``` 6. 在需要切换数据源的地方,调用TenantContext.setTenantId()方法设置当前租户的标识。例如: ```java @RestController public class UserController { @Autowired private UserService userService; @GetMapping("/users") public List<User> getUsers() { TenantContext.setTenantId("tenant1"); List<User> users = userService.getUsers(); TenantContext.clear(); return users; } } ``` 通过以上步骤,就可以实现Springboot+MyBatis-Plus的多租户动态数据源模式了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值