dynamic datasource for springboot 多数据源 动态数据源 主从分离 读写分离 分布式事务

Overview

一个基于springboot的快速集成多数据源的启动器

dynamic-sring-boot-starter

简介

dynamic-datasource-spring-boot-starter 是一个基于springboot的快速集成多数据源的启动器。

其支持 Jdk 1.7+, SpringBoot 1.4.x 1.5.x 2.x.x

文档 | Documentation

中文 | English

特性

  1. 支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。
  2. 支持无数据源启动,支持配置懒启动数据源(3.3.2+)。
  3. 支持数据库敏感配置信息 加密 ENC()。
  4. 支持每个数据库独立初始化表结构schema和数据库database。
  5. 支持 自定义注解 ,需继承DS(3.2.0+)。
  6. 提供对Druid,Mybatis-Plus,P6sy,Jndi的快速集成。
  7. 简化Druid和HikariCp配置,提供 全局参数配置 。配置一次,全局通用。
  8. 提供 自定义数据源来源 方案。
  9. 提供项目启动后 动态增加移除数据源 方案。
  10. 提供Mybatis环境下的 纯读写分离 方案。
  11. 提供使用 spel动态参数 解析数据源方案。内置spel,session,header,支持自定义。
  12. 支持 多层数据源嵌套切换 。(ServiceA >>> ServiceB >>> ServiceC)。
  13. 提供对shiro,sharding-jdbc,quartz等第三方库集成的方案,注意事项和示例。
  14. 提供 基于seata的分布式事务方案。 附:不支持原生spring事务。
  15. 提供 本地多数据源事务方案。 附:不支持原生spring事务(3.3.1+)。

约定

  1. 本框架只做 切换数据源 这件核心的事情,并不限制你的具体操作,切换了数据源可以做任何CRUD。
  2. 配置文件所有以下划线 _ 分割的数据源 首部 即为组的名称,相同组名称的数据源会放在一个组下。
  3. 切换数据源可以是组名,也可以是具体数据源名称。组名则切换时采用负载均衡算法切换。
  4. 默认的数据源名称为 master ,你可以通过 spring.datasource.dynamic.primary 修改。
  5. 方法上的注解优先于类上注解。
  6. DS支持继承抽象类上的DS,暂不支持继承接口上的DS。

使用方法

  1. 引入dynamic-datasource-spring-boot-starter。
<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
  <version>${version}</version>
</dependency>
  1. 配置数据源。
spring:
  datasource:
    dynamic:
      primary: master #设置默认的数据源或者数据源组,默认值即为master
      lazy: false #默认立即初始化数据源,true则支持在需要建立连接时再初始化数据源
      strict: false #设置严格模式,默认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: ENC(xxxxx) # 内置加密,使用请查看详细文档
          username: ENC(xxxxx)
          password: ENC(xxxxx)
          driver-class-name: com.mysql.jdbc.Driver
          schema: db/schema.sql # 配置则生效,自动初始化表结构
          data: db/data.sql # 配置则生效,自动初始化数据
          continue-on-error: true # 默认true,初始化失败是否继续
          separator: ";" # sql默认分号分隔符
          lazy: true #可独立配置是否启用懒启动
          
       #......省略
       #以上会配置一个默认库master,一个组slave下有两个子库slave_1,slave_2
# 多主多从                      纯粹多库(记得设置primary)                   混合配置
spring:                               spring:                               spring:
  datasource:                           datasource:                           datasource:
    dynamic:                              dynamic:                              dynamic:
      datasource:                           datasource:                           datasource:
        master_1:                             mysql:                                master:
        master_2:                             oracle:                               slave_1:
        slave_1:                              sqlserver:                            slave_2:
        slave_2:                              postgresql:                           oracle_1:
        slave_3:                              h2:                                   oracle_2:
  1. 使用 @DS 切换数据源。

@DS 可以注解在方法上或类上,同时存在就近原则 方法上注解 优先于 类上注解

注解 结果
没有@DS 默认数据源
@DS("dsName") dsName可以为组名也可以为具体某个库的名称
@Service
@DS("slave")
public class UserServiceImpl implements UserService {

  @Autowired
  private JdbcTemplate jdbcTemplate;

  public List selectAll() {
    return  jdbcTemplate.queryForList("select * from user");
  }
  
  @Override
  @DS("slave_1")
  public List selectByCondition() {
    return  jdbcTemplate.queryForList("select * from user where age >10");
  }
}

捐赠

uSA83t.png uSVpFJ.png

Comments
  • 无法加载到多数据源

    无法加载到多数据源

    Enviroment

    JDK Version(required): 1.8

    SpringBoot Version(required): 2.2.4

    Starter Version(required):3.0.4

    Describe

    动态数据源-检测到druid存在,如配置中未指定type,druid会默认配置,只进行到这一步,却没有提示加载到几个数据源

    Expected Result:

    Actual Result:

    Steps to reproduce

    • Step 1

    • Step 2

    • Step 3

    opened by hp88yx 25
  • 在类方法上加了@DS注解后,不管类和方法上的@DS注解指向哪个数据源,都会导致读取的始终是默认的数据源

    在类方法上加了@DS注解后,不管类和方法上的@DS注解指向哪个数据源,都会导致读取的始终是默认的数据源

    Enviroment

    JDK Version(required): JDK1.8

    SpringBoot Version(required): org.springframework.boot:spring-boot-starter-webflux:2.1.9.RELEASE

    dynamic-datasource-spring-boot-starter Version(required): 3.3.2

    druid Version(optional): 1.1.21

    Describe what happened

    在类和方法上都使用了@DS注解,经过测试发现只要在类上加入了该注解,不管类上的注解是@DS("master")还是@DS("slave"),方法上的@DS是啥,都会导致方法执行的时候默认读取master数据源

    Expected Result: 期望按照文档中说的类上的注解优先级低于方法上的注解

    Actual Result: 实际发现只要类上加了注解,不管类上和方法上的注解指定哪个数据源,都会导致只读取默认配置的数据源

    Steps to reproduce

    • Step 1 pom依赖r如下:
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
        <version>3.3.2</version>
    </dependency>
    

    数据源配置如下:

    spring:
      datasource:
        dynamic:
          primary: master #设置默认的数据源或者数据源组,默认值即为master
          strict: true #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
          datasource:
            master:
              url: ${master.datasource.url}?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&tinyInt1isBit=false&allowMultiQueries=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
              username: ${master.datasource.username}
              password: ${master.datasource.password}
              driver-class-name: com.mysql.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
            slave:
              url: ${slave.datasource.basicUrl}?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&tinyInt1isBit=false&allowMultiQueries=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
              username: ${slave.datasource.basicUsername}
              password: ${slave.datasource.basicPassword}
              driver-class-name: com.mysql.jdbc.Driver
    

    类方法部分代码截图如下: 类上的注解截图: image 方法上的注解截图: image 在issue里面找到一个类似的回答 但是替换成不使用Iservice中的默认方法测试后还是得到了非预期的结果,参照上文提供的方法上的注解截图。

    opened by chengwengao 11
  • 新增多数据源事务传播机制

    新增多数据源事务传播机制

    1.主要提取DynamicLocalTransactionInterceptor中的方法到TransactionalTemplate TransactionalInfo transactionInfo = transactionalExecutor.getTransactionInfo(); if (!StringUtils.isEmpty(TransactionContext.getXID())) { return transactionalExecutor.execute(); } boolean state = true; Object o; String xid = LocalTxUtil.startTransaction(); try { o = transactionalExecutor.execute(); } catch (Exception e) { state = !isRollback(e, transactionInfo); throw e; } finally { if (state) { LocalTxUtil.commit(xid); } else { LocalTxUtil.rollback(xid); } } return o; 原代理方法改为获取注解属性对象的封装 Method method = methodInvocation.getMethod(); final DSTransactional dsTransactional = method.getAnnotation(DSTransactional.class);

        TransactionalExecutor transactionalExecutor = new TransactionalExecutor() {
            @Override
            public Object execute() throws Throwable {
                return methodInvocation.proceed();
            }
    
            @Override
            public TransactionalInfo getTransactionInfo() {
                TransactionalInfo transactionInfo = new TransactionalInfo();
                transactionInfo.setPropagation(dsTransactional.propagation());
                transactionInfo.setNoRollbackFor(dsTransactional.noRollbackFor());
                transactionInfo.setRollbackFor(dsTransactional.rollbackFor());
                return transactionInfo;
            }
        }
    

    2.AbstractRoutingDataSource获取数据源中获取事务的数据源的方法加入xid ConnectionProxy connection = ConnectionFactory.getConnection(ds); return connection == null ? getConnectionProxy(ds, determineDataSource().getConnection()) : connection; ConnectionProxy connection = ConnectionFactory.getConnection(xid, ds); return connection == null ? getConnectionProxy(xid,ds, determineDataSource().getConnection()) : connection; 3,。增加事务异常类TransactionException

    public class TransactionException extends RuntimeException { public TransactionException(String message) { super(message); }

    public TransactionException(String message, Throwable cause) {
        super(message, cause);
    }
    

    } 4.ConnectionFactory 对于事务数据源的处理通过xid保存 通过xid获取指定事务 public class ConnectionFactory {

    private static final ThreadLocal<Map<String, ConnectionProxy>> CONNECTION_HOLDER =
            new ThreadLocal<Map<String, ConnectionProxy>>() {
    private static final ThreadLocal<Map<String, Map<String, ConnectionProxy>>> CONNECTION_HOLDER =
            new ThreadLocal<Map<String, Map<String, ConnectionProxy>>>() {
                @Override
                protected Map<String, ConnectionProxy> initialValue() {
                    return new ConcurrentHashMap<>(8);
                protected Map<String, Map<String, ConnectionProxy>> initialValue() {
                    return new ConcurrentHashMap<>();
                }
            };
    
    public static void putConnection(String ds, ConnectionProxy connection) {
        Map<String, ConnectionProxy> concurrentHashMap = CONNECTION_HOLDER.get();
        if (!concurrentHashMap.containsKey(ds)) {
    public static void putConnection(String xid, String ds, ConnectionProxy connection) {
        Map<String, Map<String, ConnectionProxy>> concurrentHashMap = CONNECTION_HOLDER.get();
        Map<String, ConnectionProxy> connectionProxyMap = concurrentHashMap.get(xid);
        if (connectionProxyMap == null) {
            connectionProxyMap = new ConcurrentHashMap<>();
            concurrentHashMap.put(xid, connectionProxyMap);
        }
        if (!connectionProxyMap.containsKey(ds)) {
            try {
                connection.setAutoCommit(false);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            concurrentHashMap.put(ds, connection);
            connectionProxyMap.put(ds, connection);
        }
    }
    
    public static ConnectionProxy getConnection(String ds) {
        return CONNECTION_HOLDER.get().get(ds);
    public static ConnectionProxy getConnection(String xid, String ds) {
        Map<String, Map<String, ConnectionProxy>> concurrentHashMap = CONNECTION_HOLDER.get();
        Map<String, ConnectionProxy> connectionProxyMap = concurrentHashMap.get(xid);
        if (CollectionUtils.isEmpty(connectionProxyMap)) {
            return null;
        }
        return connectionProxyMap.get(ds);
    }
    
    public static void notify(Boolean state) {
    public static void notify(String xid, Boolean state) {
        Map<String, Map<String, ConnectionProxy>> concurrentHashMap = CONNECTION_HOLDER.get();
        try {
            Map<String, ConnectionProxy> concurrentHashMap = CONNECTION_HOLDER.get();
            for (ConnectionProxy connectionProxy : concurrentHashMap.values()) {
                connectionProxy.notify(state);
            if (CollectionUtils.isEmpty(concurrentHashMap)) {
                return;
            }
            Map<String, ConnectionProxy> connectionProxyMap = concurrentHashMap.get(xid);
            for (ConnectionProxy connectionProxy : connectionProxyMap.values()) {
                if (connectionProxy != null) {
                    connectionProxy.notify(state);
                }
            }
        } finally {
            CONNECTION_HOLDER.remove();
            concurrentHashMap.remove(xid);
        }
    }
    

    5.DsPropagation 事务传播机制枚举 6.src/main/java/com/baomidou/dynamic/datasource/tx/LocalTxUtil.java 事务工具提交关闭事务加入xid进行获取 public static void startTransaction() { if (!StringUtils.isEmpty(TransactionContext.getXID())) { log.debug("dynamic-datasource exist local tx [{}]", TransactionContext.getXID()); public static String startTransaction() { String xid = TransactionContext.getXID(); if (!StringUtils.isEmpty(xid)) { log.debug("dynamic-datasource exist local tx [{}]", xid); } else { String xid = UUID.randomUUID().toString(); xid = UUID.randomUUID().toString(); TransactionContext.bind(xid); log.debug("dynamic-datasource start local tx [{}]", xid); } return xid; }

    /**
     * 手动提交事务
     */
    public static void commit() {
        ConnectionFactory.notify(true);
    public static void commit(String xid) {
        ConnectionFactory.notify(xid, true);
        log.debug("dynamic-datasource commit local tx [{}]", TransactionContext.getXID());
        TransactionContext.remove();
    }
    
    /**
     * 手动回滚事务
     */
    public static void rollback() {
        ConnectionFactory.notify(false);
    public static void rollback(String xid) {
        ConnectionFactory.notify(xid, false);
        log.debug("dynamic-datasource rollback local tx [{}]", TransactionContext.getXID());
        TransactionContext.remove();
    }
    

    7.事务传播机制使用的事务暂停xid对象 用于事务暂停和恢复xid package com.baomidou.dynamic.datasource.tx;

    import javax.annotation.Nonnull;

    public class SuspendedResourcesHolder { /** * The xid */ private String xid;

    public SuspendedResourcesHolder(String xid) {
        if (xid == null) {
            throw new IllegalArgumentException("xid must be not null");
        }
        this.xid = xid;
    }
    
    @Nonnull
    public String getXid() {
        return xid;
    }
    

    } 8。TransactionalExecutor 事务执行器接口 9.TransactionalInfo 对事务注解中属性的封装 10.TransactionalTemplate 事务模板方法 对事务的操作抽取到模板方法中实现。后续可自定义扩展模板方法 处理异常和事务传播机制 package com.baomidou.dynamic.datasource.tx;

    import com.baomidou.dynamic.datasource.exception.TransactionException; import com.baomidou.mybatisplus.core.toolkit.ArrayUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.util.StringUtils;

    import java.util.Objects;

    @Slf4j public class TransactionalTemplate {

    public Object execute(TransactionalExecutor transactionalExecutor) throws Throwable {
        TransactionalInfo transactionInfo = transactionalExecutor.getTransactionInfo();
        DsPropagation propagation = transactionInfo.propagation;
        SuspendedResourcesHolder suspendedResourcesHolder = null;
        try {
            switch (propagation) {
                case NOT_SUPPORTED:
                    // If transaction is existing, suspend it.
                    if (existingTransaction()) {
                        suspendedResourcesHolder = suspend();
                    }
                    return transactionalExecutor.execute();
                case REQUIRES_NEW:
                    // If transaction is existing, suspend it, and then begin new transaction.
                    if (existingTransaction()) {
                        suspendedResourcesHolder = suspend();
                    }
                    // Continue and execute with new transaction
                    break;
                case SUPPORTS:
                    // If transaction is not existing, execute without transaction.
                    if (!existingTransaction()) {
                        return transactionalExecutor.execute();
                    }
                    // Continue and execute with new transaction
                    break;
                case REQUIRED:
                    // default
                    break;
                case NEVER:
                    // If transaction is existing, throw exception.
                    if (existingTransaction()) {
                        throw new TransactionException("Existing transaction found for transaction marked with propagation never");
                    } else {
                        // Execute without transaction and return.
                        return transactionalExecutor.execute();
                    }
                case MANDATORY:
                    // If transaction is not existing, throw exception.
                    if (!existingTransaction()) {
                        throw new TransactionException("No existing transaction found for transaction marked with propagation 'mandatory'");
                    }
                    // Continue and execute with current transaction.
                    break;
                default:
                    throw new TransactionException("Not Supported Propagation:" + propagation);
            }
            return doExecute(transactionalExecutor);
        } finally {
            resume(suspendedResourcesHolder);
        }
    }
    
    private Object doExecute(TransactionalExecutor transactionalExecutor) throws Throwable {
        TransactionalInfo transactionInfo = transactionalExecutor.getTransactionInfo();
        if (!StringUtils.isEmpty(TransactionContext.getXID())) {
            return transactionalExecutor.execute();
        }
        boolean state = true;
        Object o;
        String xid = LocalTxUtil.startTransaction();
        try {
            o = transactionalExecutor.execute();
        } catch (Exception e) {
            state = !isRollback(e, transactionInfo);
            throw e;
        } finally {
            if (state) {
                LocalTxUtil.commit(xid);
            } else {
                LocalTxUtil.rollback(xid);
            }
        }
        return o;
    }
    
    private boolean isRollback(Throwable e, TransactionalInfo transactionInfo) {
        boolean isRollback = true;
        Class<? extends Throwable>[] rollbacks = transactionInfo.rollbackFor;
        Class<? extends Throwable>[] noRollbackFor = transactionInfo.noRollbackFor;
        if (ArrayUtils.isNotEmpty(noRollbackFor)) {
            for (Class<? extends Throwable> noRollBack : noRollbackFor) {
                int depth = getDepth(e.getClass(), noRollBack);
                if (depth >= 0) {
                    return false;
                }
            }
        }
        if (ArrayUtils.isNotEmpty(rollbacks)) {
            for (Class<? extends Throwable> rollback : rollbacks) {
                int depth = getDepth(e.getClass(), rollback);
                if (depth >= 0) {
                    return isRollback;
                }
            }
        }
        return false;
    }
    
    private int getDepth(Class<?> exceptionClass, Class<? extends Throwable> rollback) {
        if (rollback == Throwable.class || rollback == Exception.class) {
            return 0;
        }
        // If we've gone as far as we can go and haven't found it...
        if (exceptionClass == Throwable.class) {
            return -1;
        }
        if (Objects.equals(exceptionClass, rollback)) {
            return 0;
        }
        return getDepth(exceptionClass.getSuperclass(), rollback);
    }
    
    private void resume(SuspendedResourcesHolder suspendedResourcesHolder) {
        if (suspendedResourcesHolder != null) {
            String xid = suspendedResourcesHolder.getXid();
            TransactionContext.bind(xid);
        }
    }
    
    public SuspendedResourcesHolder suspend() {
        String xid = TransactionContext.getXID();
        if (xid != null) {
            if (log.isInfoEnabled()) {
                log.info("Suspending current transaction, xid = {}", xid);
            }
            TransactionContext.unbind(xid);
            return new SuspendedResourcesHolder(xid);
        } else {
            return null;
        }
    }
    
    public boolean existingTransaction() {
        return !StringUtils.isEmpty(TransactionContext.getXID());
    }
    

    }

    opened by zhaohaoh 10
  • fix: 修复spring.datasource.dynamic.druid.maxWait等配置未生效的问题

    fix: 修复spring.datasource.dynamic.druid.maxWait等配置未生效的问题

    What kind of change does this PR introduce? (check at least one)

    • [x] Bugfix
    • [ ] Feature
    • [ ] Code style
    • [ ] Refactor
    • [ ] Doc
    • [ ] Other, please describe:

    The description of the PR: 修复一些连接池配置未生效的问题 比如spring.datasource.dynamic.druid.maxWait, spring.datasource.dynamic.druid.maxActive等 曾导致maxWait使用了默认值 -1 ,数据库连接卡住,无任何响应

    Other information:

    opened by ContantLearn 10
  • DynamicRoutingDataSource#determinePrimaryDataSource  调用之后应该 finally 清理 threadLocal

    DynamicRoutingDataSource#determinePrimaryDataSource 调用之后应该 finally 清理 threadLocal

    Please fill it out carefully, or it will be closed. 请认真填写,不然会直接关闭。

    Enviroment

    JDK Version(required): 1.8

    SpringBoot Version(required): 2.1.9.Release

    dynamic-datasource-spring-boot-starter Version(required):3.1.0

    druid Version(optional):

    Describe what happened

    Expected Result:

    main thread invoke method DynamicDataSourceContextHolder.peek() ,so all thread inherit ThreadLocal ,and then every thread can affect by each other. Actually main Thread get the default datasource by getConnecttion and will not clear the threadLocalVariable, so when get default datasource, it can manully clear the thread local map.

    Actual Result:

    main thread invoke method DynamicDataSourceContextHolder.peek() ,so all thread inherit ThreadLocal ,and then every thread can affect by each other.

    If there is an exception,or aop invalid,please attach the exception trace:

    Just paste your stack trace here!
    

    Steps to reproduce

    • Step 1

    import activiti

    and below method will invoke dataSource.getConnection(); and main thread has the threadLocal.

    org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl#initDatabaseType
    
    private DataSource determinePrimaryDataSource() {
            log.debug("dynamic-datasource switch to the primary datasource");
            try {
                return groupDataSources.containsKey(primary) ? groupDataSources.get(primary).determineDataSource() : dataSourceMap.get(primary);
            } finally {
                DynamicDataSourceContextHolder.clear();
            }
    
    }
    
    opened by wayne0zhang 10
  • mybatis关联查询怎么设置多数据源

    mybatis关联查询怎么设置多数据源

    Enviroment

    JDK Version(required): 8u171

    SpringBoot Version(required): 2.2.6

    dynamic-datasource-spring-boot-starter Version(required):3.1.1

    druid Version(optional):1.1.10

    Describe

    配置数据源之后 在dao层的方法都放上DS注解 直接调用dao层的查询都能正确的使用第二数据源拿到数据 但是mapper映射文件中配置的关联查询 比如association这些都依然是使用的主数据源 这个问题有办法解决吗

    另外我没有使用mybatis-plus 数据库这块就是springboot+druid+myabtis 如果把DS注解写在dao层的类上就会报错 java.lang.IllegalArgumentException: Can not set final java.lang.Class field org.apache.ibatis.binding.MapperProxy.mapperInterface to org.springframework.aop.framework.JdkDynamicAopProxy

    opened by panther1942 10
  • @DS数据源未匹配成功,不管如何设置都是使用默认的primary的库

    @DS数据源未匹配成功,不管如何设置都是使用默认的primary的库

    Enviroment

    JDK Version(required): jdk1.8 SpringBoot Version(required): 2.1.3.RELEASE Starter Version(required): 2.5.3

    Describe

    按照示例进行了项目改造,然后我不管在mapper还是serviceImpl里面设置ds源,都无效,直接全是primary设置的库,我跟踪进去后,发现DS的value注入值一直为null,调试跟踪没有解决掉,所以来请教下

    项目使用了mybatisplus 3.1.0版本

    image

    image

    image

    image image

    image

    跟了代码,发现在init load的时候,的确两个连接都进去了,但是在使用的时候,ds不能取到填写的那个value的值

    Expected Result: 我的表system_user是在membermanage库,但是每次都是到我的默认库smartcampus

    Actual Result:

    期望能在指定库,不是在默认库

    Steps to reproduce

    • Step 1

    • Step 2

    • Step 3

    opened by noroadzh 10
  • druid多数据源错误》dbType not support : null, url null

    druid多数据源错误》dbType not support : null, url null

    Enviroment

    JDK Version(required): 1.8 SpringBoot Version(required): 2.1.1 Starter Version(required): 3.0.6 & 1.3.0

    Describe

    druid多数据源错误》dbType not support : null, url null

    不引入多数据源,mybatis-plus启动正常,引入后启动失败

    配置 datasource: druid: stat-view-servlet: loginUsername: admin loginPassword: 123456 dynamic: primary: master #设置默认的数据源或者数据源组,默认值即为master druid: # 全局druid参数,绝大部分值和默认保持一致。(现已支持的参数如下,不清楚含义不要乱设置) initial-size: 1 max-active: 20 min-idle: 1 max-wait: 60000 time-between-eviction-runs-millis: 60000 test-while-idle: true test-on-borrow: false test-on-return: false validation-query: select 'x' pool-prepared-statements: true filters: stat,wall # 注意这个值和druid原生不一致,默认启动了stat,wall datasource: master: username: sa password: 123456 driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver url: jdbc:sqlserver://192.168.0.65:1433;DatabaseName=tyksnew;

    mybaits-plus配置

    mybatis-plus:

    MyBatis Mapper所对应的XML文件位置

    mapper-locations: classpath:/mapper/*Mapper.xml typeAliasesPackage: com.test.exam.entity global-config: # 自动刷新Mapper对应的XML文件 refresh: false # 关闭MP3.0自带的banner banner: false db-config: #主键类型 0:"数据库ID自增", 1:"未设置主键类型",2:"用户输入ID",3:"全局唯一ID (数字类型唯一ID)", 4:"全局唯一ID UUID"; id-type: AUTO #字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断" field-strategy: NOT_NULL # 默认数据库表下划线命名 table-underline: true # 逻辑删除配置 # 逻辑删除全局值(1表示已删除,这也是Mybatis Plus的默认配置) logic-delete-value: 1 # 逻辑未删除全局值(0表示未删除,这也是Mybatis Plus的默认配置) logic-not-delete-value: 0 configuration: map-underscore-to-camel-case: true

    错误信息:

    va.lang.IllegalStateException: dbType not support : null, url null at com.alibaba.druid.wall.WallFilter.init(WallFilter.java:159) at com.alibaba.druid.pool.DruidDataSource.init(DruidDataSource.java:762) at com.baomidou.dynamic.datasource.AbstractDynamicDataSourceProvider.createDruidDataSource(AbstractDynamicDataSourceProvider.java:91) at com.baomidou.dynamic.datasource.AbstractDynamicDataSourceProvider.createDataSource(AbstractDynamicDataSourceProvider.java:40) at com.baomidou.dynamic.datasource.YmlDynamicDataSourceProvider.loadMasterDataSource(YmlDynamicDataSourceProvider.java:38) at com.baomidou.dynamic.datasource.DynamicRoutingDataSource.afterPropertiesSet(DynamicRoutingDataSource.java:56) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1804) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1741) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:576) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:273) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1237) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1164) at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760) at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:509) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1288) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1127) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:273) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1237) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1164) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1467) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1362) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:575) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:273) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1237) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1164) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:593) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:374) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1378) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:575) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:846) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:863) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546) at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) at com.fairplay.exam.ExamApplication.main(ExamApplication.java:15) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)

    opened by liulipengju 10
  • 关于事务的问题想说一下

    关于事务的问题想说一下

    文档上说的不支持spring原生事务,说的不完全对。

    首先说下为什么不支持Spring原生事务,因为切面执行顺序不一样,如果 @Transactional 注解先执行会调用getConnection方法,这时候我们的@Ds注解还没起作用呢,所以拿到的Connection会有问题

    但是我们让@Ds这个注解先起作用就可以了。

    最后这个问题完全可以用手动调用切换数据源的操作来让项目支持Spring的原生事务 实现应该挺简单的。

    opened by cqyisbug 9
  • dynamic-datasource多库配置,一个库连不上,整个程序都会终止运行,这个问题要如何避免?

    dynamic-datasource多库配置,一个库连不上,整个程序都会终止运行,这个问题要如何避免?

    baomidou团队推出dynamic-datasource模块,用来配置多数据库源还是十分方便的 —— 不用写繁琐的Config Bean,直接在dao类里打@DS注解就可以了。

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

    但我最近发现一个问题:当你所配置的多个数据源里面,只要有1个数据源无法访问,整个程序在启动时就会报错终止,不再运行。

    虽然这个问题发生的情况不算多,但还是有可能会遇到,因此我希望能够避免。

    换言之:我希望当某个数据源连不上时,仅影响该数据源本身,而不是终止整个程序。 让其他能够正常连接的数据源依然能够正常运作。

    这个要如何配置呢?或者有什么改进方案没?

    https://www.zhihu.com/question/395982380

    opened by Hu-J-H 9
  • 整合sharding的时候,停止程序报错,和#395差不多

    整合sharding的时候,停止程序报错,和#395差不多

    image 如:https://github.com/baomidou/dynamic-datasource-spring-boot-starter/issues/395 但是我这边是报了npe。

    datasource的配置: `@Configuration public class DataSourceAutoConfiguration { /** * 分表数据源名称 */ public static final String SHARDING_DATA_SOURCE_NAME = "sharding"; @Resource private DynamicDataSourceProperties properties; @Lazy @Resource private ShardingDataSource shardingDataSource;

    @Bean
    public DynamicDataSourceProvider dynamicDataSourceProvider() {
        return new AbstractDataSourceProvider() {
            @Override
            public Map<String, DataSource> loadDataSources() {
                Map<String, DataSource> dataSourceMap = new HashMap<>();
                dataSourceMap.put(SHARDING_DATA_SOURCE_NAME, shardingDataSource);
                Map<String, DataSource> shardingInnerDataSources = shardingDataSource.getDataSourceMap();
                dataSourceMap.putAll(shardingInnerDataSources);
                return dataSourceMap;
            }
        };
    }
    
    @Primary
    @Bean
    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;
    }
    

    }`

    yml的配置: spring: datasource: dynamic: strict: true hikari: min-idle: 5 max-pool-size: 50 is-auto-commit: true idle-timeout: 30000 max-lifetime: 300000 connection-timeout: 30000 connection-test-query: select 1 datasource: master: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver pool-name: xxx-pool username: root password: url: jdbc:mysql://localhost:3306/xxx?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&connectTimeout=5000&socketTimeout=60000 stock: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver pool-name: xxx-pool username: root password: url: jdbc:mysql://localhost:3306/xxx?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&connectTimeout=5000&socketTimeout=60000 shardingsphere: datasource: names: ds-0 ds-0: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://localhost:3306/sharding_0?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&connectTimeout=5000&socketTimeout=60000 username: root password: min-idle: 5 max-pool-size: 50 is-auto-commit: true idle-timeout: 30000 pool-name: ds-0-pool max-lifetime: 300000 connection-timeout: 30000 connection-test-query: select 1 sharding: tables: tb_user: actual-data-nodes: ds-0.tb_user_$->{0..1} table-strategy: standard: sharding-column: user_id precise-algorithm-class-name: xxx.TbShardingAlgorithmForLong algorithm: config: - tableName: tb_user shardingNumber: 2

    Enviroment

    JDK Version(required): 1.8 SpringBoot Version(required): 2.3.2 dynamic-datasource-spring-boot-starter Version(required): 3.5.0 sharding Version(optional): 4.1.1

    Describe what happened

    想知道 https://github.com/baomidou/dynamic-datasource-spring-boot-starter/issues/395 说是等发版,是已经解决了还是latest版本目前还没解决。

    Expected Result:

    Actual Result:

    If there is an exception,or aop invalid,please attach the exception trace:

    Just paste your stack trace here!
    

    Steps to reproduce

    • Step 1

    • Step 2

    • Step 3

    opened by hachikozjq 8
  • build(deps-dev): bump spring-boot-starter-web from 1.5.3.RELEASE to 2.5.12

    build(deps-dev): bump spring-boot-starter-web from 1.5.3.RELEASE to 2.5.12

    Bumps spring-boot-starter-web from 1.5.3.RELEASE to 2.5.12.

    Release notes

    Sourced from spring-boot-starter-web's releases.

    v2.5.12

    :lady_beetle: Bug Fixes

    • MustacheAutoConfiguration in a Servlet web application fails with a ClassNotFoundException when Spring MVC is not on the classpath #30456

    :notebook_with_decorative_cover: Documentation

    • Javadoc of org.springframework.boot.gradle.plugin.ResolveMainClassName.setClasspath(Object) is inaccurate #30468
    • Document that @DefaultValue can be used on a record component #30460

    :hammer: Dependency Upgrades

    • Upgrade to Jackson Bom 2.12.6.20220326 #30477
    • Upgrade to Spring Framework 5.3.18 #30491

    :heart: Contributors

    We'd like to thank all the contributors who worked on this release!

    v2.5.11

    :star: New Features

    • Add EIGHTEEN to JavaVersion enum #29524

    :lady_beetle: Bug Fixes

    • Thymeleaf auto-configuration in a reactive application can fail due to duplicate templateEngine beans #30384
    • ConfigurationPropertyName#equals is not symmetric when adapt has removed trailing characters from an element #30317
    • server.tomcat.keep-alive-timeout is not applied to HTTP/2 #30267
    • Setting spring.mustache.enabled to false has no effect #30250
    • bootWar is configured eagerly #30211
    • Actuator @ReadOperation on Flux cancels request after first element emitted #30095
    • No metrics are bound for R2DBC ConnectionPools that have been wrapped #30090
    • Unnecessary allocations in Prometheus scraping endpoint #30085
    • Condition evaluation report entry for a @ConditionalOnSingleCandidate that does not match due to multiple primary beans isn't as clear as it could be #30073
    • Generated password are logged without an "unsuitable for production use" note #30061
    • Files in META-INF are not found when deploying a Gradle-built executable war to a servlet container #30026
    • spring-boot-configuration-processor fails compilation due to @DefaultValue with a long value and generates invalid metadata for byte and short properties with out-of-range default values #30020
    • Dependency management for Netty tcNative is incomplete leading to possible version conflicts #30010
    • Dependency management for Apache Kafka is incomplete #29023

    :notebook_with_decorative_cover: Documentation

    • Fix JsonSerializer example in reference guide #30329
    • Default value of spring.thymeleaf.reactive.media-types is not documented #30280
    • Add Netty in "Enable HTTP Response Compression" #30234

    ... (truncated)

    Commits
    • 35105a0 Release v2.5.12
    • 17936b8 Polish
    • 94c40c7 Upgrade to Spring Framework 5.3.18
    • 2e90fd2 Upgrade CI to Docker 20.10.14
    • 6cded5b Upgrade Java 18 version in CI image
    • 06c5e26 Upgrade to Jackson Bom 2.12.6.20220326
    • c0c32d8 Merge pull request #30456 from candrews
    • 8cb11b7 Polish "Make MustacheViewResolver bean back off without Spring MVC"
    • 7101b50 Make MustacheViewResolver bean back off without Spring MVC
    • 05b7bef Fix javadoc of ResolveMainClassName setClasspath(Object)
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • Add test modules and corresponding unit tests

    Add test modules and corresponding unit tests

    Please fill it out carefully, or it will be closed. 请认真填写,不然会直接关闭。

    Enviroment

    JDK Version(required):

    • 17 SpringBoot Version(required):
    • 3.0.1 dynamic-datasource-spring-boot-starter Version(required):
    • 3.6.0 druid Version(optional):
    • Null.

    Describe what happened

    • The project's GitHub Actions lacks tests for specific features.

    Expected Result:

    • Add test modules and corresponding unit tests.
    • Related to https://github.com/baomidou/dynamic-datasource-spring-boot-starter/issues/471 and https://github.com/linghengqian/graalvm-trace-metadata-smoketest/issues/1. This will first help with graalvm's nativeTest integration.

    Actual Result:

    If there is an exception,or aop invalid,please attach the exception trace:

    Just paste your stack trace here!
    

    Steps to reproduce

    • Step 1

    • Step 2

    • Step 3

    opened by linghengqian 1
  • Dynamic Datasource not judging Jakarta EE namespace when using SPEL

    Dynamic Datasource not judging Jakarta EE namespace when using SPEL

    Please fill it out carefully, or it will be closed. 请认真填写,不然会直接关闭。

    Enviroment

    JDK Version(required):

    • 17

    SpringBoot Version(required):

    • 3.0.1

    dynamic-datasource-spring-boot-starter Version(required):

    • 3.6.1

    druid Version(optional):

    • Null.

    Describe what happened

    • Dynamic Datasource not judging Jakarta EE namespace when using SPEL.
    • Found at https://github.com/oracle/graalvm-reachability-metadata/pull/154 and https://github.com/linghengqian/graalvm-trace-metadata-smoketest/issues/1 .

    Expected Result:

    • Normal.

    Actual Result:

    • An error occurred.

    If there is an exception,or aop invalid,please attach the exception trace:

    Caused by: jakarta.servlet.ServletException: Handler dispatch failed: java.lang.NoSuchMethodError: 'javax.servlet.http.HttpServletRequest org.springframework.web.context.request.ServletRequestAttributes.getRequest()'
    	at app//org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1095)
    	at app//org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973)
    	at app//org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1010)
    	at app//org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:902)
    	at app//jakarta.servlet.http.HttpServlet.service(HttpServlet.java:705)
    	at app//org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:884)
    	at app//org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72)
    	at app//jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814)
    	at app//org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:165)
    	at app//org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132)
    	at app//org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:201)
    	at app//com.lingh.dynamicdatasourcespeltest.SPELTest.lambda$testSPEL$0(SPELTest.java:67)
    	at app//org.junit.jupiter.api.AssertDoesNotThrow.assertDoesNotThrow(AssertDoesNotThrow.java:49)
    	... 88 more
    Caused by: java.lang.NoSuchMethodError: 'javax.servlet.http.HttpServletRequest org.springframework.web.context.request.ServletRequestAttributes.getRequest()'
    	at com.baomidou.dynamic.datasource.processor.jakarta.DsJakartaSessionProcessor.doDetermineDatasource(DsJakartaSessionProcessor.java:43)
    	at com.baomidou.dynamic.datasource.processor.DsProcessor.determineDatasource(DsProcessor.java:53)
    	at com.baomidou.dynamic.datasource.processor.DsProcessor.determineDatasource(DsProcessor.java:60)
    	at com.baomidou.dynamic.datasource.aop.DynamicDataSourceAnnotationInterceptor.determineDatasourceKey(DynamicDataSourceAnnotationInterceptor.java:58)
    	at com.baomidou.dynamic.datasource.aop.DynamicDataSourceAnnotationInterceptor.invoke(DynamicDataSourceAnnotationInterceptor.java:47)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
    	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752)
    	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703)
    	at com.lingh.dynamicdatasourcespeltest.service.spel.UserService$$SpringCGLIB$$0.selectSpelBySession(<generated>)
    	at com.lingh.dynamicdatasourcespeltest.controller.UserController.session(UserController.java:23)
    	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207)
    	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152)
    	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
    	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884)
    	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)
    	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080)
    	... 100 more
    

    Steps to reproduce

    • git at https://github.com/linghengqian/dynamic-datasource-spel-test .
    • Execute the following commands.
    git clone [email protected]:linghengqian/dynamic-datasource-spel-test.git
    cd ./dynamic-datasource-spel-test
    sdk use java 22.3.r17-grl
    ./gradlew clean test
    
    opened by linghengqian 2
  • 添加对spring native的支持

    添加对spring native的支持

    image

    Enviroment

    JDK Version(required): graalvm-ce-java11-22.3.0

    SpringBoot Version(required): 2.7.5

    dynamic-datasource-spring-boot-starter Version(required):3.5.2

    druid Version(optional):

    Describe what happened

    Native Build Tools构建本地可执行文件时出现

    Expected Result:

    Actual Result:

    If there is an exception,or aop invalid,please attach the exception trace:

    Just paste your stack trace here!
    

    Steps to reproduce

    • Step 1

    • Step 2

    • Step 3

    help wanted 
    opened by tiro8183 7
Releases(v3.6.0)
  • v3.6.0(Dec 4, 2022)

    What's Changed

    • 支持spirngboot3
    • :sparkles: 支持 Spring Boot 新版自动配置 by @xuxiaowei-com-cn in https://github.com/baomidou/dynamic-datasource-spring-boot-starter/pull/454
    • 支持配置druid新版本socketTimeout、connectTimeout属性 by @Liu-YanP in https://github.com/baomidou/dynamic-datasource-spring-boot-starter/pull/456

    New Contributors

    • @xuxiaowei-com-cn made their first contribution in https://github.com/baomidou/dynamic-datasource-spring-boot-starter/pull/454
    • @Liu-YanP made their first contribution in https://github.com/baomidou/dynamic-datasource-spring-boot-starter/pull/456

    Full Changelog: https://github.com/baomidou/dynamic-datasource-spring-boot-starter/compare/v3.5.2...v3.6.0

    Source code(tar.gz)
    Source code(zip)
  • v3.5.2(Aug 29, 2022)

    What's Changed

    • throw exception in local transaction by @Nutao in https://github.com/baomidou/dynamic-datasource-spring-boot-starter/pull/426
    • 适用spel的#root.target by @huaibingshifu in https://github.com/baomidou/dynamic-datasource-spring-boot-starter/pull/427
    • 解决DruidConfig的stat、wall属性使用Map接受参数了,DruidStatConfigUtil在进行反射赋值的时候会报错 by @Bin1993 in https://github.com/baomidou/dynamic-datasource-spring-boot-starter/pull/434
    • 让默认的DynamicDataSourceProvider优先级为0 by @VonXXGhost in https://github.com/baomidou/dynamic-datasource-spring-boot-starter/pull/437
    • support hikaricp 原生参数

    New Contributors

    • @Nutao made their first contribution in https://github.com/baomidou/dynamic-datasource-spring-boot-starter/pull/426
    • @huaibingshifu made their first contribution in https://github.com/baomidou/dynamic-datasource-spring-boot-starter/pull/427
    • @Bin1993 made their first contribution in https://github.com/baomidou/dynamic-datasource-spring-boot-starter/pull/434
    • @VonXXGhost made their first contribution in https://github.com/baomidou/dynamic-datasource-spring-boot-starter/pull/437

    Full Changelog: https://github.com/baomidou/dynamic-datasource-spring-boot-starter/compare/v3.5.1...v3.5.2

    Source code(tar.gz)
    Source code(zip)
    dynamic-datasource-spring-boot-starter-3.5.2-javadoc.jar(890.20 KB)
    dynamic-datasource-spring-boot-starter-3.5.2-sources.jar(94.17 KB)
    dynamic-datasource-spring-boot-starter-3.5.2.jar(139.87 KB)
  • v3.5.1(Feb 24, 2022)

  • v3.5.0(Nov 25, 2021)

    What's Changed

    • feat:新增druid慢sql日志级别配置项 by @whcrow in https://github.com/baomidou/dynamic-datasource-spring-boot-starter/pull/402
    • feat:新增本地事务对类的支持 #387 by @lonecloud in https://github.com/baomidou/dynamic-datasource-spring-boot-starter/pull/405
    • feat:新增是否开启默认DS注解选项(#396) by @lonecloud in https://github.com/baomidou/dynamic-datasource-spring-boot-starter/pull/401
    • feat:新增一个event,可在数据源创建前后做自己操作。可用于自定义解密。
    • feat:新增一个LocalTxUtil可手动开启提交回滚本地事务。
    • fix:修复某些情况下关闭数据源调用close失败 by @cheese8 in https://github.com/baomidou/dynamic-datasource-spring-boot-starter/pull/391
    • fix:修复 @DS优先级 #407 by @lonecloud in https://github.com/baomidou/dynamic-datasource-spring-boot-starter/pull/408
    • fix:修复同时开启p6spy和seata,p6spy不生效的问题。
    • refactor: 重构creator的自动注入逻辑。
    • refactor: 重构druid的各种filter的参数注入,使用map来支持任意参数。
    • break:移除健康检查(支持不好,以后考虑重写)
    • break:重构自动建表配置新增init层级。
    • break: 重构策略strategy的方法为determineKey。
    • 其他,注释的完善。

    New Contributors

    • @cheese8 made their first contribution in https://github.com/baomidou/dynamic-datasource-spring-boot-starter/pull/391
    • @r-asou made their first contribution in https://github.com/baomidou/dynamic-datasource-spring-boot-starter/pull/392
    • @lonecloud made their first contribution in https://github.com/baomidou/dynamic-datasource-spring-boot-starter/pull/401
    • @whcrow made their first contribution in https://github.com/baomidou/dynamic-datasource-spring-boot-starter/pull/402

    Full Changelog: https://github.com/baomidou/dynamic-datasource-spring-boot-starter/compare/v3.4.1...v3.5.0

    Source code(tar.gz)
    Source code(zip)
    dynamic-datasource-spring-boot-starter-3.5.0.jar(137.70 KB)
  • v3.4.1(Jul 27, 2021)

    • refactor: 使用反射重构了全局参数和局部参数的使用。
    • refactor: 移除了关闭数据源的工具类,放回动态数据源类中。(部分用户反馈工具类失败)
    • refactor: 默认所有creator继承一个抽象creator处理共有逻辑。
    • feat: 可单独指定poolName了。 以前poolName和数据源名称保持一致,现在默认一致除非指定。
    Source code(tar.gz)
    Source code(zip)
  • v3.4.0(Jul 27, 2021)

    fix: 修复非默认连接池创建器创建的数据源关闭失败问题。 fix: 修复连接池创建器创建的数据源lazy空指针问题。 fix: 修复本地事务,使用默认数据源不加DS空指针问题。 feat: 新增一个DynamicDataSourcePropertiesCustomizer 以支持参数扩展。 feat: breake change,支持同时从多个来源初始化数据源。 feat: 新增一个DynamicDatasourceNamedInterceptor 以支持手动配置切面。

    Source code(tar.gz)
    Source code(zip)
  • v3.3.6(Jul 27, 2021)

    fix: 部分用户反馈强依赖DBCP。 feat: beecp和dbcp的创建根据反射重构。 style: 移除没用的stringUtils。 style: 增加些许注释。

    Source code(tar.gz)
    Source code(zip)
  • v3.3.5(Jul 27, 2021)

    fix: 修复上个版本BeeCp判断存在误用HIkaricp地址的错误。 feat: 新增dbcp2连接池支持。 fix: ItemDataSource的wrap修复,获得真实连接。 style: 移除HIkaricp无用的配置。

    Source code(tar.gz)
    Source code(zip)
  • v3.3.4(Jul 27, 2021)

    fix: 修复上个版本更改Advisor引起的数据源不能切换严重错误。 feat: 新增beecp连接池支持。 fix: ItemDataSource的wrap修复,获得真实连接。

    Source code(tar.gz)
    Source code(zip)
  • v3.3.2(Mar 13, 2021)

    • feat:重要更新-支持无数据源启动,支持配置懒启动数据源。
    • refactor:重要更新-Druid不再默认启动wall的filter。
    • refactor:重要更新-DataSourceCreator移除含有publicKey的方法,由DefaultDataSourceCreator传递。
    • refactor:DefaultDataSourceCreator独立不继承DataSourceCreator。
    • refactor:简化本地事务ThreadLocal。
    • feat: 健康检查优化。
    • style:license format。
    • chore:remove travis。
    Source code(tar.gz)
    Source code(zip)
    dynamic-datasource-spring-boot-starter-3.3.2.jar(129.64 KB)
lilishop是采用JAVA开发的B2B2C多用户商城系统/电商系统/电子商务。基于当前流行技术组合的前后端分离商城系统:后端使用 SpringBoot、MybatisPlus、SpringSecurity、redis、ES、mysql、mongodb等主流技术,前端使用vue框架iview、uniapp。支持分布式部署,分布式事务,支持docker、k8s。商城支持 PC、WAP、H5、小程序、APP等各个客户端

Lilishop B2B2C商城系统 官方公众号 & 开源不易,如有帮助请点Star 介绍 官网:https://pickmall.cn Lilishop 是一款Java开发,基于SpringBoot研发的B2B2C多用户商城,前端使用 Vue、uniapp开发 系统全端全部代码开源 产品前后端分离

null 3k Dec 31, 2022
Dynamic Configuration Capability for SpringBoot Application

Spring Boot Dynamic Config Hot-reload your SpringBoot configurations, with just a '@DynamicConfig' annotation, the simplest solution, ever. English 简体

Joey Yang 153 Jan 3, 2023
🔥 强大的动态线程池,并附带监控报警功能(没有依赖中间件),完全遵循阿里巴巴编码规范。Powerful dynamic thread pool, does not rely on any middleware, with monitoring and alarm function.

?? 动态线程池(DTP)系统,包含 Server 端及 SpringBoot Client 端需引入的 Starter. 这个项目做什么? 动态线程池(Dynamic-ThreadPool),下面简称 DTP 系统 美团线程池文章 介绍中,因为业务对线程池参数没有合理配置,触发过几起生产事故,进而

longtai 3.4k Dec 30, 2022
ReDoSHunter: A Combined Static and Dynamic Approach for Regular Expression DoS Detection

ReDoSHunter ReDoSHunter is a combined static and dynamic approach for regular expression DoS detection. LATEST NOTE (updated at 2021.09.13): ReDoSHunt

Yeting Li 43 Dec 23, 2022
Generate a dynamic PAC script that will route traffic to your Burp proxy only if it matches the scope defined in your Burp target.

Burp PAC Server This Burp Extension generates a dynamic Proxy Auto-Configuration (PAC) script that will route traffic to your Burp proxy only if it ma

null 30 Jun 13, 2022
A quiz app with great layout design, dynamic questions using firebase and what not....

AndroidQuizApp An android quiz app created using Android Studio with our language JAVA that has great layout design, dynamic questions using firebase

Ejaz Mahmood 4 Dec 30, 2022
This is the VapeCloud project, it is a Minecraft Dynamic CloudSystem based on Nio-Networking.

This is the VapeCloud project, it is a Minecraft Dynamic CloudSystem based on Nio-Networking. IMPORTENT: this Cloudsystem is still in Development Requ

RauchigesEtwas 2 Dec 19, 2022
Dynamic detection of likely invariants

This is the distribution of the Daikon invariant detector, Daikon version 5.8.11, released November 2, 2021. If you are working with a Daikon distrib

null 159 Dec 28, 2022
A light-weight and dynamic dependency injection framework

⚠️ This project is now part of the EE4J initiative. This repository has been archived as all activities are now happening in the corresponding Eclipse

Java EE 105 Dec 23, 2022
Dynamic Reports using Jasper Reports

DynamicJasper DynamicJasper (DJ) is an API that hides the complexity of JasperReports, it helps developers to save time when designing simple/medium c

intive-FDV 218 Dec 28, 2022
A Fully Code Integrated Dynamic DataBase Management System for the Java Platform

dynamic-database A fully code integrated minimal database management system for Java, Scala, Kotlin or Groovy projects. It is written in Java and can

omega ui 2 Jun 8, 2022
The KubeJS data dumper and dynamic typing generator.

ProbeJS A data dumper and typing generator for the KubeJS functions, constants and classes. Great thanks to @DAmNRelentless, @LatvianModder and @yeste

Li Junyu 22 Dec 8, 2022
基于SpringCloud2.1的微服务开发脚手架,整合了spring-security-oauth2、nacos、feign、sentinel、springcloud-gateway等。服务治理方面引入elasticsearch、skywalking、springboot-admin、zipkin等,让项目开发快速进入业务开发,而不需过多时间花费在架构搭建上。持续更新中

快速开始 先决条件 首先本机先要安装以下环境,建议先学习了解springboot和springcloud基础知识。 git java8 maven 开发环境搭建 linux和mac下可在项目根目录下执行 ./install.sh 快速搭建开发环境。如要了解具体的步骤,请看如下文档。 具体步骤如下:

zhoutaoo 7.9k Jan 6, 2023
springboot 框架与其它组件结合如 jpa、mybatis、websocket、security、shiro、cache等

致歉 由于自己懒以及身体对issuse 解决的不及时。请大家以后提issuse 的时候写清楚 模块名 比如“springboot-SpringSecurity4” 和问题,我会抽时间抓紧解决。 springboot-SpringSecurity0 包含两部分代码: 第一是 博客 springboot

abel 5.9k Jan 5, 2023
SpringBoot 基础教程 | 从入门到上瘾 | 基于2.0.0.M5制作

推荐阅读本教程的三大理由: 文章内容均为原创,结合官方文档和实战经验编写。 文章结构经过细致整理,对新人学习更加友好。 精选常用技术,不求全面,但求精华!! SpringBoot 源码精读 图文教程 源码下载:《SpringBoot 基础教程-Git 》 — Hey Man,Don't forget

一只袜子 2.5k Dec 29, 2022
springboot SSO 单点登录,OAuth2实现,支持App登录,支持分布式

smart-sso QQ交流群:454343484 ?? 、769134727 简述 smart-sso使用当下最流行的SpringBoot技术,基于OAuth2认证授权协议,为您构建一个易理解、高可用、高扩展性的分布式单点登录应用基层。 相关文档 smart-sso单点登录(一):简介 smart

Joe 1.9k Dec 31, 2022
一个能够获取随机图片的 Api,使用 SpringBoot 构建

Random-Image-Api Random-Image-Api 一个能够获取随机图片的 Api,基于 Spring Boot 构建 可读取本地图片列表的地址,并提供随机访问服务,可配置域名白名单访问 项目说明 程序启动的时候会自动加载 项目路径/list 文件夹下的所有列表文件; 图片列表文件:

陈亚伟 1.3k Dec 21, 2022
SpringBoot 脚手架,简化项目构建

EasyRiggerInitializr | SpringBoot 脚手架,简化项目构建 作者: 小傅哥,Java Developer, ✏️ 虫洞 · 科技栈,作者, ?? CSDN 博客专家 本代码库是作者小傅哥多年从事一线互联网Java开发的学习历程技术汇总,旨在为大家提供一个清晰详细的学习教

小傅哥 81 Nov 20, 2022