当前位置: 首页 > news >正文

上海网站制作培训wordpress 维修主题

上海网站制作培训,wordpress 维修主题,wordpress公众号抓取,衡水seo外包项目支持多数据库连接是个很常见的需求&#xff0c;这不仅是要在编译前连已经知道的多个数据库&#xff0c;有时还要在程序运行时连后期增加的多个数据源来获得数据。 一、编译前注册数据库连接 1.引入依赖包 <!-- springboot 3.x --><dependency><groupId&g…

项目支持多数据库连接是个很常见的需求,这不仅是要在编译前连已经知道的多个数据库,有时还要在程序运行时连后期增加的多个数据源来获得数据。

一、编译前注册数据库连接

1.引入依赖包

<!-- springboot 3.x --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-3-starter</artifactId>
</dependency>
<!-- springboot 2.x --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId>
</dependency>

2.配置文件

一般本地应用可能有多个数据源,比如,需要支持读写分离的主从数据库配置,可能的application-druid.yml配置文件代码如下:

# 数据源配置
spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.cj.jdbc.Driverdynamic:primary: MASTERdatasource:# 主库数据源MASTER:url: jdbc:mysql://127.0.0.1/ry?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8username: rootpassword: 123456# 从库数据源SLAVE:url: jdbc:mysql://127.0.0.1/ruoyi?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8username: rootpassword: 123456druid:# 初始连接数initialSize: 5# 最小连接池数量minIdle: 10# 最大连接池数量maxActive: 20# 配置获取连接等待超时的时间maxWait: 60000# 配置连接超时时间connectTimeout: 30000# 配置网络超时时间socketTimeout: 60000# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒timeBetweenEvictionRunsMillis: 60000# 配置一个连接在池中最小生存的时间,单位是毫秒minEvictableIdleTimeMillis: 300000# 配置一个连接在池中最大生存的时间,单位是毫秒maxEvictableIdleTimeMillis: 900000# 配置检测连接是否有效validationQuery: SELECT 1 FROM DUALtestWhileIdle: truetestOnBorrow: falsetestOnReturn: falsewebStatFilter:enabled: truestatViewServlet:enabled: true# 设置白名单,不填则允许所有访问allow:url-pattern: /druid/*# 控制台管理用户名和密码login-username: ruoyilogin-password: 123456filter:stat:enabled: true# 慢SQL记录log-slow-sql: trueslow-sql-millis: 1000merge-sql: truewall:config:multi-statement-allow: true

3.配置DruidConfig

/*** druid 配置多数据源* */
@Configuration
public class DruidConfig
{/** 主数据库配置 */@Bean@ConfigurationProperties("spring.datasource.druid.master")public DataSource masterDataSource(DruidProperties druidProperties){DruidDataSource dataSource = DruidDataSourceBuilder.create().build();return druidProperties.dataSource(dataSource);}/** 从数据库配置 */@Bean@ConfigurationProperties("spring.datasource.druid.slave")@ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")public DataSource slaveDataSource(DruidProperties druidProperties){DruidDataSource dataSource = DruidDataSourceBuilder.create().build();return druidProperties.dataSource(dataSource);}/** 动态数据源 */@Bean(name = "dynamicDataSource")@Primarypublic DynamicDataSource dataSource(DataSource masterDataSource){Map<Object, Object> targetDataSources = new HashMap<>();// 加入主数据库配置targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);// 加入从数据库配置setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");return new DynamicDataSource(masterDataSource, targetDataSources);}/*** 设置数据源* * @param targetDataSources 备选数据源集合* @param sourceName 数据源名称* @param beanName bean名称*/public void setDataSource(Map<Object, Object> targetDataSources, String sourceName, String beanName){try{DataSource dataSource = SpringUtils.getBean(beanName);targetDataSources.put(sourceName, dataSource);}catch (Exception e){}}
}

4.配置DynamicDataSource

新建DynamicDataSource 类来继承AbstractRoutingDataSource 类。

继承自 Spring 提供的 AbstractRoutingDataSource,通过重写 determineCurrentLookupKey 方法,根据上下文信息动态选择当前使用的数据源。

/*** 动态数据源类,用于实现多数据源切换。*/
public class DynamicDataSource extends AbstractRoutingDataSource {/*** 构造函数,初始化默认数据源和目标数据源映射。** @param defaultTargetDataSource 默认数据源,在未指定其他数据源时使用* @param targetDataSourceMap 目标数据源映射,包含多个可选的数据源*/public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSourceMap) {// 设置默认数据源super.setDefaultTargetDataSource(defaultTargetDataSource);// 设置目标数据源映射super.setTargetDataSources(targetDataSourceMap);// 初始化父类属性super.afterPropertiesSet();}/*** 确定当前使用的数据源键。* 该方法会根据上下文中的数据源类型来决定使用哪个数据源。** @return 当前使用的数据源键*/@Overrideprotected Object determineCurrentLookupKey() {return DynamicDataSourceContextHolder.getDataSourceType();}}

5.配置DynamicDataSourceContextHolder

例如在web应用这种多线程的环境中,每个线程需要执行访问的数据库都不一样。因此需要给每个线程设置独立变量。

新建DynamicDataSourceContextHolder文件,代码如下:

/*** 数据源切换处理* */
public class DynamicDataSourceContextHolder
{public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);/*** 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,* 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。*/private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();/*** 设置数据源的变量*/public static void setDataSourceType(String dsType){log.info("切换到{}数据源", dsType);CONTEXT_HOLDER.set(dsType);}/*** 获得数据源的变量*/public static String getDataSourceType(){return CONTEXT_HOLDER.get();}/*** 清空数据源变量*/public static void clearDataSourceType(){CONTEXT_HOLDER.remove();}
}

6.配置AOP切面类

通过 AOP 拦截带有 @DataSource 注解的方法或类,在方法执行前设置数据源,在方法执行后清除数据源,确保每个请求都能正确使用指定的数据源。

代码如下:

/*** 多数据源处理切面类。*/
@Aspect
@Order(1)
@Component
public class DataSourceAspect {protected Logger logger = LoggerFactory.getLogger(getClass());/*** 定义切入点,匹配带有 @DataSource 注解的方法或类。*/@Pointcut("@annotation(com.ruoyi.common.annotation.DataSource)"+ "|| @within(com.ruoyi.common.annotation.DataSource)")public void dsPointCut() {}/*** 环绕通知,拦截 dsPointCut 切入点匹配的方法。* 在方法执行前设置数据源类型,在方法执行后清除数据源类型。** @param point 当前连接点对象* @return 方法返回值* @throws Throwable 如果方法执行过程中抛出异常*/@Around("dsPointCut()")public Object around(ProceedingJoinPoint point) throws Throwable {DataSource dataSource = getDataSource(point);if (StringUtils.isNotNull(dataSource)) {// 根据注解配置设置数据源类型if ("".equals(dataSource.name())) {DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());} else {DynamicDataSourceContextHolder.setDataSourceType(dataSource.name());}}try {// 执行目标方法return point.proceed();} finally {// 方法执行完毕后清除数据源类型DynamicDataSourceContextHolder.clearDataSourceType();}}/*** 获取当前方法或类上的 @DataSource 注解配置。** @param point 当前连接点对象* @return 数据源配置信息*/public DataSource getDataSource(ProceedingJoinPoint point) {MethodSignature signature = (MethodSignature) point.getSignature();// 从方法上查找 @DataSource 注解DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);if (Objects.nonNull(dataSource)) {return dataSource;}// 如果方法上没有找到,则从类上查找 @DataSource 注解return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class);}
}

7.使用方式

现在可以通过注解选择要使用哪个数据库。

在需要使用多数据源方法或类上添加@DataSource注解,其中value用来表示数据源。

@DataSource(value = DataSourceType.SLAVE)
public List<SysUser> selectUserList(SysUser user)
{return userMapper.selectUserList(user);
}
@Service
@DataSource(value = DataSourceType.SLAVE)
public class SysUserServiceImpl{}

或者手动切换数据源

public List<SysUser> selectUserList(SysUser user)
{DynamicDataSourceContextHolder.setDataSourceType(DataSourceType.SLAVE.name());List<SysUser> userList = userMapper.selectUserList(user);DynamicDataSourceContextHolder.clearDataSourceType();return userList;
}

在这里插入图片描述

二、运行时访问数据库

前面访问多数据源的方式必须提前在yaml这样的配置文件中提前填写好数据库的连接属性。

但是类似BI展示这样的软件项目可能得访问十几个业务的数据源,并且别的数据源的访问信息还时刻在变。这样的话,就不方便把数据库的连接属性提前写在配置文件中了。

1.配置数据管理工具


@Configuration
public class DataSourceManagement implements InitializingBean {protected final Logger logger = LoggerFactory.getLogger(DataSourceManagement.class);/*** 额外数据源*/private Map<String, DataSource> targetDataSources = new HashMap<>();/*** 配置文件的数据源*/@Autowiredprivate DynamicDataSourceProperties dataSourceProperties;@Autowiredprivate CreateDataSource c;@Autowired(required = false)private AfterCreateDataSource afterCreateDataSource;private DynamicDataSource dynamicDataSource;/*** 创建并返回动态数据源实例。** @return 动态数据源实例*/@Bean(name = "dynamicDataSource")@Primarypublic DynamicDataSource dataSource() {Map<Object, Object> targetDataSourceMap = new HashMap<>(targetDataSources);this.dynamicDataSource = new DynamicDataSource(targetDataSources.get(dataSourceProperties.getPrimary()), targetDataSourceMap);return this.dynamicDataSource;}/*** 验证数据源是否可用。** @param dataSource 要验证的数据源*/public void validateDataSource(DataSource dataSource) {try (Connection conn = dataSource.getConnection()) {String validationQuery = "SELECT 1";try (Statement stmt = conn.createStatement();ResultSet rs = stmt.executeQuery(validationQuery)) {if (!(rs.next() && rs.getInt(1) == 1)) {throw new RuntimeException("数据源连接验证失败:查询结果不正确");}}} catch (SQLException e) {throw new RuntimeException("数据源连接验证失败", e);}}/*** 在所有依赖项设置完成后执行此方法。* 初始化所有配置的数据源,并进行连接验证。*/@Overridepublic void afterPropertiesSet() throws Exception {dataSourceProperties.getDatasource().forEach((name, props) -> {Properties properties = dataSourceProperties.build(props);CommonDataSource commonDataSource = c.createDataSource(name, properties);if (afterCreateDataSource != null) {afterCreateDataSource.afterCreateDataSource(name, properties, commonDataSource);}DataSource dataSource = (DataSource) commonDataSource;logger.info("数据源:{} 校验中.......", name);// 计时long start = System.currentTimeMillis();validateDataSource(dataSource);logger.info("数据源:{} 链接成功,耗时:{}ms", name, System.currentTimeMillis() - start);this.putDataSource(name, dataSource);});}/*** 添加或更新一个数据源,并创建相应的SqlSessionFactory。** @param name       数据源名称* @param dataSource 数据源实例*/public void putDataSource(String name, DataSource dataSource) {targetDataSources.put(name, dataSource);}/*** 添加一个新的数据源。** @param name       数据源名称* @param properties 数据源属性*/public void addDataSourceWithCheck(String name, Properties properties) {if (targetDataSources.containsKey(name)) {logger.info("数据源" + name + "之前已经创建,准备测试数据源是否正常...");//throw new RuntimeException("数据源已存在");} else {CommonDataSource commonDataSource = c.createDataSource(name, properties);if (afterCreateDataSource != null) {afterCreateDataSource.afterCreateDataSource(name, properties, commonDataSource);}DataSource dataSource = (DataSource) commonDataSource;logger.info("数据源:{} 校验中.......", name);// 计时long start = System.currentTimeMillis();validateDataSource(dataSource);logger.info("数据源:{} 链接成功,耗时:{}ms", name, System.currentTimeMillis() - start);this.putDataSource(name, dataSource);HashMap<Object, Object> objectHashMap = new HashMap<>(this.targetDataSources);// 将map赋值给父类的TargetDataSourcesthis.dynamicDataSource.setTargetDataSources(objectHashMap);// 重要:将TargetDataSources中的连接信息放入resolvedDataSources管理,否则无法切换数据源this.dynamicDataSource.afterPropertiesSet();logger.debug("添加数据源成功,名称:{}", name);}}}

2.创建数据源

通过 DruidXADataSource 创建数据源,并使用 DruidConfig 和 DynamicDataSourceProperties 配置数据源属性。

/*** 数据源创建类,实现 CreateDataSource 接口。* */
@Component
public class DataSourceCreate implements CreateDataSource {@Autowiredprivate DynamicDataSourceProperties properties;@Autowiredprivate DruidConfig druidConfig;/*** 创建数据源的方法。** @param name 数据源名称* @param prop 数据源配置属性* @return 创建的数据源对象*/@Overridepublic DataSource createDataSource(String name, Properties prop) {// 创建 DruidXADataSource 实例DruidXADataSource dataSource = new DruidXADataSource();// 将创建的数据源添加到 DruidConfig 的数据源列表中druidConfig.getDruidDataSources().add(dataSource);// 设置数据源的连接属性dataSource.setConnectProperties(prop);// 使用 DynamicDataSourceProperties 配置数据源的其他属性properties.setProperties(dataSource, prop);// 返回创建的数据源对象return dataSource;}
}

3.准备实体

准备个存储数据库连接属性的实体,用于接收信息。

@Data
public class DataSource {private String id;private String connIp;private String connPort;private String connDbName;private String connUserName;private String connPassWord;private String connName;private String connType;private String connProperty;private String connDriverClass;
}

4.调用方式

写一个服务类,将从某个存储数据库连接信息的表里查出所有数据源。然后根据连接属性创建动态数据源。

@Service
public class DBChangeServiceImpl implements IDBChangeService {private final Logger logger = LoggerFactory.getLogger(DBChangeServiceImpl.class);@AutowiredDataSourceMapper dataSourceMapper;@Autowiredprivate DataSourceManagement dataSourceManagement;/*** 获取数据源* @return*/@Overridepublic List<DataSource> get() {return dataSourceMapper.get();}/*** 切换数据源* @param datasourceId* @return*/@Overridepublic boolean changeDb(String datasourceId) {//清除本线程的数据源DynamicDataSourceContextHolder.clearDataSourceType();logger.debug("清除本线程的数据源");//获取所有数据源List<DataSource> dataSourcesList = dataSourceMapper.get();logger.debug("获取到的数据源列表: {}", JSON.toJSONString(dataSourcesList));//遍历所有数据源,切换到指定数据源for (DataSource dataSource : dataSourcesList) {if (dataSource.getId().equals(datasourceId)) {logger.info(JSON.toJSONString(dataSource));logger.info("需要使用的的数据源已经找到,datasourceId是:" + dataSource.getId());Properties properties = buildDataSourceProperties(dataSource);//创建数据源连接&检查 若存在则不需重新创建try {// 使用DataSourceManagement来创建数据源并检查dataSourceManagement.addDataSourceWithCheck(dataSource.getId(), properties);// 切换数据源DynamicDataSourceContextHolder.setDataSourceType(dataSource.getId());logger.info("标记切换到数据源:"+datasourceId);return true;} catch (Exception e) {logger.error("数据源切换失败", e);e.printStackTrace();}}}logger.debug("未找到目标数据源");return false;}private Properties buildDataSourceProperties(DataSource dataSource) {Properties properties = new Properties();properties.setProperty("url", "jdbc:mysql://" + dataSource.getConnIp() + ":" + dataSource.getConnPort() + "/" + dataSource.getConnDbName());properties.setProperty("username", dataSource.getConnUserName());properties.setProperty("password", dataSource.getConnPassWord());properties.setProperty("driverClassName", dataSource.getConnDriverClass());// 添加其他必要的属性return properties;}}

切换数据源执行sql语句后,记得把数据源再切回去。

public AjaxResult runWithSql(String datasourceid, String sql){//切换到数据库dbChangeService.changeDb(datasourceid);System.out.println("Current DataSource Type: " + DynamicDataSourceContextHolder.getDataSourceType());System.out.println("RunWithSql: "+sql);List<Map<String, Object>> maps = execSqlService.runWithSql(sql);System.out.println("=======>"+JSON.toJSONString(maps));//切回主数据源DynamicDataSourceContextHolder.clearDataSourceType();return AjaxResult.success(maps);}

可以自行测试,发现连接成功了。
在这里插入图片描述

http://www.yayakq.cn/news/719989/

相关文章:

  • 阿里巴巴网站详情页怎么做站长统计app软件下载官网
  • 网站搬家怎么做做视频网站 版权怎么解决
  • asp.net个人网站空间wordpress5.0.2取消了链接
  • 三好街网站建设与维护亚马逊跨境电商新手入门
  • 校园网站建设需求建站软件免费版下载
  • 陈村九江网站建设深圳方维网站设计公司
  • 论坛网站建设公司站长工具使用方法
  • 网站开发需要的技术人员有什么太平阳电脑网网站模板
  • 快手做任务网站咸阳网站网站建设
  • 使用阿里云建网站好的外包公司
  • 自主建设网站的意义网址交易网站
  • 纯静态网站怎么入侵WordPress 云 memcache
  • 滑县网站建设价格个人网站备案类型
  • 网站开发的技术类型有哪些商务网站如何推广
  • 网站有冒号怎么打开正规品牌网站设计地址
  • 大连app网站建设天津网站设计网站制作
  • 网站建设 信科网络网站建设太金手指六六十八
  • 网站建设婚恋交友网站 微信维护怎么做
  • 专业微网站建设公司哪家好怎么用手机创建网页
  • 怎么对企业进行网站建设小企业来说 电子商务网站服务器的建设方案
  • 巢湖路桥建设集团有限公司网站创意网红墙图片
  • 网站可以更更换空间吗wordpress怎么在导航栏添加搜索框
  • 如何看访问网站的dns如何更改地图上的店名
  • 优质的做网站衡阳市建设学校官方网站
  • 为什么很多网站用php做百度推广哪家做的最好
  • ftp网站上传 方法网站开发文档模板
  • 旅游网站策划案网站建设公司大型
  • 青岛网站建设seo优化深圳seo技术
  • 济宁做公司网站视频 播放网站怎么做的
  • 整站优化方案wordpress目录迁移