赞
踩
Spring Boot是一个快速开发Spring应用程序的框架,而Druid是一个高性能的数据库连接池,可以提高数据库访问的效率。在Spring Boot中使用Druid作为数据库连接池,可以更好地管理和优化数据库连接,提高应用程序的性能。
同时,为了更好地支持多数据源,我们可以结合AOP实现自动切换数据源。本篇博客将介绍如何在Spring Boot中使用Druid实现数据库连接池,并通过AOP实现多数据源的自动切换。

在使用Druid之前,我们需要在Spring Boot中配置Druid。我们可以在pom.xml中添加Druid的依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</dependency>
然后在application.properties中添加以下配置:
# 数据源配置 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver spring.datasource.druid.master.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true spring.datasource.druid.master.username=root spring.datasource.druid.master.password=root spring.datasource.druid.slave.enabled=true spring.datasource.druid.slave.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true spring.datasource.druid.slave.username=root spring.datasource.druid.slave.password=root # Druid连接池监控配置 spring.datasource.druid.initialSize=5 spring.datasource.druid.minIdle=10 spring.datasource.druid.maxActive=20 spring.datasource.druid.maxWait=60000 spring.datasource.druid.timeBetweenEvictionRunsMillis=60000 spring.datasource.druid.minEvictableIdleTimeMillis=300000 spring.datasource.druid.maxEvictableIdleTimeMillis=900000 spring.datasource.druid.rewriteBatchedStatements=true spring.datasource.druid.validationQuery=SELECT 1 FROM DUAL spring.datasource.druid.testWhileIdle=true spring.datasource.druid.testOnBorrow=false spring.datasource.druid.testOnReturn=false spring.datasource.druid.webStatFilter.enabled=true spring.datasource.druid.statViewServlet.enabled=true spring.datasource.druid.statViewServlet.allow= spring.datasource.druid.statViewServlet.url-pattern=/druid/* spring.datasource.druid.statViewServlet.login-username=admin spring.datasource.druid.statViewServlet.login-password=123456 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.druid.filter.stat.merge-sql=true spring.datasource.druid.filter.wall.config.multi-statement-allow=true
或
spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver druid: # 主库数据源 master: url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true username: root password: root # 从库数据源 slave: # 从数据源开关/默认关闭 enabled: true url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true username: root password: root # 初始连接数 initialSize: 5 # 最小连接池数量 minIdle: 10 # 最大连接池数量 maxActive: 20 # 配置获取连接等待超时的时间 maxWait: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 timeBetweenEvictionRunsMillis: 60000 # 配置一个连接在池中最小生存的时间,单位是毫秒 minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最大生存的时间,单位是毫秒 maxEvictableIdleTimeMillis: 900000 rewriteBatchedStatements: true # 配置检测连接是否有效 validationQuery: SELECT 1 FROM DUAL testWhileIdle: true testOnBorrow: false testOnReturn: false webStatFilter: enabled: true statViewServlet: enabled: true # 设置白名单,不填则允许所有访问 allow: url-pattern: /druid/* # 控制台管理用户名和密码 login-username: ddz login-password: 123456 filter: stat: enabled: true # 慢SQL记录 log-slow-sql: true slow-sql-millis: 1000 merge-sql: true wall: config: multi-statement-allow: true
这里我们配置了一个MySQL数据库连接池,并设置了一些Druid的监控配置。其中,spring.datasource.druid.stat-view-servlet.enabled=true 表示开启Druid的监控功能,spring.datasource.druid.stat-view-servlet.url-pattern=/druid/* 表示Druid的监控地址为 /druid/*。
接下来,我们需要实现多数据源的切换。在Spring Boot中,我们可以通过AOP来实现数据源的自动切换。我们可以使用@Aspect注解来定义一个切面类,并使用@Around注解来定义切面方法。
首先,我们需要定义一个枚举类,用于存储数据源的名称:
public enum DataSourceType
{
/**
* 主库
*/
MASTER,
/**
* 从库
*/
SLAVE
}
然后,我们定义一个切面类DataSourceAspect,并在切面方法中根据注解参数来切换数据源:
@Aspect @Order(1) @Component public class DataSourceAspect { @Pointcut("@annotation(com.example.demo.annotation.DataSource)") public void dataSourcePointCut() { } @Around("dataSourcePointCut()") public Object around(ProceedingJoinPoint point) throws Throwable { // 从注解中获取需要切换的数据源 MethodSignature signature = (MethodSignature) point.getSignature(); Method method = signature.getMethod(); DataSource ds = method.getAnnotation(DataSource.class); if (ds == null) { // 默认主数据源 DynamicDataSource.setDataSource(DataSourceType.MASTER); } else { DynamicDataSource.setDataSource(ds.value()); } try { return point.proceed(); } finally { // 销毁数据源 在执行方法之后 DynamicDataSource.clearDataSource(); } } }
在切面方法中,我们首先获取切面方法的注解参数@DataSource,根据注解参数来切换数据源。如果注解参数为空,则默认使用主数据源。
然后,在try代码块中执行业务方法,并在finally代码块中清除数据源。
为了实现数据源的自动切换,我们还需要定义一个DynamicDataSource类,用于切换数据源。在DynamicDataSource类中,我们可以使用ThreadLocal来存储当前线程使用的数据源。
public class DynamicDataSource extends AbstractRoutingDataSource { /** * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本, * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。 */ private static final ThreadLocal<DataSourceType> contextHolder = new ThreadLocal<>(); /** * 设置数据源的变量 */ public static void setDataSource(DataSourceType dataSourceType) { contextHolder.set(dataSourceType); } /** * 清空数据源变量 */ public static void clearDataSource() { contextHolder.remove(); } /** * 确定当前查找关键字。这通常用于检查线程绑定的事务上下文。 * 允许使用任意键。返回的键需要与存储的查找键类型匹配,如resolveSpecifiedLookupKey方法所解析的。 */ @Override protected Object determineCurrentLookupKey() { return contextHolder.get(); } }
在DynamicDataSource类中,我们定义了一个ThreadLocal变量contextHolder,用于存储当前线程使用的数据源。在setDataSource()方法中,我们可以将当前线程使用的数据源存储到contextHolder变量中。在clearDataSource()方法中,我们可以清除contextHolder变量中存储的数据源。在determineCurrentLookupKey()方法中,我们可以根据contextHolder变量中存储的数据源来选择数据源。
最后,我们需要在业务方法中添加@DataSource注解,用于指定数据源。@DataSource注解是一个自定义注解,需要在程序中进行定义。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
DataSourceType value() default DataSourceType.MASTER;
}
在@DataSource注解中,我们可以在方法和类上指定使用哪个数据源。如果不指定数据源,则默认使用主数据源。
现在,我们已经完成了使用Druid实现数据库连接池和Druid结合AOP实现多数据源自动切换的实现。
先编写一个逻辑类来通过注解选择不同的数据源。
@Service
public interface UserService {
/**
* 新增用户到主库
*/
@DataSource(DataSourceType.MASTER)
int insertUserToMaster(User user);
/**
* 新增用户到从库
*/
@DataSource(DataSourceType.SLAVE)
int insertUserToSlave(User user);
}
下面,我们可以编写一个测试类来验证我们的代码是否正确。
@RunWith(SpringRunner.class)
@SpringBootTest
public class DataSourceTest {
@Autowired
private UserService userService;
@Test
public void testDataSource() {
userService.insertUserToMaster(new User("test1"));
userService.insertUserToSlave(new User("test2"));
}
}
在测试类中,我们注入了一个UserService实例,并调用了插入用户的方法。在插入用户时,我们指定了使用不同数据源,从而会往不同的数据源中新增数据。最后,我们可以使用断言来验证测试结果是否正确。
通过以上的步骤,我们已经成功地实现了使用Druid实现数据库连接池和Druid结合AOP实现多数据源自动切换。总结起来,我们需要完成以下步骤:
添加Druid依赖:在pom.xml文件中添加Druid的依赖。
配置Druid数据源:在application.properties文件中添加Druid数据源的配置信息。
定义切面类:定义一个切面类,用于在方法执行前切换数据源,并在方法执行后清除数据源。
定义自定义注解:定义一个自定义注解@DataSource,用于指定数据源。
编写业务代码:编写业务代码,并在业务方法上添加@DataSource注解,用于指定数据源。
编写测试代码:编写测试代码,并使用断言来验证测试结果是否正确。
使用Druid实现数据库连接池和Druid结合AOP实现多数据源自动切换,可以有效地解决在多数据源情况下的数据库连接池和数据源切换问题,同时也可以提高系统的稳定性和性能。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。