springboot结合baomidou dynamic-datasource组件实现多数据源

发布时间 2023-08-25 14:22:35作者: buguge

当系统数据量过大,系统性能问题逐渐浮出水面。使用主从模式,不失是一个较好的选择。即业务在主库执行,不影响业务的查询考虑走从库。这时,程序需要动态多数据源配置。

?程序如何实现
1. pom引入多数据源组件依赖

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

2. properties配置

数据库配置项较多,为了便于维护和管理这些配置项,我的实践在apollo里新建名为spring-datasource的Namespace。

spring.datasource.url = jdbc:mysql://10.0.x.x:3306/mydb?characterEncoding=UTF-8&useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai&allowMultiQueries=true
spring.datasource.username = mydb
spring.datasource.password = mydbp@ssword
spring.datasource.hikari.maximum-pool-size = 17
spring.datasource.hikari.connection-timeout = 9000
spring.datasource.hikari.max-life-time = 1740000
spring.datasource.dynamic.enabled = true
spring.datasource.dynamic.primary = master
spring.datasource.dynamic.datasource.slave.type = com.zaxxer.hikari.HikariDataSource
spring.datasource.dynamic.datasource.slave.driver-class-name = com.mysql.jdbc.Driver
spring.datasource.dynamic.datasource.slave.hikari.max-pool-size = 5
spring.datasource.dynamic.datasource.slave.hikari.min-idle = 5
spring.datasource.dynamic.datasource.slave.url = jdbc:mysql://10.12.x.x:30020/mydb?characterEncoding=UTF-8&useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
spring.datasource.dynamic.datasource.slave.username = read
spring.datasource.dynamic.datasource.slave.password = readp@ssword
spring.datasource.dynamic.datasource.master.type = com.zaxxer.hikari.HikariDataSource
spring.datasource.dynamic.datasource.master.driver-class-name = com.mysql.jdbc.Driver
spring.datasource.dynamic.datasource.master.hikari.max-pool-size = 17
spring.datasource.dynamic.datasource.master.hikari.min-idle = 17
spring.datasource.dynamic.datasource.master.url = jdbc:mysql://10.0.x.x:3306/mydb?characterEncoding=UTF-8&useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai&allowMultiQueries=true
spring.datasource.dynamic.datasource.master.username = mydb
spring.datasource.dynamic.datasource.master.password = mydbp@ssword
spring.datasource.dynamic.hikari.connection-timeout = 9000
spring.datasource.dynamic.hikari.max-lifetime = 1740000
spring.datasource.dynamic.hikari.max-pool-size = 17
spring.datasource.dynamic.hikari.min-idle = 17

3. 在bean或方法上使用@DS指定数据源,不指定则使用默认数据源

//方式一:在bean上使用@DS
@Service
@DS("slave")
public class TidbUserSignManager extends ServiceImpl<UserSignMapper, UserSign> {
}

//方式二:在bean的方法上使用@DS

    @DS("slave")
    public int invoiceCount() {
        return testMapper.mysqlInvoiceCount();
    }

 

package com.baomidou.dynamic.datasource.annotation;

import java.lang.annotation.*;

/**
 * The core Annotation to switch datasource. It can be annotate at class or method.
 *
 * @author TaoYu Kanyuxia
 * @since 1.0.0
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DS {

    /**
     * groupName or specific database name or spring SPEL name.
     *
     * @return the database you want to switch
     */
    String value();
}

 

?几点说明

1. spring.datasource.dynamic.enabled可以决定是否开启多数据源模式
多数据源模式下,spring.datasource.dynamic.enabled默认为true。当然,我们也可以设置为false,来让程序任然走单数据源模式。此时,@DS注解会失效,直接走主库。

2. 需指定spring.datasource.dynamic.primary
需要指定默认住数据源。不指定primary启动会报错 Error creating bean with name 'dataSource': dynamic-datasource Please check the setting of primary

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.actuate.autoconfigure.jdbc.DataSourceHealthIndicatorAutoConfiguration': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [com/baomidou/dynamic/datasource/spring/boot/autoconfigure/DynamicDataSourceAutoConfiguration.class]: Invocation of init method failed; nested exception is java.lang.RuntimeException: dynamic-datasource Please check the setting of primary
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:769)
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1325)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1171)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
        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.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:392)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1305)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1144)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
        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.getBeansOfType(DefaultListableBeanFactory.java:602)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:590)
        at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1226)
        at org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorRegistryBeans.get(HealthIndicatorRegistryBeans.java:42)
        at org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration.healthIndicatorRegistry(HealthIndicatorAutoConfiguration.java:78)
        at org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration$$EnhancerBySpringCGLIB$$f7945325.CGLIB$healthIndicatorRegistry$0(<generated>)
        at org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration$$EnhancerBySpringCGLIB$$f7945325$$FastClassBySpringCGLIB$$7779fa6b.invoke(<generated>)
View Code

3. hikari配置,需要注意的是,单数据源与多数据源模式下的属性名是不一样的。这一点比较蛋疼。例如:maximum-pool-size与max-pool-size、max-life-time与max-lifetime