怎么在网站上做链接,wordpress 获取文章评论,微信公众号上漂亮的模板怎么弄,北京seo推广系统Druid连接池 Spring Boot 配置多数据源【最简单的方式】 文章目录 Druid连接池 Spring Boot 配置多数据源【最简单的方式】 0.前言1.基础介绍2.步骤2.1. 引入依赖2.2. 配置文件2.3. 核心源码Druid数据源创建器Druid配置项 DruidConfig 3.示例项目3.1. pom3.1.1. 依赖版本定义3.…Druid连接池 Spring Boot 配置多数据源【最简单的方式】 文章目录 Druid连接池 Spring Boot 配置多数据源【最简单的方式】 0.前言1.基础介绍2.步骤2.1. 引入依赖2.2. 配置文件2.3. 核心源码Druid数据源创建器Druid配置项 DruidConfig 3.示例项目3.1. pom3.1.1. 依赖版本定义3.1.2. 依赖版本管理3.1.3. pom依赖 3.2. 源代码3.2.1. DruidApplication3.2.2. UserService3.2.2. UserServiceImpl3.2.3. UserMapper3.2.3. User3.2.4. UserDto3.2.5. UserController3.2.6. 示例sql 4.参考文档 0.前言
看了网上好多关于Spring Boot 配置数据库 多数据源的文章其实不用那么多重复造轮子目前已经有了一个特别成熟的开源组件dynamic-datasource 已经支持各种各样的场景来满足你多数据源的需求我大概整理了一下希望对初学者有用。
1.基础介绍
本文我们使用 dynamic-datasource 多数据源组件实现在springboot 项目中快速集成多数据源。
支持 数据源分组 适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。支持数据库敏感配置信息 加密 ENC()。支持每个数据库独立初始化表结构schema和数据库database。支持无数据源启动支持懒加载数据源需要的时候再创建连接。支持 自定义注解 需继承DS(3.2.0)。提供并简化对DruidHikariCpBeeCpDbcp2的快速集成。提供对Mybatis-PlusQuartzShardingJdbcP6syJndi等组件的集成方案。提供 自定义数据源来源 方案如全从数据库加载。提供项目启动后 动态增加移除数据源 方案。提供Mybatis环境下的 纯读写分离 方案。提供使用 spel动态参数 解析数据源方案。内置spelsessionheader支持自定义。支持 多层数据源嵌套切换 。ServiceA ServiceB ServiceC。提供 **基于seata的分布式事务方案。提供 本地多数据源事务方案。
2.步骤
2.1. 引入依赖
1.引入依赖具体版本参考你当前的项目依赖管理中添加dependencyManagement中统一管理 dependencygroupIdcom.baomidou/groupIdartifactIddynamic-datasource-spring-boot-starter/artifactId/dependencydependencygroupIdcom.alibaba/groupIdartifactIddruid-spring-boot-starter/artifactId/dependencydependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactId/dependency排除原生Druid的快速配置类。 注意v3.3.3及以上版本不用排除了。 方法1. 利用注解排除 SpringBootApplication(exclude DruidDataSourceAutoConfigure.class)
SpringBootApplication(exclude DruidDataSourceAutoConfigure.class)
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}方法2. 利用配置排除 或者也可以使用这种方式在配置文件中排除
spring:autoconfigure:exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure2.2. 配置文件
增加配置如下下面为了方便期间使用h2数据库作为示例数据库mysql和其他数据库请按正确的jdbc url 配置
spring:datasource:druid:stat-view-servlet:enabled: truelogin-username: adminlogin-password: 123456dynamic:lazy: true# 配置全局druid参数请按需配置druid:initial-size: 5max-active: 8min-idle: 3max-wait: 1000validation-query: select 1datasource:master:username: sapassword: 123456url: jdbc:h2:mem:test;MODEMySQLdriver-class-name: org.h2.Driverdruid:socketTimeout: 1111slave_1:username: sapassword: 123456url: jdbc:h2:mem:test;MODEMySQLdriver-class-name: org.h2.Driverdruid:initial-size: 6slave_2:username: sapassword: 123456url: jdbc:h2:mem:test;MODEMySQLdriver-class-name: org.h2.Driverdruid 的原生配置在dynamic-datasource都是实现了的大家可以按需选择
spring:datasource:druid:stat-view-servlet:enabled: trueloginUsername: adminloginPassword: 123456dynamic:druid: #以下是支持的全局默认值initial-size:max-active:filters: stat # 注意这个值和druid原生不一致默认启动了stat。 如果确定什么filter都不需要 这里填 ...等等基本都支持wall:none-base-statement-allow:stat:merge-sql:log-slow-sql:slow-sql-millis: datasource:master:username: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://xx.xx.xx.xx:3306/dynamic?characterEncodingutf8useSSLfalsedruid: # 以下是独立参数每个库可以重新设置initial-size: 20validation-query: select 1 FROM DUAL #比如oracle就需要重新设置这个public-key: #非全局参数设置即表示启用加密,底层会自动帮你配置相关的连接参数和filter推荐使用本项目自带的加密方法。
# ......# 生成 publickey 和密码推荐使用本项目自带的加密方法。
# java -cp druid-1.1.10.jar com.alibaba.druid.filter.config.ConfigTools youpassword2.3. 核心源码
多数据源组件核心源码解释
Druid数据源创建器 package com.baomidou.dynamic.datasource.creator.druid;import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.filter.logging.CommonsLogFilter;
import com.alibaba.druid.filter.logging.Log4j2Filter;
import com.alibaba.druid.filter.logging.Log4jFilter;
import com.alibaba.druid.filter.logging.Slf4jLogFilter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;
import com.baomidou.dynamic.datasource.creator.DataSourceCreator;
import com.baomidou.dynamic.datasource.creator.DataSourceProperty;
import com.baomidou.dynamic.datasource.enums.DdConstants;
import com.baomidou.dynamic.datasource.exception.ErrorCreateDataSourceException;
import com.baomidou.dynamic.datasource.toolkit.DsStrUtils;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;import javax.sql.DataSource;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.*;/*** Druid数据源创建器* * 该类是一个实现了DataSourceCreator接口的类提供了创建Druid数据源的方法。* * since 2020/1/21*/
Slf4j
NoArgsConstructor
AllArgsConstructor
public class DruidDataSourceCreator implements DataSourceCreator {// 配置参数列表private static final SetString PARAMS new HashSet();// 从配置文件中复制配置信息的方法private static Method configMethod null;static {fetchMethod();}static {// 设置Druid支持的连接参数PARAMS.add(defaultCatalog);PARAMS.add(defaultAutoCommit);PARAMS.add(defaultReadOnly);PARAMS.add(defaultTransactionIsolation);PARAMS.add(testOnReturn);PARAMS.add(validationQueryTimeout);PARAMS.add(sharePreparedStatements);PARAMS.add(connectionErrorRetryAttempts);PARAMS.add(breakAfterAcquireFailure);PARAMS.add(removeAbandonedTimeoutMillis);PARAMS.add(removeAbandoned);PARAMS.add(logAbandoned);PARAMS.add(queryTimeout);PARAMS.add(transactionQueryTimeout);PARAMS.add(timeBetweenConnectErrorMillis);PARAMS.add(connectTimeout);PARAMS.add(socketTimeout);}// Autowired(required false)// private ApplicationContext applicationContext;// Druid配置对象private DruidConfig gConfig;/*** Druid since 1.2.17 use configFromPropeties to copy config* Druid 1.2.17 use configFromPropety to copy config* 根据Druid的版本选择从配置文件中复制配置信息的方法*/private static void fetchMethod() {ClassDruidDataSource aClass DruidDataSource.class;try {configMethod aClass.getMethod(configFromPropeties, Properties.class);return;} catch (NoSuchMethodException ignored) {}try {configMethod aClass.getMethod(configFromPropety, Properties.class);return;} catch (NoSuchMethodException ignored) {}throw new RuntimeException(Druid does not has configFromPropeties or configFromPropety method!);}/*** 创建Druid数据源。* * param dataSourceProperty 数据源配置信息* return 创建的Druid数据源对象*/Overridepublic DataSource createDataSource(DataSourceProperty dataSourceProperty) {DruidDataSource dataSource new DruidDataSource();dataSource.setUsername(dataSourceProperty.getUsername());dataSource.setPassword(dataSourceProperty.getPassword());dataSource.setUrl(dataSourceProperty.getUrl());dataSource.setName(dataSourceProperty.getPoolName());String driverClassName dataSourceProperty.getDriverClassName();if (DsStrUtils.hasText(driverClassName)) {dataSource.setDriverClassName(driverClassName);}DruidConfig config dataSourceProperty.getDruid();Properties properties DruidConfigUtil.mergeConfig(gConfig, config);// 初始化Druid过滤器ListFilter proxyFilters this.initFilters(dataSourceProperty, properties.getProperty(druid.filters));dataSource.setProxyFilters(proxyFilters);try {configMethod.invoke(dataSource, properties);} catch (Exception ignore) {}// 设置连接参数dataSource.setConnectProperties(config.getConnectionProperties());// 设置Druid内置properties不支持的参数for (String param : PARAMS) {DruidConfigUtil.setValue(dataSource, param, gConfig, config);}if (Boolean.FALSE.equals(dataSourceProperty.getLazy())) {try {dataSource.init();} catch (SQLException e) {throw new ErrorCreateDataSourceException(druid create error, e);}}返回创建的Druid数据源对象。return dataSource;}/*** 初始化Druid过滤器。* * param dataSourceProperty 数据源配置信息* param filters 过滤器列表* return 初始化后的过滤器列表*/private ListFilter initFilters(DataSourceProperty dataSourceProperty, String filters) {ListFilter proxyFilters new ArrayList(2);if (DsStrUtils.hasText(filters)) {String[] filterItems filters.split(,);for (String filter : filterItems) {switch (filter) {case stat:// 初始化Druid Stat过滤器proxyFilters.add(DruidStatConfigUtil.toStatFilter(dataSourceProperty.getDruid().getStat(), gConfig.getStat()));break;case wall:// 初始化Druid Wall过滤器WallConfig wallConfig DruidWallConfigUtil.toWallConfig(dataSourceProperty.getDruid().getWall(), gConfig.getWall());WallFilter wallFilter new WallFilter();wallFilter.setConfig(wallConfig);proxyFilters.add(wallFilter);break;case slf4j:// 初始化Druid Slf4j Log过滤器proxyFilters.add(DruidLogConfigUtil.initFilter(Slf4jLogFilter.class, dataSourceProperty.getDruid().getSlf4j(), gConfig.getSlf4j()));break;case commons-log:// 初始化Druid Commons Log过滤器proxyFilters.add(DruidLogConfigUtil.initFilter(CommonsLogFilter.class, dataSourceProperty.getDruid().getCommonsLog(), gConfig.getCommonsLog()));break;case log4j:// 初始化Druid Log4j过滤器proxyFilters.add(DruidLogConfigUtil.initFilter(Log4jFilter.class, dataSourceProperty.getDruid().getLog4j(), gConfig.getLog4j()));break;case log4j2:// 初始化Druid Log4j2过滤器proxyFilters.add(DruidLogConfigUtil.initFilter(Log4j2Filter.class, dataSourceProperty.getDruid().getLog4j2(), gConfig.getLog4j2()));break;default:log.warn(dynamic-datasource current not support [{}], filter);}}}// TODO: 从Spring容器中获取过滤器
// if (this.applicationContext ! null) {
// for (String filterId : gConfig.getProxyFilters()) {
// proxyFilters.add(this.applicationContext.getBean(filterId, Filter.class));
// }
// }return proxyFilters;}/*** 判断是否支持创建该类型的数据源。* * param dataSourceProperty 数据源配置信息* return 如果支持创建该类型的数据源则返回true否则返回false*/Overridepublic boolean support(DataSourceProperty dataSourceProperty) {Class? extends DataSource type dataSourceProperty.getType();return type null || DdConstants.DRUID_DATASOURCE.equals(type.getName());}
}Druid配置项 DruidConfig
dynamic-datasource 多数据源组件将Druid 的配置项进行了支持目前支持以下这些
package com.baomidou.dynamic.datasource.creator.druid;import lombok.Getter;
import lombok.Setter;import java.util.*;/*** Druid参数配置** author TaoYu* since 1.2.0*/
Getter
Setter
public class DruidConfig {private Integer initialSize;private Integer maxActive;private Integer minIdle;private Integer maxWait;private Long timeBetweenEvictionRunsMillis;private Long timeBetweenLogStatsMillis;private Long keepAliveBetweenTimeMillis;private Integer statSqlMaxSize;private Long minEvictableIdleTimeMillis;private Long maxEvictableIdleTimeMillis;private String defaultCatalog;private Boolean defaultAutoCommit;private Boolean defaultReadOnly;private Integer defaultTransactionIsolation;private Boolean testWhileIdle;private Boolean testOnBorrow;private Boolean testOnReturn;private String validationQuery;private Integer validationQueryTimeout;private Boolean useGlobalDataSourceStat;private Boolean asyncInit;private String filters;private Boolean clearFiltersEnable;private Boolean resetStatEnable;private Integer notFullTimeoutRetryCount;private Integer maxWaitThreadCount;private Boolean failFast;private Long phyTimeoutMillis;private Long phyMaxUseCount;private Boolean keepAlive;private Boolean poolPreparedStatements;private Boolean initVariants;private Boolean initGlobalVariants;private Boolean useUnfairLock;private Boolean killWhenSocketReadTimeout;private Properties connectionProperties;private Integer maxPoolPreparedStatementPerConnectionSize;private String initConnectionSqls;private Boolean sharePreparedStatements;private Integer connectionErrorRetryAttempts;private Boolean breakAfterAcquireFailure;private Boolean removeAbandoned;private Integer removeAbandonedTimeoutMillis;private Boolean logAbandoned;private Integer queryTimeout;private Integer transactionQueryTimeout;private String publicKey;private Integer connectTimeout;private Integer socketTimeout;private Long timeBetweenConnectErrorMillis;private MapString, Object wall new HashMap();private MapString, Object slf4j new HashMap();private MapString, Object log4j new HashMap();private MapString, Object log4j2 new HashMap();private MapString, Object commonsLog new HashMap();private MapString, Object stat new HashMap();private ListString proxyFilters new ArrayList();
}3.示例项目
3.1. pom
3.1.1. 依赖版本定义 propertiesproject.build.sourceEncodingUTF-8/project.build.sourceEncodingproject.reporting.outputEncodingUTF-8/project.reporting.outputEncodingjava.version1.8/java.versionds.version4.1.2/ds.versionmybatis-spring-boot-starter.version3.0.0/mybatis-spring-boot-starter.versiondruid.version1.2.18/druid.versionp6spy.version3.9.1/p6spy.versionh2.version2.2.220/h2.versionspring-boot-dependencies.version2.7.13/spring-boot-dependencies.version
/properties3.1.2. 依赖版本管理
dependencyManagementdependenciesdependencygroupIdcom.baomidou/groupIdartifactIddynamic-datasource-spring-boot-starter/artifactIdversion${ds.version}/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-dependencies/artifactIdversion${spring-boot-dependencies.version}/versiontypepom/typescopeimport/scope/dependencydependencygroupIdorg.springdoc/groupIdartifactIdspringdoc-openapi-ui/artifactIdversion1.7.0/version/dependencydependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactIdversion${mybatis-spring-boot-starter.version}/version/dependencydependencygroupIdcom.alibaba/groupIdartifactIddruid/artifactIdversion${druid.version}/version/dependencydependencygroupIdcom.alibaba/groupIdartifactIddruid-spring-boot-starter/artifactIdversion${druid.version}/version/dependencydependencygroupIdcom.h2database/groupIdartifactIdh2/artifactIdversion${h2.version}/version/dependency/dependencies/dependencyManagement
3.1.3. pom依赖 dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-validation/artifactId/dependencydependencygroupIdorg.springdoc/groupIdartifactIdspringdoc-openapi-ui/artifactId/dependencydependencygroupIdcom.baomidou/groupIdartifactIddynamic-datasource-spring-boot-starter/artifactId/dependencydependencygroupIdcom.alibaba/groupIdartifactIddruid-spring-boot-starter/artifactId/dependencydependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactId/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdscopeprovided/scope/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependencies3.2. 源代码
3.2.1. DruidApplication
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;Slf4j
SpringBootApplication
MapperScan(com.icepip.samples.druid.mapper)
public class DruidApplication {public static void main(String[] args) {SpringApplication.run(DruidApplication.class, args);log.info(open http://localhost:8080/swagger-ui.html \n http://localhost:8080/druid/index.html);}
}3.2.2. UserService
import com.icepip.samples.druid.entity.User;import java.util.List;public interface UserService {ListUser selectMasterUsers();ListUser selectSlaveUsers();void addUser(User user);void deleteUserById(Long id);
}3.2.2. UserServiceImpl
在切换数据源的时候使用注解 DS(slave)
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.samples.druid.entity.User;
import com.baomidou.samples.druid.mapper.UserMapper;
import com.baomidou.samples.druid.service.UserService;
import org.springframework.stereotype.Service;import java.util.List;Service
public class UserServiceImpl implements UserService {private final UserMapper userMapper;public UserServiceImpl(UserMapper userMapper) {this.userMapper userMapper;}Overridepublic ListUser selectMasterUsers() {return userMapper.selectUsers(1);}DS(slave)Overridepublic ListUser selectSlaveUsers() {return userMapper.selectUsers(1);}Overridepublic void addUser(User user) {userMapper.addUser(user.getName(), user.getAge());}Overridepublic void deleteUserById(Long id) {userMapper.deleteUserById(id);}
}3.2.3. UserMapper
import com.baomidou.icepip.druid.entity.User;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Component;import java.util.List;Component
public interface UserMapper {Select(select * from t_user where age #{age})ListUser selectUsers(Param(age) Integer age);SuppressWarnings(UnusedReturnValue)Insert(insert into t_user (name,age) values (#{name},#{age}))boolean addUser(Param(name) String name, Param(age) Integer age);Delete(delete from t_user where id #{id})void deleteUserById(Long id);
}3.2.3. User
import lombok.Data;Data
public class User {private Integer id;private String name;private Integer age;
}3.2.4. UserDto
import lombok.Data;Data
public class UserDto {private Integer id;private String name;private Integer age;
}3.2.5. UserController
import com.baomidou.icepip.druid.entity.User;
import com.baomidou.icepip.druid.service.UserService;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;import java.util.List;
import java.util.Random;RestController
AllArgsConstructor
RequestMapping(/users)
public class UserController {private static final Random RANDOM new Random();private final UserService userService;GetMapping(master)public ListUser masterUsers() {return userService.selectMasterUsers();}GetMapping(slave)public ListUser slaveUsers() {return userService.selectSlaveUsers();}PostMappingpublic User addUser() {User user new User();user.setName(测试用户 RANDOM.nextInt());user.setAge(RANDOM.nextInt(100));userService.addUser(user);return user;}DeleteMapping({id})public String deleteUser(PathVariable Long id) {userService.deleteUserById(id);return 成功删除用户 id;}
}3.2.6. 示例sql
CREATE TABLE IF NOT EXISTS t_user
(id BIGINT(20) NOT NULL AUTO_INCREMENT,name VARCHAR(30) NULL DEFAULT NULL,age INT(11) NULL DEFAULT NULL,PRIMARY KEY (id)
);4.参考文档
1.多数据源 https://baomidou.com/pages/a61e1b/#dynamic-datasource