SpringBoot+dynamic+MyBatisPlus 多数据源bug

项目场景:

项目场景:项目有连接不同数据库的需求,最后发现dynamic-datasource-spring-boot-starter比较热门且配置简单,就选用这个了。


开发环境

  1. JDK11
  2. SpringBoot 2.3.5.x
  3. 数据源:MySQL、clickhouse

dynamic-datasource介绍

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

dynamic-datasource特性

  • 支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。
  • 支持数据库敏感配置信息 加密 ENC()。
  • 支持每个数据库独立初始化表结构schema和数据库database。
  • 支持无数据源启动,支持懒加载数据源(需要的时候再创建连接)。
  • 支持 自定义注解 ,需继承DS(3.2.0+)。
  • 提供并简化对Druid,HikariCp,BeeCp,Dbcp2的快速集成。
  • 提供对Mybatis-Plus,Quartz,ShardingJdbc,P6sy,Jndi等组件的集成方案。
  • 提供 自定义数据源来源 方案(如全从数据库加载)。
  • 提供项目启动后 动态增加移除数据源 方案。
  • 提供Mybatis环境下的 纯读写分离 方案。
  • 提供使用 spel动态参数 解析数据源方案。内置spel,session,header,支持自定义。
  • 支持 多层数据源嵌套切换 。(ServiceA >>> ServiceB >>> ServiceC)。
  • 提供 基于seata的分布式事务方案。
  • 提供 本地多数据源事务方案。 附:不能和原生spring事务混用。

dynamic-datasource的相关约定

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

配置步骤

引入dynamic-datasource依赖

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

配置数据源

# MySQL数据源
spring.datasource.dynamic.datasource.master.url=jdbc:mysql://IP:端口/数据库?useSSL=false&useUnicode=true&serverTimezone=Asia/Shanghai
spring.datasource.dynamic.datasource.master.username=*
spring.datasource.dynamic.datasource.master.password=*
spring.datasource.dynamic.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.dynamic.datasource.master.type=com.alibaba.druid.pool.DruidDataSource
# 初始化时建立物理连接的个数
spring.datasource.mysql.initial-size=5
# 最大连接池数量
spring.datasource.mysql.max-active=20
# 最小连接池数量
spring.datasource.mysql.min-idle=5
# 获取连接时最大等待时间
spring.datasource.mysql.max-wait=60000
#mybatis路径配置
page.helper.helper-dialect=mysql
page.helper.reasonable=true
page.helper.support-methods-arguments=true
#mybatis映射文件路径
mybatis-plus.mapper-locations=classpath:mapper/*Mapper.xml,/**/*Mapper.xml
# 控制台输出日志
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

#多数据源配置
# 指定默认数据源
spring.datasource.dynamic.primary=master
# true:找不到数据源报错,false:找不到数据源则使用数据源
spring.datasource.dynamic.strict=false

#CK数据源
spring.datasource.dynamic.datasource.ck.driver-class-name=ru.yandex.clickhouse.ClickHouseDriver
spring.datasource.dynamic.datasource.ck.url=jdbc:clickhouse://IP:端口/数据库
spring.datasource.dynamic.datasource.ck.username=*
spring.datasource.dynamic.datasource.ck.password=*
spring.datasource.dynamic.datasource.ck.type=com.alibaba.druid.pool.DruidDataSource
#MyBatis-Plus日志打印
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

使用 @DS 切换数据源

@DS 可以注解在方法上或类上,同时存在就近原则 方法上注解 优先于 类上注解。 不使用@DS注解,即默认数据源,即 master

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

  @Autowired
  private JdbcTemplate jdbcTemplate;

  // 不使用@DS注解则代表使用默认数据源
  // 如果类上存在,则使用类上标注的数据源
  public List selectAll() {
    return  jdbcTemplate.queryForList("select * from user");
  }
  
  @Override
  @DS("ck")
  // 方法上注解 优先于 类上注解,即使类上标注也优先采用方法上的标注
  public List selectByCondition() {
    return  jdbcTemplate.queryForList("select * from user where age >10");
  }
}

到这就搞定了多数据源配置,MyBatisPlus配置看着github开源项目就可以了demo-orm-mybatis-plus


遇到的问题

Invalid bound statement (not found)

网上说的大概可以归类如下,但是解决不了我的问题
在这里插入图片描述


原因分析:

提示:后来通过控制台日志发现,启动项目的时候,ck的xml文件就没有打印出来,只有master数据库(即MySQL)的xml文件打印出来了,在想是不是文件没有注入。

IDEA的maven项目中,默认源代码目录下的xml等资源文件并不会在编译的时候一块打包进classes文件夹,而是直接舍弃掉。
在这里插入图片描述


解决方案:

提示:在maven中添加过滤,即pom.xml文件添加如下

<!--配置Maven 对resource文件 过滤 -->
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
好的,这是一个比较具体的技术问题。首先,Spring Boot可以通过配置多个数据源来实现多数据源的切换。其次,可以使用AOP技术,在方法执行前动态切换数据源。以下是一些关键的代码片段: 1. 在application.properties文件中配置多个数据源 ``` spring.datasource.primary.url=jdbc:mysql://localhost:3306/db1 spring.datasource.primary.username=user1 spring.datasource.primary.password=pass1 spring.datasource.secondary.url=jdbc:mysql://localhost:3306/db2 spring.datasource.secondary.username=user2 spring.datasource.secondary.password=pass2 ``` 2. 创建多个数据源的Bean ``` @Configuration public class DataSourceConfig { @Bean(name = "primaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.primary") public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "secondaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.secondary") public DataSource secondaryDataSource() { return DataSourceBuilder.create().build(); } } ``` 3. 创建动态数据源并设置默认数据源 ``` @Configuration public class DynamicDataSourceConfig { @Autowired @Qualifier("primaryDataSource") private DataSource primaryDataSource; @Autowired @Qualifier("secondaryDataSource") private DataSource secondaryDataSource; @Bean(name = "dynamicDataSource") public DataSource dynamicDataSource() { DynamicDataSource dynamicDataSource = new DynamicDataSource(); Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put(DataSourceType.PRIMARY.name(), primaryDataSource); targetDataSources.put(DataSourceType.SECONDARY.name(), secondaryDataSource); dynamicDataSource.setTargetDataSources(targetDataSources); dynamicDataSource.setDefaultTargetDataSource(primaryDataSource); return dynamicDataSource; } @Bean public JdbcTemplate jdbcTemplate() { return new JdbcTemplate(dynamicDataSource()); } } ``` 4. 创建AOP切面,在方法执行前根据注解切换数据源 ``` @Aspect @Component public class DataSourceAspect { @Autowired @Qualifier("dynamicDataSource") private DataSource dynamicDataSource; @Pointcut("@annotation(com.example.demo.datasource.DataSource)") public void dataSourcePointCut() {} @Before("dataSourcePointCut()") public void before(JoinPoint joinPoint) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); DataSource dataSource = signature.getMethod().getAnnotation(DataSource.class); if (dataSource != null) { DataSourceType dataSourceType = dataSource.value(); DynamicDataSourceContextHolder.setDataSourceType(dataSourceType.name()); } } @After("dataSourcePointCut()") public void after(JoinPoint joinPoint) { DynamicDataSourceContextHolder.clearDataSourceType(); } } ``` 5. 在需要切换数据源的方法上添加注解 ``` @DataSource(DataSourceType.SECONDARY) public List<User> listUsers() { return jdbcTemplate.query("SELECT * FROM user", new BeanPropertyRowMapper<>(User.class)); } ``` 这样就可以实现动态切换多数据源了。希望能够帮到你!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值