【微服务~原始真解】Spring Cloud —— 访问数据库整合Druid数据源

80 篇文章 0 订阅
79 篇文章 0 订阅

在这里插入图片描述

??这里是【秒懂·云原生】,关注我学习云原生不迷路
??如果对你有帮助,给博主一个免费的点赞以示鼓励
欢迎各位??点赞??评论收藏

??专栏介绍

【秒懂·云原生】 目前主要更新微服务,一起学习一起进步。

??本期介绍

主要介绍Spring Cloud —— 访问数据库整合Druid数据源

文章目录

Spring Boot JDBC访问数据库

对于数据访问层,无论是 SQL(关系型数据库) 还是 NOSQL(非关系型数据库),Spring Boot 都默认采用整合 Spring Data 的方式进行统一处理,通过大量自动配置,来简化我们对数据访问层的操作,我们只需要进行简单的设置即可实现对书层的访问。

引入JDBC启动器

<!--导入JDBC的启动器--> 
<dependency> 
<groupId>org.springframework.boot</groupId> 
<artifactId>spring-boot-starter-data-jdbc</artifactId> 
</dependency>

数据库驱动

<dependency> 
<groupId>mysql</groupId> 
<artifactId>mysql-connector-java</artifactId> 
<version>8.0.29</version> 
</dependency>

配置数据源

这里填自己数据库的信息

#数据源连接信息 
spring: 
  datasource: 
    username: root 
    password: root 
    url: jdbc:mysql://localhost:3306/db
    driver-class-name: com.mysql.cj.jdbc.Driver

测试

Spring Boot 提供了一个名为 JdbcTemplate 的轻量级数据访问工具,它是对 JDBC 的封装。Spring Boot 对 JdbcTemplate 提供了默认自动配置,我们可以直接使用 @Autowired 或构造函数将它注入到 bean 中使用。

Spring Boot整合Druid数据源

Druid 是阿里巴巴推出的一款开源的高性能数据源产品,Druid 支持所有JDBC 兼容的数据库,包括 Oracle、MySQL、SQL Server 和 H2 等等。Druid 不仅结合了 C3P0、DBCP 和 PROXOOL 等数据源产品的优点,同时还加入了强大的监控功能。通过 Druid 的监控功能,可以实时观察数据库连接池和 SQL 的运行情况,帮助用户及时排查出系统中存在的问题。使用 Druid Spring Boot Starter 将 Druid 与 Spring Boot 整合

引入 Druid Spring Boot Starter 依赖

<dependency>
 <groupId>com.alibaba</groupId>
  <artifactId>druid-spring-boot-starter</artifactId> 
  <version>1.2.9</version> 
  </dependency>

配置属性

#数据库连接信息配置 
spring: 
  datasource: 
    driver-class-name: com.mysql.jdbc.Driver 
    username: root 
    password: root 
    url: jdbc:mysql://localhost:3306/db 
    pools: 
      initial-size: 10 # 初始化时建立物理连接的个数。初始化发生 在显示调用init方法,或者第一次getConnection时 
      min-idle: 10 # 最小连接池数量 最小空闲数量 
      maxActive: 200 # 最大连接池数量 最大活跃连接数 
      maxWait: 60000 # 获取连接时最大等待时间,单位毫秒。配置了 maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置 
      timeBetweenEvictionRunsMillis: 60000 # 检查空闲连接的 频率.Destroy线程会检测连接的间隔时间,如果连接空闲时间大于等于 minEvictableIdleTimeMillis则关闭物理连接。 
      minEvictableIdleTimeMillis: 300000 # 连接的最小生存时 间.连接保持空闲而不被驱逐的最小时间 
      validationQuery: SELECT 1 # 验证数据库服务可用性的 sql.用来检测连接是否有效的sql 因数据库方言而差, 例如 oracle 应该写 成 SELECT 1 FROM DUAL 
      testWhileIdle: true # 申请连接时检测空闲时间,根据空闲时 间再检测连接是否有效.建议配置为true,不影响性能,并且保证安全性。申请 连接的时候检测,如果空闲时间大于timeBetweenEvictionRun 
      testOnBorrow: false # 申请连接时直接检测连接是否有效.申 请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性 能。testOnReturn: false # 归还连接时检测连接是否有效.归还连 接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 
      poolPreparedStatements: true # 开启PSCache 
      maxPoolPreparedStatementPerConnectionSize: 20 #设置 PSCache值
      connectionErrorRetryAttempts: 3 # 连接出错后再尝试连接 三次 
      breakAfterAcquireFailure: true # 数据库服务宕机自动重 连机制 
      timeBetweenConnectErrorMillis: 300000 # 连接出错后重 试时间间隔asyncInit: true # 异步初始化策略 
      remove-abandoned: true # 是否自动回收超时连接 
      remove-abandoned-timeout: 1800 # 超时时间(以秒数为单 位) 超过此值后,druid将强制回收该连接 
      transaction-query-timeout: 6000 # 事务超时时间 
      filters: stat,wall,log4j2 
      connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 
    stat-view-servlet: 
      enabled: true #是否开启内置监控页面,默认值 为 false 
      url-pattern: "/druid/*" #StatViewServlet 的映射 路径,即内置监控页面的访问地址 
      allow: 127.0.0.1 #白名单 
      deny: #黑名单 
      reset-enable: false #是否启用重置按钮 
      login-username: admin #内置监控页面的登录页用户名 username
      login-password: admin #内置监控页面的登录页密码 password
    web-stat-filter: enabled: true #是否开启内置监控中的 Web- jdbc 关联监控的数据 
      url-pattern: "/*" #匹配路径 
      exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*" #排除 路径 
      session-stat-enable: true #是否监控session

配置类

DruidDataSourceConfig.java

package com.example.demo;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.sql.SQLException;

/**
 * @author yeqv
 * @program demo
 * @Classname DruidDataConfig
 * @Date 2022/4/29 16:35
 * @Email w16638771062@163.com
 */
@Configuration
@ConfigurationProperties(prefix = "spring.datasource")
@Data
public class DruidDataSourceConfig {
    @Autowired
    DruidStatProperties druidStatProperties;
    @Autowired
    StatFilter statFilter;
    private String url;
    private String username;
    private String password;
    private String driverClasName;

    @Bean
    public DataSource dataSource(DruidPools druidPools) throws SQLException {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(getUrl());
        dataSource.setUsername(getUsername());
        dataSource.setPassword(getPassword());
        dataSource.setDriverClassName(getDriverClasName());
        dataSource.setInitialSize(druidPools.getInitialSize());
        dataSource.setMinIdle(druidPools.getMinIdle());
        dataSource.setMaxActive(druidPools.getMaxActive());
        dataSource.setMaxWait(druidPools.getMaxWait());
        dataSource.setTimeBetweenEvictionRunsMillis(druidPools.getTimeBetweenEvictionRunsMillis());
        dataSource.setMinEvictableIdleTimeMillis(druidPools.getMinEvictableIdleTimeMillis());
        dataSource.setValidationQuery(druidPools.getValidationQuery());
        dataSource.setTestWhileIdle(druidPools.testWhileIdle);
        dataSource.setTestOnBorrow(druidPools.testOnBorrow);
        dataSource.setTestOnReturn(druidPools.testOnReturn);
        dataSource.setPoolPreparedStatements(druidPools.poolPreparedStatements);
        dataSource.setMaxPoolPreparedStatementPerConnectionSize(druidPools.maxPoolPreparedStatementPerConnectionSize);
        dataSource.setConnectionErrorRetryAttempts(druidPools.connectionErrorRetryAttempts);
        dataSource.setBreakAfterAcquireFailure(druidPools.breakAfterAcquireFailure);
        dataSource.setTimeBetweenConnectErrorMillis(druidPools.timeBetweenConnectErrorMillis);
        dataSource.setAsyncInit(druidPools.asyncInit);
        dataSource.setRemoveAbandoned(druidPools.removeAbandoned);
        dataSource.setRemoveAbandoned(druidPools.removeAbandoned);
        dataSource.setTransactionQueryTimeout(druidPools.transactionQueryTimeout);
        dataSource.setFilters(druidPools.filters);
        dataSource.setConnectProperties(druidPools.connectionProperties);
        return dataSource;
    }

    @Bean
    public ServletRegistrationBean druidServlet(StatConfig statConfig) {
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(); // 现在要进行druid监控的配置处理操作
        servletRegistrationBean.setServlet(new StatViewServlet());
        servletRegistrationBean.addUrlMappings(druidStatProperties.getStatViewServlet().getUrlPattern());
        servletRegistrationBean.addInitParameter("allow", statConfig.getAllow()); // 白名单
        servletRegistrationBean.addInitParameter("deny", statConfig.getDeny()); // 黑名单
        servletRegistrationBean.addInitParameter("loginUsername", statConfig.getLoginUsername()); // 用户名
        servletRegistrationBean.addInitParameter("loginPassword", statConfig.getLoginPassword()); // 密码
        servletRegistrationBean.addInitParameter("resetEnable", statConfig.getResetEnable()); // 是否可以重置数据源
        return servletRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean filterRegistrationBean(StatFilter statFilter) {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new WebStatFilter());
        filterRegistrationBean.addUrlPatterns(statFilter.urlPattern); // 所有请求进行监控处理
        filterRegistrationBean.addInitParameter("exclusions", statFilter.exclusions);
        filterRegistrationBean.setEnabled(statFilter.enabled);
        return filterRegistrationBean;
    }
}

StatFilter.java

package com.example.demo;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

/**
 * @author yeqv
 * @program demo
 * @Classname StatFilter
 * @Date 2022/4/29 16:51
 * @Email w16638771062@163.com
 */
@Configuration
@ConfigurationProperties(prefix = "spring.datasource.web-stat-filter")
@Data
public class StatFilter {
    boolean enabled;
    String urlPattern;
    String exclusions;
}

StatConfig.java

package com.example.demo;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

/**
 * @author yeqv
 * @program demo
 * @Classname StatConfig
 * @Date 2022/4/29 16:48
 * @Email w16638771062@163.com
 */
@Configuration
@ConfigurationProperties(prefix = "spring.datasource.stat-view-servlet")
@Data
public class StatConfig {
    String urlPattern;
    String allow;
    String deny;
    String resetEnable;
    String loginUsername;
    String loginPassword;

}

DruidPools.java

package com.example.demo;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import java.util.Properties;

/**
 * @author yeqv
 * @program demo
 * @Classname DruidPools
 * @Date 2022/4/29 16:45
 * @Email w16638771062@163.com
 */
@Configuration
@ConfigurationProperties(prefix = "spring.datasource.pools")
@Data
public class DruidPools {
    int initialSize;
    int minIdle;
    int maxActive;
    int maxWait;
    long timeBetweenEvictionRunsMillis;
    long minEvictableIdleTimeMillis;
    String validationQuery;
    boolean testWhileIdle;
    boolean testOnBorrow;
    boolean testOnReturn;
    boolean poolPreparedStatements;
    int maxPoolPreparedStatementPerConnectionSize;
    int connectionErrorRetryAttempts;
    boolean breakAfterAcquireFailure;
    long timeBetweenConnectErrorMillis;
    boolean asyncInit;
    boolean removeAbandoned;
    long removeAbandonedTimeout;
    int transactionQueryTimeout;
    String filters;
    Properties connectionProperties;

}

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Cloud可以通过使用动态数据源实现数据库读写分离,具体步骤如下: 1. 引入相关依赖 在Spring Boot项目的pom.xml文件中引入以下依赖: ``` <!-- MyBatis --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.0.0</version> </dependency> <!-- Druid 数据库连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.21</version> </dependency> <!-- HikariCP 数据库连接池 --> <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <version>3.4.5</version> </dependency> <!-- Spring Data JPA --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> ``` 2. 配置数据源 在application.properties或application.yml文件中配置数据源,例如: ``` # 主数据源 spring.datasource.master.jdbc-url=jdbc:mysql://localhost:3306/masterdb?useUnicode=true&characterEncoding=utf-8 spring.datasource.master.username=root spring.datasource.master.password=123456 spring.datasource.master.driver-class-name=com.mysql.jdbc.Driver # 从数据源 spring.datasource.slave.jdbc-url=jdbc:mysql://localhost:3306/slavedb?useUnicode=true&characterEncoding=utf-8 spring.datasource.slave.username=root spring.datasource.slave.password=123456 spring.datasource.slave.driver-class-name=com.mysql.jdbc.Driver ``` 3. 配置动态数据源 创建动态数据源配置类,例如: ``` @Configuration public class DynamicDataSourceConfig { @Bean @ConfigurationProperties("spring.datasource.master") public DataSource masterDataSource() { return DataSourceBuilder.create().build(); } @Bean @ConfigurationProperties("spring.datasource.slave") public DataSource slaveDataSource() { return DataSourceBuilder.create().build(); } @Bean public DynamicDataSource dynamicDataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("slaveDataSource") DataSource slaveDataSource) { Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put(DataSourceType.MASTER, masterDataSource); targetDataSources.put(DataSourceType.SLAVE, slaveDataSource); return new DynamicDataSource(masterDataSource, targetDataSources); } } ``` 其中,masterDataSource()和slaveDataSource()方法分别返回主数据源和从数据源,而dynamicDataSource()方法则创建一个动态数据源,该数据源包含主数据源和从数据源,且可以根据具体的业务需求动态切换数据源。 4. 创建数据源切换类 创建数据源切换类,例如: ``` public class DataSourceContextHolder { private static final ThreadLocal<DataSourceType> contextHolder = new ThreadLocal<>(); public static void setDataSourceType(DataSourceType dataSourceType) { contextHolder.set(dataSourceType); } public static DataSourceType getDataSourceType() { return contextHolder.get(); } public static void clearDataSourceType() { contextHolder.remove(); } } ``` 该类使用ThreadLocal存储数据源类型,setDataSourceType()方法设置当前线程使用数据源类型,getDataSourceType()方法获取当前线程使用数据源类型,clearDataSourceType()方法清空当前线程使用数据源类型。 5. 创建数据源切面类 创建数据源切面类,例如: ``` @Aspect @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 dataSource = method.getAnnotation(DataSource.class); if (dataSource == null) { DataSourceContextHolder.setDataSourceType(DataSourceType.MASTER); } else { DataSourceContextHolder.setDataSourceType(dataSource.value()); } try { return point.proceed(); } finally { DataSourceContextHolder.clearDataSourceType(); } } } ``` 该类使用@Aspect注解声明为切面类,使用@Pointcut注解定义切点,使用@Around注解定义环绕通知,在方法执行前根据注解中指定的数据源类型切换数据源,在方法执行后清空数据源类型。 6. 根据具体业务需求使用动态数据源 在需要使用动态数据源的地方,使用@DataSource注解指定数据源类型,例如: ``` @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override @DataSource(DataSourceType.MASTER) public int addUser(User user) { return userMapper.addUser(user); } @Override @DataSource(DataSourceType.SLAVE) public User getUserById(int id) { return userMapper.getUserById(id); } } ``` 以上就是使用Spring Cloud实现数据库读写分离的步骤。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值