国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【源碼解析】多數(shù)據(jù)源 dynamic-datasource快速入門及源碼解析

這篇具有很好參考價值的文章主要介紹了【源碼解析】多數(shù)據(jù)源 dynamic-datasource快速入門及源碼解析。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

快速入門

依賴引入

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>

配置文件

spring.datasource.druid.stat-view-servlet.enabled = true
spring.datasource.druid.stat-view-servlet.login-username = root
spring.datasource.druid.stat-view-servlet.login-password = root
spring.datasource.dynamic.druid.filters = stat,wall
spring.datasource.druid.aop-patterns = com.charles.mapper.*
spring.datasource.druid.web-stat-filter.enabled = true
spring.datasource.druid.filter.stat.enabled = true
spring.datasource.druid.filter.stat.log-slow-sql = true
spring.datasource.druid.filter.stat.slow-sql-millis = 1000

spring.datasource.dynamic.primary = db0
spring.datasource.dynamic.datasource.db1.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.dynamic.datasource.db1.url = jdbc:mysql://127.0.0.1:3306/eb-crm?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true
spring.datasource.dynamic.datasource.db1.username = app
spring.datasource.dynamic.datasource.db1.password = Ys@123456
spring.datasource.dynamic.datasource.db1.type = com.alibaba.druid.pool.DruidDataSource
spring.datasource.dynamic.datasource.db0.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.dynamic.datasource.db0.url = jdbc:mysql://127.0.0.1:3306/newcrm?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true
spring.datasource.dynamic.datasource.db0.username = app
spring.datasource.dynamic.datasource.db0.password = Ys@123456
spring.datasource.dynamic.datasource.db0.type = com.alibaba.druid.pool.DruidDataSource

使用注解攔截

@DS("db1")
public interface TbpExcelLogMapper extends BaseMapper<TbpExcelLog> {
}

源碼解析

啟動的時候,會加載在dynamic-datasource-spring-boot-starter的jar包中的spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration

數(shù)據(jù)源加載

DynamicDataSourceAutoConfiguration會注入DynamicRoutingDataSource

    @Bean
    @ConditionalOnMissingBean
    public DataSource dataSource() {
        DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
        dataSource.setPrimary(properties.getPrimary());
        dataSource.setStrict(properties.getStrict());
        dataSource.setStrategy(properties.getStrategy());
        dataSource.setP6spy(properties.getP6spy());
        dataSource.setSeata(properties.getSeata());
        return dataSource;
    }

DynamicRoutingDataSource#afterPropertiesSet,系統(tǒng)啟動的時候會加載所有的數(shù)據(jù)源

    @Override
    public void afterPropertiesSet() throws Exception {
        // 檢查開啟了配置但沒有相關(guān)依賴
        checkEnv();
        // 添加并分組數(shù)據(jù)源
        Map<String, DataSource> dataSources = new HashMap<>(16);
        for (DynamicDataSourceProvider provider : providers) {
            dataSources.putAll(provider.loadDataSources());
        }
        for (Map.Entry<String, DataSource> dsItem : dataSources.entrySet()) {
            addDataSource(dsItem.getKey(), dsItem.getValue());
        }
        // 檢測默認(rèn)數(shù)據(jù)源是否設(shè)置
        if (groupDataSources.containsKey(primary)) {
            log.info("dynamic-datasource initial loaded [{}] datasource,primary group datasource named [{}]", dataSources.size(), primary);
        } else if (dataSourceMap.containsKey(primary)) {
            log.info("dynamic-datasource initial loaded [{}] datasource,primary datasource named [{}]", dataSources.size(), primary);
        } else {
            log.warn("dynamic-datasource initial loaded [{}] datasource,Please add your primary datasource or check your configuration", dataSources.size());
        }
    }

DynamicDataSourceAutoConfiguration會注入DynamicDataSourceProvider

    @Bean
    public DynamicDataSourceProvider ymlDynamicDataSourceProvider() {
        return new YmlDynamicDataSourceProvider(properties.getDatasource());
    }

AbstractDataSourceProvider#createDataSourceMap,根據(jù)配置文件中的信息創(chuàng)建數(shù)據(jù)源。

    protected Map<String, DataSource> createDataSourceMap(
            Map<String, DataSourceProperty> dataSourcePropertiesMap) {
        Map<String, DataSource> dataSourceMap = new HashMap<>(dataSourcePropertiesMap.size() * 2);
        for (Map.Entry<String, DataSourceProperty> item : dataSourcePropertiesMap.entrySet()) {
            String dsName = item.getKey();
            DataSourceProperty dataSourceProperty = item.getValue();
            String poolName = dataSourceProperty.getPoolName();
            if (poolName == null || "".equals(poolName)) {
                poolName = dsName;
            }
            dataSourceProperty.setPoolName(poolName);
            dataSourceMap.put(dsName, defaultDataSourceCreator.createDataSource(dataSourceProperty));
        }
        return dataSourceMap;
    }

AbstractDataSourceCreator#createDataSource,模板方法。該方法會調(diào)用dataSourceInitEvent.beforeCreate(dataSourceProperty);。而doCreateDataSource交由每個子類來創(chuàng)建。

    @Override
    public DataSource createDataSource(DataSourceProperty dataSourceProperty) {
        String publicKey = dataSourceProperty.getPublicKey();
        if (StringUtils.isEmpty(publicKey)) {
            publicKey = properties.getPublicKey();
            dataSourceProperty.setPublicKey(publicKey);
        }
        Boolean lazy = dataSourceProperty.getLazy();
        if (lazy == null) {
            lazy = properties.getLazy();
            dataSourceProperty.setLazy(lazy);
        }
        dataSourceInitEvent.beforeCreate(dataSourceProperty);
        DataSource dataSource = doCreateDataSource(dataSourceProperty);
        dataSourceInitEvent.afterCreate(dataSource);
        this.runScrip(dataSource, dataSourceProperty);
        return wrapDataSource(dataSource, dataSourceProperty);
    }

DruidDataSourceCreator#doCreateDataSource,創(chuàng)建druid數(shù)據(jù)源。根據(jù)全局配置gConfig和定制化配置結(jié)合來生成DruidDataSourcespring.datasource.dynamic.datasource.xxx.type=com.alibaba.druid.pool.DruidDataSource可以進(jìn)行定制化配置,也可以通過spring.datasource.dynamic.druid全局配置druid的屬性

    private DruidConfig gConfig;

    @Override
    public DataSource doCreateDataSource(DataSourceProperty dataSourceProperty) {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUsername(dataSourceProperty.getUsername());
        dataSource.setPassword(dataSourceProperty.getPassword());
        dataSource.setUrl(dataSourceProperty.getUrl());
        dataSource.setName(dataSourceProperty.getPoolName());
        String driverClassName = dataSourceProperty.getDriverClassName();
        if (!StringUtils.isEmpty(driverClassName)) {
            dataSource.setDriverClassName(driverClassName);
        }
        DruidConfig config = dataSourceProperty.getDruid();
        Properties properties = config.toProperties(gConfig);

        List<Filter> proxyFilters = this.initFilters(dataSourceProperty, properties.getProperty("druid.filters"));
        dataSource.setProxyFilters(proxyFilters);

        dataSource.configFromPropety(properties);
        //連接參數(shù)單獨(dú)設(shè)置
        dataSource.setConnectProperties(config.getConnectionProperties());
        //設(shè)置druid內(nèi)置properties不支持的的參數(shù)
        this.setParam(dataSource, config);

        if (Boolean.FALSE.equals(dataSourceProperty.getLazy())) {
            try {
                dataSource.init();
            } catch (SQLException e) {
                throw new ErrorCreateDataSourceException("druid create error", e);
            }
        }
        return dataSource;
    }

切面修改數(shù)據(jù)源的key

DynamicDataSourceAutoConfiguration會注入DynamicDataSourceAnnotationAdvisor

    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    @Bean
    @ConditionalOnProperty(prefix = DynamicDataSourceProperties.PREFIX + ".aop", name = "enabled", havingValue = "true", matchIfMissing = true)
    public Advisor dynamicDatasourceAnnotationAdvisor(DsProcessor dsProcessor) {
        DynamicDatasourceAopProperties aopProperties = properties.getAop();
        DynamicDataSourceAnnotationInterceptor interceptor = new DynamicDataSourceAnnotationInterceptor(aopProperties.getAllowedPublicOnly(), dsProcessor);
        DynamicDataSourceAnnotationAdvisor advisor = new DynamicDataSourceAnnotationAdvisor(interceptor, DS.class);
        advisor.setOrder(aopProperties.getOrder());
        return advisor;
    }

DynamicDataSourceAnnotationAdvisor#buildPointcut,構(gòu)造切面,對方法和類都攔截。

    private Pointcut buildPointcut() {
        Pointcut cpc = new AnnotationMatchingPointcut(annotation, true);
        Pointcut mpc = new AnnotationMethodPoint(annotation);
        return new ComposablePointcut(cpc).union(mpc);
    }

如果使用@Aspect來切面的話,對注解進(jìn)行切片,要注意@within@annotation的區(qū)別。

 1.  @within 對象級別
 2.  @annotation 方法級別

DynamicDataSourceAnnotationInterceptor#invoke,獲取方法上或者類上的注解中的key

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        String dsKey = determineDatasourceKey(invocation);
        DynamicDataSourceContextHolder.push(dsKey);
        try {
            return invocation.proceed();
        } finally {
            DynamicDataSourceContextHolder.poll();
        }
    }

DynamicDataSourceAnnotationInterceptor#determineDatasourceKey,如果key以#開頭,則返回dsProcessor.determineDatasource(invocation, key),否則直接返回key。

    private String determineDatasourceKey(MethodInvocation invocation) {
        String key = dataSourceClassResolver.findKey(invocation.getMethod(), invocation.getThis());
        return key.startsWith(DYNAMIC_PREFIX) ? dsProcessor.determineDatasource(invocation, key) : key;
    }

DsProcessor

DynamicDataSourceAutoConfiguration會注入DsProcessor,使用過濾器鏈的模式進(jìn)行處理。

    @Bean
    @ConditionalOnMissingBean
    public DsProcessor dsProcessor(BeanFactory beanFactory) {
        DsHeaderProcessor headerProcessor = new DsHeaderProcessor();
        DsSessionProcessor sessionProcessor = new DsSessionProcessor();
        DsSpelExpressionProcessor spelExpressionProcessor = new DsSpelExpressionProcessor();
        spelExpressionProcessor.setBeanResolver(new BeanFactoryResolver(beanFactory));
        headerProcessor.setNextProcessor(sessionProcessor);
        sessionProcessor.setNextProcessor(spelExpressionProcessor);
        return headerProcessor;
    }

DsHeaderProcessor#doDetermineDatasource,如果方法上的注解類似于@DS(#header=tenat_id),那么切換路由的key是由header中tenat_id的值決定的。

    @Override
    public String doDetermineDatasource(MethodInvocation invocation, String key) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        return request.getHeader(key.substring(8));
    }

spelExpressionProcessor是支持表達(dá)式的。

在注解中配置@DS("#header=tenantName"),則從header里面去尋找key;寫了@DS("#session=tenantName"),就從session里面獲取以tenantName為鍵的值。而@DS("#tenantName")@DS("#user.tenantName")根據(jù)參數(shù)來獲取。

獲取數(shù)據(jù)源

獲取連接,AbstractRoutingDataSource#getConnection()。首先獲取數(shù)據(jù)源,從數(shù)據(jù)源中獲取Connection

    @Override
    public Connection getConnection() throws SQLException {
        String xid = TransactionContext.getXID();
        if (StringUtils.isEmpty(xid)) {
            return determineDataSource().getConnection();
        } else {
            String ds = DynamicDataSourceContextHolder.peek();
            ds = StringUtils.isEmpty(ds) ? "default" : ds;
            ConnectionProxy connection = ConnectionFactory.getConnection(ds);
            return connection == null ? getConnectionProxy(ds, determineDataSource().getConnection()) : connection;
        }
    }

DynamicRoutingDataSource#determineDataSource,獲取線程變量的數(shù)據(jù),根據(jù)線程變量獲取數(shù)據(jù)源。

    @Override
    public DataSource determineDataSource() {
        String dsKey = DynamicDataSourceContextHolder.peek();
        return getDataSource(dsKey);
    }

DynamicRoutingDataSource#getDataSource,該key為空,獲取默認(rèn)數(shù)據(jù)源,優(yōu)先從groupDataSources里面獲取數(shù)據(jù)源,然后再從dataSourceMap里面獲取。

    public DataSource getDataSource(String ds) {
        if (StringUtils.isEmpty(ds)) {
            return determinePrimaryDataSource();
        } else if (!groupDataSources.isEmpty() && groupDataSources.containsKey(ds)) {
            log.debug("dynamic-datasource switch to the datasource named [{}]", ds);
            return groupDataSources.get(ds).determineDataSource();
        } else if (dataSourceMap.containsKey(ds)) {
            log.debug("dynamic-datasource switch to the datasource named [{}]", ds);
            return dataSourceMap.get(ds);
        }
        if (strict) {
            throw new CannotFindDataSourceException("dynamic-datasource could not find a datasource named" + ds);
        }
        return determinePrimaryDataSource();
    }

DynamicDataSourceStrategy,從群組里面獲取數(shù)據(jù)源需要配置獲取策略,從集合中決定是哪一個,有隨機(jī)和輪詢。

public class RandomDynamicDataSourceStrategy implements DynamicDataSourceStrategy {

    @Override
    public String determineKey(List<String> dsNames) {
        return dsNames.get(ThreadLocalRandom.current().nextInt(dsNames.size()));
    }
}

比對一下,spring-jdbc中的動態(tài)數(shù)據(jù)源切換。

AbstractRoutingDataSource#afterPropertiesSet,重寫了InitializingBean#afterPropertiesSet的方法。

    public void afterPropertiesSet() {
        if (this.targetDataSources == null) {
            throw new IllegalArgumentException("Property 'targetDataSources' is required");
        } else {
            this.resolvedDataSources = new HashMap(this.targetDataSources.size());
            this.targetDataSources.forEach((key, value) -> {
                Object lookupKey = this.resolveSpecifiedLookupKey(key);
                DataSource dataSource = this.resolveSpecifiedDataSource(value);
                this.resolvedDataSources.put(lookupKey, dataSource);
            });
            if (this.defaultTargetDataSource != null) {
                this.resolvedDefaultDataSource = this.resolveSpecifiedDataSource(this.defaultTargetDataSource);
            }

        }
    }

AbstractRoutingDataSource#getConnection()。獲取lookupKey的方式由子類決定。

    public Connection getConnection() throws SQLException {
        return this.determineTargetDataSource().getConnection();
    }

    protected DataSource determineTargetDataSource() {
        Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
        Object lookupKey = this.determineCurrentLookupKey();
        DataSource dataSource = (DataSource)this.resolvedDataSources.get(lookupKey);
        if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
            dataSource = this.resolvedDefaultDataSource;
        }

        if (dataSource == null) {
            throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
        } else {
            return dataSource;
        }
    }

    @Nullable
    protected abstract Object determineCurrentLookupKey();

多數(shù)據(jù)源事務(wù)

DynamicDataSourceAutoConfiguration會注入dynamicTransactionAdvisor,主要是攔截處理有DSTransactional注解的方法。

    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    @Bean
    @ConditionalOnProperty(prefix = DynamicDataSourceProperties.PREFIX, name = "seata", havingValue = "false", matchIfMissing = true)
    public Advisor dynamicTransactionAdvisor() {
        DynamicLocalTransactionInterceptor interceptor = new DynamicLocalTransactionInterceptor();
        return new DynamicDataSourceAnnotationAdvisor(interceptor, DSTransactional.class);
    }

DynamicLocalTransactionInterceptor,開啟事務(wù)。

public class DynamicLocalTransactionInterceptor implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        if (!StringUtils.isEmpty(TransactionContext.getXID())) {
            return methodInvocation.proceed();
        }
        boolean state = true;
        Object o;
        LocalTxUtil.startTransaction();
        try {
            o = methodInvocation.proceed();
        } catch (Exception e) {
            state = false;
            throw e;
        } finally {
            if (state) {
                LocalTxUtil.commit();
            } else {
                LocalTxUtil.rollback();
            }
        }
        return o;
    }
}

LocalTxUtil#startTransaction

    public static void startTransaction() {
        if (!StringUtils.isEmpty(TransactionContext.getXID())) {
            log.debug("dynamic-datasource exist local tx [{}]", TransactionContext.getXID());
        } else {
            String xid = UUID.randomUUID().toString();
            TransactionContext.bind(xid);
            log.debug("dynamic-datasource start local tx [{}]", xid);
        }
    }

AbstractRoutingDataSource#getConnection(),判斷是否存在事務(wù)id,如果存在,則獲取連接,并封裝成ConnectionProxy。

    @Override
    public Connection getConnection() throws SQLException {
        String xid = TransactionContext.getXID();
        if (StringUtils.isEmpty(xid)) {
            return determineDataSource().getConnection();
        } else {
            String ds = DynamicDataSourceContextHolder.peek();
            ds = StringUtils.isEmpty(ds) ? "default" : ds;
            ConnectionProxy connection = ConnectionFactory.getConnection(ds);
            return connection == null ? getConnectionProxy(ds, determineDataSource().getConnection()) : connection;
        }
    }

    private Connection getConnectionProxy(String ds, Connection connection) {
        ConnectionProxy connectionProxy = new ConnectionProxy(connection, ds);
        ConnectionFactory.putConnection(ds, connectionProxy);
        return connectionProxy;
    }

ConnectionFactory#putConnection,存儲到線程變量中的concurrentHashMap。

    public static void putConnection(String ds, ConnectionProxy connection) {
        Map<String, ConnectionProxy> concurrentHashMap = CONNECTION_HOLDER.get();
        if (!concurrentHashMap.containsKey(ds)) {
            try {
                connection.setAutoCommit(false);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            concurrentHashMap.put(ds, connection);
        }
    }

提交事務(wù),LocalTxUtil#commit

    public static void commit() {
        ConnectionFactory.notify(true);
        log.debug("dynamic-datasource commit local tx [{}]", TransactionContext.getXID());
        TransactionContext.remove();
    }

ConnectionFactory#notify,對于線程變量中的連接全部處理(回滾或者提交),并清空線程變量。

    public static void notify(Boolean state) {
        try {
            Map<String, ConnectionProxy> concurrentHashMap = CONNECTION_HOLDER.get();
            for (ConnectionProxy connectionProxy : concurrentHashMap.values()) {
                connectionProxy.notify(state);
            }
        } finally {
            CONNECTION_HOLDER.remove();
        }
    }

配置文件加密

DynamicDataSourceAutoConfiguration會注入EncDataSourceInitEvent

    @Bean
    @ConditionalOnMissingBean
    public DataSourceInitEvent dataSourceInitEvent() {
        return new EncDataSourceInitEvent();
    }

EncDataSourceInitEvent#beforeCreate,對加密的字符串進(jìn)行解密

    @Override
    public void beforeCreate(DataSourceProperty dataSourceProperty) {
        String publicKey = dataSourceProperty.getPublicKey();
        if (StringUtils.hasText(publicKey)) {
            dataSourceProperty.setUrl(decrypt(publicKey, dataSourceProperty.getUrl()));
            dataSourceProperty.setUsername(decrypt(publicKey, dataSourceProperty.getUsername()));
            dataSourceProperty.setPassword(decrypt(publicKey, dataSourceProperty.getPassword()));
        }
    }

EncDataSourceInitEvent#decrypt,匹配正則表達(dá)式則進(jìn)行解密。 Pattern ENC_PATTERN = Pattern.compile("^ENC\\((.*)\\)$");

    private String decrypt(String publicKey, String cipherText) {
        if (StringUtils.hasText(cipherText)) {
            Matcher matcher = ENC_PATTERN.matcher(cipherText);
            if (matcher.find()) {
                try {
                    return CryptoUtils.decrypt(publicKey, matcher.group(1));
                } catch (Exception e) {
                    log.error("DynamicDataSourceProperties.decrypt error ", e);
                }
            }
        }
        return cipherText;
    }

腳本執(zhí)行器

AbstractDataSourceCreator#runScrip,用對應(yīng)的數(shù)據(jù)源執(zhí)行腳本

    private void runScrip(DataSource dataSource, DataSourceProperty dataSourceProperty) {
        DatasourceInitProperties initProperty = dataSourceProperty.getInit();
        String schema = initProperty.getSchema();
        String data = initProperty.getData();
        if (StringUtils.hasText(schema) || StringUtils.hasText(data)) {
            ScriptRunner scriptRunner = new ScriptRunner(initProperty.isContinueOnError(), initProperty.getSeparator());
            if (StringUtils.hasText(schema)) {
                scriptRunner.runScript(dataSource, schema);
            }
            if (StringUtils.hasText(data)) {
                scriptRunner.runScript(dataSource, data);
            }
        }
    }

主從插件

MasterSlaveAutoRoutingPlugin。當(dāng)進(jìn)行查詢的時候,切換數(shù)據(jù)源SLAVE;當(dāng)進(jìn)行更新的時候,切換數(shù)據(jù)源,MASTER。

@Intercepts({
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
@Slf4j
public class MasterSlaveAutoRoutingPlugin implements Interceptor {

    @Autowired
    protected DataSource dynamicDataSource;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement) args[0];
        String pushedDataSource = null;
        try {
            String dataSource = SqlCommandType.SELECT == ms.getSqlCommandType() ? DdConstants.SLAVE : DdConstants.MASTER;
            pushedDataSource = DynamicDataSourceContextHolder.push(dataSource);
            return invocation.proceed();
        } finally {
            if (pushedDataSource != null) {
                DynamicDataSourceContextHolder.poll();
            }
        }
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
    }
}

【源碼解析】多數(shù)據(jù)源 dynamic-datasource快速入門及源碼解析文章來源地址http://www.zghlxwxcb.cn/news/detail-420270.html

到了這里,關(guān)于【源碼解析】多數(shù)據(jù)源 dynamic-datasource快速入門及源碼解析的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • SpringBoot+MybatisPlus+dynamic-datasources實(shí)現(xiàn)連接Postgresql和mysql多數(shù)據(jù)源

    SpringBoot+MybatisPlus+dynamic-datasources實(shí)現(xiàn)連接Postgresql和mysql多數(shù)據(jù)源

    dynamic-datasource-spring-boot-starter實(shí)現(xiàn)動態(tài)數(shù)據(jù)源Mysql和Sqlserver: dynamic-datasource-spring-boot-starter實(shí)現(xiàn)動態(tài)數(shù)據(jù)源Mysql和Sqlserver_dynamic-datasource-spring-boot-starter mysql sqlse-CSDN博客 SpringBoot中整合MybatisPlus快速實(shí)現(xiàn)Mysql增刪改查和條件構(gòu)造器: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/13

    2024年01月21日
    瀏覽(31)
  • Springboot+mybatis-plus+dynamic-datasource+Druid 多數(shù)據(jù)源 分布式事務(wù)

    Springboot+mybatis-plus+dynamic-datasource+Druid 多數(shù)據(jù)源 分布式事務(wù)

    背景 處理多數(shù)據(jù)源事務(wù)一直是一個復(fù)雜而棘手的問題,通常我們有兩種主流的解決方法。 第一種是通過Atomikos手動創(chuàng)建多數(shù)據(jù)源事務(wù),這種方法更適合數(shù)據(jù)源數(shù)量較少,參數(shù)配置不復(fù)雜,對性能要求不高的項(xiàng)目。然而,這種方法的最大困難在于需要手動配置大量設(shè)置,這可能

    2024年02月11日
    瀏覽(26)
  • MyBatis Plus 插件 動態(tài)數(shù)據(jù)源實(shí)現(xiàn)原理與源碼講解 (dynamic-datasource-spring-boot-starter-master)

    MyBatis Plus 插件 動態(tài)數(shù)據(jù)源實(shí)現(xiàn)原理與源碼講解 (dynamic-datasource-spring-boot-starter-master)

    目錄 1. 介紹 2. 基本原理 3. 源碼介紹 3.1 使用 AOP 攔截,方法執(zhí)行前獲取到當(dāng)前方法要用的數(shù)據(jù)源 3.2 實(shí)現(xiàn)自定義?DataSource 接口,實(shí)現(xiàn) DataSource 接口的 getConnect 方法做動態(tài)處理 多數(shù)據(jù)源即一個項(xiàng)目中同時存在多個不同的數(shù)據(jù)庫連接池。 比如 127.0.0.1:3306/test? ?127.0.0.1:3307/test?

    2024年02月07日
    瀏覽(28)
  • Dynamic DataSource 多數(shù)據(jù)源配置【 Springboot + DataSource + MyBatis Plus + Druid】

    Dynamic DataSource 多數(shù)據(jù)源配置【 Springboot + DataSource + MyBatis Plus + Druid】

    MybatisPlus多數(shù)據(jù)源配置主要解決的是多數(shù)據(jù)庫連接和切換的問題。在一些大型應(yīng)用中,由于數(shù)據(jù)量的增長或者業(yè)務(wù)模塊的增多,可能需要訪問多個數(shù)據(jù)庫。這時,就需要配置多個數(shù)據(jù)源。 2.1.1、引用依賴 2.1.2、application.yml 配置 2.1.3、通用配置類 2.1.4、使用方式 這里便不過多的

    2024年02月03日
    瀏覽(32)
  • 使用mybatis和dynamic-datasource-spring-boot-starter動態(tài)切換數(shù)據(jù)源操作數(shù)據(jù)庫

    記錄 :415 場景 :使用mybatis和dynamic-datasource-spring-boot-starter動態(tài)切換數(shù)據(jù)源操作數(shù)據(jù)庫。 版本 :JDK 1.8,Spring?Boot 2.6.3,dynamic-datasource-spring-boot-starter-3.3.2,mybatis-3.5.9。 源碼 :https://github.com/baomidou/dynamic-datasource-spring-boot-starter dynamic-datasource-spring-boot-starter :一個基于springboot的快

    2023年04月19日
    瀏覽(23)
  • 使用多數(shù)據(jù)源dynamic-datasource-spring-boot-starter遇到的問題記錄

    使用多數(shù)據(jù)源dynamic-datasource-spring-boot-starter遇到的問題記錄

    記錄使用多數(shù)據(jù)源dynamic-datasource-spring-boot-starter遇到的問題: 1、工程啟動失敗 缺少clickhouse連接驅(qū)動,引入對應(yīng)的maven依賴 2、clickhouse的sql語句讀到了mysql數(shù)據(jù)庫 在工程的配置文件只配置了ck數(shù)據(jù)源配置的時候,@DS(“數(shù)據(jù)源名稱”)用在service接口上沒什么問題。 由于新的需求

    2024年02月15日
    瀏覽(28)
  • 苞米豆的多數(shù)據(jù)源 → dynamic-datasource-spring-boot-starter,挺香的!

    苞米豆的多數(shù)據(jù)源 → dynamic-datasource-spring-boot-starter,挺香的!

    2023年元旦,我媽又開始了對我的念叨 媽:你到底想多少歲結(jié)婚 我:60 媽:60,你想找個多大的 我:找個55的啊,她55我60,結(jié)婚都有退休金,不用上班不用生孩子,不用買車買房,成天就是玩兒 我:而且一結(jié)婚就是白頭偕老,多好 我媽直接一大嘴巴子呼我臉上 最近接到一個

    2023年04月21日
    瀏覽(19)
  • 分享一個優(yōu)秀的動態(tài)數(shù)據(jù)源開源庫-dynamic-datasource-spring-boot-starter

    分享一個優(yōu)秀的動態(tài)數(shù)據(jù)源開源庫-dynamic-datasource-spring-boot-starter

    在我們的Java后端研發(fā)工作中, 有時候由于業(yè)務(wù)的快速迭代和數(shù)據(jù)的安全隔離性,往往會為不同的 API業(yè)務(wù)線分配不同的數(shù)據(jù)庫,即一個微服務(wù)經(jīng)常需要和多個數(shù)據(jù)源打交道。 dynamic-datasource-spring-boot-starter 是一個基于springboot的快速集成多數(shù)據(jù)源的啟動器。 其支持 Jdk 1.7+, Spring

    2024年02月12日
    瀏覽(18)
  • 使用dynamic-datasource-spring-boot-starter動態(tài)切換數(shù)據(jù)源操作數(shù)據(jù)庫(MyBatis-3.5.9)

    記錄 :383 場景 :使用dynamic-datasource-spring-boot-starter動態(tài)切換數(shù)據(jù)源,使用MyBatis操作數(shù)據(jù)庫。提供三種示例:一,使用@DS注解作用到類上。二,使用@DS注解作用到方法上。三,不使用注解,使用DynamicDataSourceContextHolder類在方法內(nèi)靈活切換不同數(shù)據(jù)源。 源碼: https://github.com/

    2024年01月20日
    瀏覽(24)
  • CompletableFuture異步編程事務(wù)及多數(shù)據(jù)源配置詳解(含gitee源碼)

    CompletableFuture異步編程事務(wù)及多數(shù)據(jù)源配置詳解(含gitee源碼)

    倉庫地址:?buxingzhe: 一個多數(shù)據(jù)源和多線程事務(wù)練習(xí)項(xiàng)目 小伙伴們在日常編碼中經(jīng)常為了提高程序運(yùn)行效率采用多線程編程,在不涉及事務(wù)的情況下,使用dou.lea大神提供的CompletableFuture異步編程利器,它提供了許多優(yōu)雅的api,我們可以很方便的進(jìn)行異步多線程編程,速度杠杠

    2024年01月22日
    瀏覽(20)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包