springboot结合baomidou dynamic-datasource组件实现多数据源
当系统数据量过大,系统性能问题逐渐浮出水面。使用主从模式,不失是一个较好的选择。即业务在主库执行,不影响业务的查询考虑走从库。这时,程序需要动态多数据源配置。
🍀程序如何实现
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(); }
🍀服务启动日志如下,可以看到各数据源的start日志。
[main] INFO org.springframework.web.context.ContextLoader:296 - Root WebApplicationContext: initialization completed in 79822 ms
2023-08-15 22:01:02.531 [main] INFO com.alibaba.arthas.spring.ArthasConfiguration:70 - Arthas agent start success.
Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
2023-08-15 22:01:10.904 [main] INFO com.zaxxer.hikari.HikariDataSource:80 - master - Starting...
2023-08-15 22:01:10.908 [main] WARN com.zaxxer.hikari.util.DriverDataSource:68 - Registered driver with driverClassName=com.mysql.jdbc.Driver was not found, trying direct instantiation.
2023-08-15 22:01:12.929 [main] INFO com.zaxxer.hikari.HikariDataSource:82 - master - Start completed.
2023-08-15 22:01:12.938 [main] INFO com.zaxxer.hikari.HikariDataSource:80 - slave - Starting...
2023-08-15 22:01:12.940 [main] WARN com.zaxxer.hikari.util.DriverDataSource:68 - Registered driver with driverClassName=com.mysql.jdbc.Driver was not found, trying direct instantiation.
2023-08-15 22:01:12.965 [main] INFO com.zaxxer.hikari.HikariDataSource:82 - slave - Start completed.
2023-08-15 22:01:12.967 [main] INFO c.b.dynamic.datasource.DynamicRoutingDataSource:132 - dynamic-datasource - load a datasource named [slave] success
2023-08-15 22:01:12.968 [main] INFO c.b.dynamic.datasource.DynamicRoutingDataSource:132 - dynamic-datasource - load a datasource named [master] success
2023-08-15 22:01:12.974 [main] INFO c.b.dynamic.datasource.DynamicRoutingDataSource:237 - dynamic-datasource initial loaded [2] datasource,primary datasource named [master]
2023-08-15 22:01:13.242 [main] INFO i.s.s.a.datasource.SeataAutoDataSourceProxyCreator:45 - Auto proxy of [dataSource]
🍀几点说明
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>)
3. hikari配置,需要注意的是,单数据源与多数据源模式下的属性名是不一样的。这一点比较蛋疼。例如:maximum-pool-size与max-pool-size、max-life-time与max-lifetime
当看到一些不好的代码时,会发现我还算优秀;当看到优秀的代码时,也才意识到持续学习的重要!--buguge
本文来自博客园,转载请注明原文链接:https://www.cnblogs.com/buguge/p/17656803.html