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

基于注解切换、Hikari实现的SpringBoot动态数据源(支持JNDI)

实现效果

先说效果,要实现方法级别注解切换当前数据源,不设置注解时走默认数据源,同时支持JNDI源。

总体思路

Spring框架中存在一个抽象类AbstractRoutingDataSource,他是一个可以动态选择当前DataSource的路由类,我们就是要从这里入手,重新实现数据源的切换选择逻辑。然后借助注解和切面,将当前需要的数据源名称放在ThreadLocal中,需要时从当前线程取得即可完成数据源的切换。
注解部分比较简单不再详说,看AbstractRoutingDataSource。该类文档写的非常全面,自行翻译一下就可以看懂。主要看其中的几个关键方法。

setTargetDataSources

类中存在一个成员变量targetDataSources,结合之后的setTargetDataSources方法可知,这里用来保存目标数据源。
根据注释我们可以知道,targetDataSources的key可以是数据源的名字,value是相应数据源的实例。
当然这里也可是使用其他的保存方式,然后自行改写用来查找数据源的determineCurrentLookupKey方法,默认场景就足够我们使用了。所以我们要构建一个Map出来,其中key用来区分数据源的名字,value放入对应数据源的实例,有几个数据源就放几个进去。

	@Nullableprivate Map<Object, Object> targetDataSources;/*** Specify the map of target DataSources, with the lookup key as key.* The mapped value can either be a corresponding {@link javax.sql.DataSource}* instance or a data source name String (to be resolved via a* {@link #setDataSourceLookup DataSourceLookup}).* <p>The key can be of arbitrary type; this class implements the* generic lookup process only. The concrete key representation will* be handled by {@link #resolveSpecifiedLookupKey(Object)} and* {@link #determineCurrentLookupKey()}.*/public void setTargetDataSources(Map<Object, Object> targetDataSources) {this.targetDataSources = targetDataSources;}

setDefaultTargetDataSource

上面说了如何设置当前数据源,那如果在开发的时候每一个方法都要声明一下使用哪个源就太麻烦了,所以Spring提供了一个方法用来设置默认的数据源,没啥可说的,传入DataSource实例就好了。

	@Nullableprivate Object defaultTargetDataSource;/*** Specify the default target DataSource, if any.* <p>The mapped value can either be a corresponding {@link javax.sql.DataSource}* instance or a data source name String (to be resolved via a* {@link #setDataSourceLookup DataSourceLookup}).* <p>This DataSource will be used as target if none of the keyed* {@link #setTargetDataSources targetDataSources} match the* {@link #determineCurrentLookupKey()} current lookup key.*/public void setDefaultTargetDataSource(Object defaultTargetDataSource) {this.defaultTargetDataSource = defaultTargetDataSource;}

determineCurrentLookupKey

在设置好数据源之后,接下来这几个寻路方法则是能实现动态数据源切换的重点。afterPropertiesSet方法对我们以配置的数据源进行校验;如果我们在第一步配置数据源map的时候对key有特殊处理则要自己实现抽象方法resolveSpecifiedLookupKey,告诉Spring应该怎么解析这个key值;determineTargetDataSource则最终确定要使用哪一个数据源,其中有一个方法determineCurrentLookupKey需要关注,这个方法会返回当前要使用的数据源名字,但他是个抽象方法,所以我们需要给他重写一下,改为从当前线程获取数据源名称

	@Overridepublic void afterPropertiesSet() {if (this.targetDataSources == null) {throw new IllegalArgumentException("Property 'targetDataSources' is required");}this.resolvedDataSources = CollectionUtils.newHashMap(this.targetDataSources.size());this.targetDataSources.forEach((key, value) -> {Object lookupKey = resolveSpecifiedLookupKey(key);DataSource dataSource = resolveSpecifiedDataSource(value);this.resolvedDataSources.put(lookupKey, dataSource);});if (this.defaultTargetDataSource != null) {this.resolvedDefaultDataSource = resolveSpecifiedDataSource(this.defaultTargetDataSource);}}@Overridepublic Connection getConnection(String username, String password) throws SQLException {return determineTargetDataSource().getConnection(username, password);}/*** Retrieve the current target DataSource. Determines the* {@link #determineCurrentLookupKey() current lookup key}, performs* a lookup in the {@link #setTargetDataSources targetDataSources} map,* falls back to the specified* {@link #setDefaultTargetDataSource default target DataSource} if necessary.* @see #determineCurrentLookupKey()*/protected DataSource determineTargetDataSource() {Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");Object lookupKey = determineCurrentLookupKey();DataSource dataSource = this.resolvedDataSources.get(lookupKey);if (dataSource == null && (this.lenientFallback || lookupKey == null)) {dataSource = this.resolvedDefaultDataSource;}if (dataSource == null) {throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");}return dataSource;}/*** Determine the current lookup key. This will typically be* implemented to check a thread-bound transaction context.* <p>Allows for arbitrary keys. The returned key needs* to match the stored lookup key type, as resolved by the* {@link #resolveSpecifiedLookupKey} method.*/@Nullableprotected abstract Object determineCurrentLookupKey();

代码实现

思路理顺了,代码写起来就比较快,直接贴最后代码,部分地方保留了注释。

数据源切换注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 数据源切换注解,默认为primary*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface TargetDataSource {DataSourceEnum value() default DataSourceEnum.PRIMARY;
}

数据源切换切面

这里需要特别提醒一下,事务注解@Transactional默认处于切面代理的最后一个,所以我们需要保证数据源切换注解优先级要高于事务注解

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;/*** 数据源切换切面*/
@Aspect
@Component
@Order(1)
public class DynamicDataSourceAspect {private final static Logger log = LoggerFactory.getLogger(DynamicDataSourceAspect.class);@Before(value = "@annotation(targetDataSource)")public void beforePointCut(TargetDataSource targetDataSource) {log.debug("数据源切换为 " + targetDataSource.value().getDataSourceName());DynamicDataSourceContextHolder.setDataSource(targetDataSource.value().getDataSourceName());}@After(value = "@annotation(targetDataSource)")public void afterPointCut(TargetDataSource targetDataSource) {log.debug("数据源恢复为 " + DataSourceEnum.PRIMARY.getDataSourceName());DynamicDataSourceContextHolder.clearDataSource();}
}

数据源枚举类

/*** 数据源枚举类*/
public enum DataSourceEnum {PRIMARY("primary"), SECONDARY("secondary");private final String dataSourceName;public String getDataSourceName() {return dataSourceName;}DataSourceEnum(String dataSourceName) {this.dataSourceName = dataSourceName;}
}

数据源上下文保持类

/*** 数据源上下文线程持有类*/
public class DynamicDataSourceContextHolder {/*** 存放当前线程使用的数据源类型信息*/private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();public static void setDataSource(String dataSourceType) {CONTEXT_HOLDER.set(dataSourceType);}public static String getDataSource() {return CONTEXT_HOLDER.get();}public static void clearDataSource() {CONTEXT_HOLDER.remove();}
}

AbstractRoutingDataSource自定义实现

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;import javax.sql.DataSource;
import java.util.Map;/*** 动态数据源切换类** @author liuenqi*/
public class DynamicDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {return DynamicDataSourceContextHolder.getDataSource();}public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {// 默认数据源super.setDefaultTargetDataSource(defaultTargetDataSource);// 所有目标数据源super.setTargetDataSources(targetDataSources);// 后处理super.afterPropertiesSet();}
}

数据源注册

注意使用jndi源的时候需要加一个特定前缀。

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;/*** 多数据源注册类*/
public class DynamicDataSourceRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware {private DataSource primaryDataSource;private DataSource secondaryDataSource;@Overridepublic void setEnvironment(Environment environment) {initPrimaryDataSource(environment);initSecondaryDataSource(environment);}/*** 组装主数据源参数,兼容jdbc-url与jndi** @param env Environment*/private void initPrimaryDataSource(Environment env) {Map<String, String> paramMap = new HashMap<>(4);if (StringUtils.isNotBlank(env.getProperty("spring.datasource.primary.url"))) {paramMap.put("url", env.getProperty("spring.datasource.primary.url"));paramMap.put("userName", env.getProperty("spring.datasource.primary.username"));paramMap.put("password", env.getProperty("spring.datasource.primary.password"));paramMap.put("driverClassName", env.getProperty("spring.datasource.primary.driver-class-name"));} else {paramMap.put("jndi", env.getProperty("spring.datasource.primary.jndi-name"));}primaryDataSource = buildDataSource(paramMap);}/*** 组装辅数据源参数,兼容jdbc-url与jndi** @param env Environment*/private void initSecondaryDataSource(Environment env) {if (StringUtils.isNotBlank(env.getProperty("spring.datasource.secondary.url"))) {Map<String, String> paramMap = new HashMap<>(4);paramMap.put("url", env.getProperty("spring.datasource.secondary.url"));paramMap.put("userName", env.getProperty("spring.datasource.secondary.username"));paramMap.put("password", env.getProperty("spring.datasource.secondary.password"));paramMap.put("driverClassName", env.getProperty("spring.datasource.secondary.driver-class-name"));secondaryDataSource = buildDataSource(paramMap);} else if (StringUtils.isNotBlank(env.getProperty("spring.datasource.secondary.jndi-name"))) {Map<String, String> paramMap = new HashMap<>(2);paramMap.put("jndi", env.getProperty("spring.datasource.secondary.jndi-name"));secondaryDataSource = buildDataSource(paramMap);}}@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {Map<Object, Object> targetDataSource = new HashMap<>(2);targetDataSource.put("primary", primaryDataSource);if (Objects.nonNull(secondaryDataSource)) {targetDataSource.put("secondary", secondaryDataSource);}// 为DynamicDataSource构造参数,注意参数顺序ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();constructorArgumentValues.addGenericArgumentValue(primaryDataSource);constructorArgumentValues.addGenericArgumentValue(targetDataSource);// 构造bean放入IOCGenericBeanDefinition beanDefinition = new GenericBeanDefinition();beanDefinition.setBeanClass(DynamicDataSource.class);beanDefinition.setConstructorArgumentValues(constructorArgumentValues);beanDefinition.setSynthetic(true);registry.registerBeanDefinition("dataSource", beanDefinition);}/*** 使用HikariDataSource** @param paramMap {"url":"JDBC-URL","userName":"数据库用户名","password":"密码","driverClassName":"驱动名","jndi":"jndi源"}* @return HikariDataSource*/private DataSource buildDataSource(Map<String, String> paramMap) {HikariConfig hikariConfig = new HikariConfig();if (paramMap.containsKey("url")) {hikariConfig.setJdbcUrl(paramMap.get("url"));hikariConfig.setUsername(paramMap.get("userName"));hikariConfig.setPassword(paramMap.get("password"));hikariConfig.setDriverClassName(paramMap.get("driverClassName"));} else {hikariConfig.setDataSourceJNDI("java:comp/env/" + paramMap.get("jndi"));}return new HikariDataSource(hikariConfig);}
}

application.yml配置

spring:datasource:primary:url: jdbc:mysql://xxxxxusername: xxxxpassword: xxxxxdriver-class-name: com.mysql.cj.jdbc.Driversecondary: jndi-name: jdbc/db

相关文章:

基于注解切换、Hikari实现的SpringBoot动态数据源(支持JNDI)

实现效果 先说效果&#xff0c;要实现方法级别注解切换当前数据源&#xff0c;不设置注解时走默认数据源&#xff0c;同时支持JNDI源。 总体思路 Spring框架中存在一个抽象类AbstractRoutingDataSource&#xff0c;他是一个可以动态选择当前DataSource的路由类&#xff0c;我…...

Java中的动态链接VS操作系统动态链接

在操作系统OS中为了优化内存的使用会采用一种动态链接方式&#xff0c;一个文件想要在操作系统中运行必须经过编译、汇编译、链接、装载等步骤。可以参考Java程序是怎么跑起来的。本篇主要讲解Java栈帧中动态链接部分与操作系统的的动态链接的区别与联系 操纵系统为什么需要动态…...

深入理解Linux虚拟内存管理(七)

系列文章目录 Linux 内核设计与实现 深入理解 Linux 内核 Linux 设备驱动程序 Linux设备驱动开发详解 深入理解Linux虚拟内存管理&#xff08;一&#xff09; 深入理解Linux虚拟内存管理&#xff08;二&#xff09; 深入理解Linux虚拟内存管理&#xff08;三&#xff09; 深入理…...

GSR II 智能速度辅助系统的型式认证和系统作为独立技术单元的型式认证测试流程和技术要求

智能速度辅助系统ISA的型式认证和系统作为独立技术单元的型式认证测试流程和技术要求 补充欧洲议会和欧洲理事会第2019/2144号条例,为机动车智能速度辅助系统的型式认证和这些系统作为独立技术单元的型式认证规定了详细的测试程序和技术要求,并修订该条例的附件二 (1)(EU…...

工厂方法模式(五)

过气的&#xff0c;终究是过气了 上一章简单介绍了工厂模式(四), 如果没有看过,请观看上一章 一.工厂方法模式 工厂方法模式&#xff0c;通过定义工厂父类负责定义创建对象的公共接口&#xff0c;而子类则负责生成具体的对象。 将类的实例化&#xff08;具体产品的创建&…...

力扣笔记(每日随机一题)——最佳买卖股票时机含冷冻期

问题&#xff08;中等&#xff09; 给定一个整数数组prices&#xff0c;其中第 prices[i] 表示第 i 天的股票价格 。​ 设计一个算法计算出最大利润。在满足以下约束条件下&#xff0c;你可以尽可能地完成更多的交易&#xff08;多次买卖一支股票&#xff09;: 卖出股票后&a…...

yolov5 6.1 关于 tensorrt 加速的使用以及问题说明

文章目录 1. 参考连接2. 使用说明2.1 导出加速模型2.1 使用加速模型2.2 加速参数对比 3. 问题说明3.1 在 Tensorrt 8.4.1.5 版本上使用 export.py 导出失败的问题3.2 把模型文件由 best.pt 更换成加速后的 best.engine 后&#xff0c;执行推理时标注的类别名不正确的问题3.3 导…...

SVR(支持向量机)用法介绍

一、SVR回归介绍 SVR(Support Vector Regression)是支持向量机(SVM)在回归问题中的应用。与SVM分类模型相似&#xff0c;SVR也是一种非概率性算法&#xff0c;通过使用核函数将数据映射到高维空间&#xff0c;并在该空间上寻找最优的超平面与训练数据之间的间隔最大化&#xf…...

是面试官放水,还是公司实在是太缺人?这都没挂,腾讯原来这么容易进···

本人211非科班&#xff0c;之前在字节和腾讯实习过&#xff0c;这次其实没抱着什么特别大的希望投递&#xff0c;没想到腾讯可以再给我一次机会&#xff0c;还是挺开心的。 本来以为有个机会就不错啦&#xff01;没想到能成功上岸&#xff0c;在这里要特别感谢帮我内推的同学&…...

算法模板(5):数学(1):数学知识(1)

数论 整数的整除性 [x]表示不超过x的最大整数&#xff0c;叫做取整函数或高斯函数。设整数a&#xff0c;b不同时为零&#xff0c;则存在一对整数m&#xff0c;n&#xff0c;使得 ( a , b ) a m b n (a, b) am bn (a,b)ambn。注&#xff1a;a和b的最大公因数会写成 (a, b)…...

电子行业 K 公司对接 Nexperia EDI 项目案例

项目背景 Nexperia 是一家全球领先的半导体制造商&#xff0c;专注于提供高性能、高可靠性和创新性的半导体解决方案。公司成立于2017年&#xff0c;是前飞思卡尔半导体业务的一部分&#xff0c;并在全球范围内拥有多个设计、研发和生产基地。 Nexperia 使用 EDI&#xff08;…...

chatgpt赋能python:Python如何将英文转化为中文的最佳方法

Python如何将英文转化为中文的最佳方法 介绍 在现代全球化社会中&#xff0c;国与国之间的交流越来越频繁&#xff0c;相应的语言翻译工具的需求也愈发迫切。Python是一种易于学习、快速上手的编程语言&#xff0c;适合初学者和经验丰富的程序员使用&#xff0c;在语言翻译方…...

知道这些英文文档翻译的方式吗

在工作中&#xff0c;大家有没有遇到领导交给你一份外语的文档&#xff0c;要你去观看和理解&#xff0c;但是我们看不太懂或者没啥时间去一点点翻译怎么办呢&#xff1f;我们就需要有工具来将文档翻译&#xff0c;它是一项非常实用和便捷的功能&#xff0c;它可以将文档中的文…...

供应链安全

供应链安全 目录 文章目录 供应链安全目录本节实战可信任软件供应链概述构建镜像Dockerfile文件优化镜像漏洞扫描工具&#xff1a;Trivy检查YAML文件安全配置&#xff1a;kubesec准入控制器&#xff1a; Admission Webhook准入控制器&#xff1a; ImagePolicyWebhook关于我最后…...

华硕天选4原装Windows11系统带ASUSRECOVERY恢复工厂模式安装

华硕工厂恢复系统 &#xff0c;安装结束后带隐藏分区以及机器所有驱动软件,奥创Myasus Recovery 文件地址https://pan.baidu.com/s/1Pq09oDzmFI6hXVdf8Vqjqw?pwd3fs8 提取码:3fs8 文件格式&#xff1a;5个底包(HDI KIT COM MCAFEE EDN) 1个引导工具TLK 支持ASUSRECOVERY型…...

数据库期末复习(8)并发控制

笔记 数据库DBMS并发控制(1)_旅僧的博客-CSDN博客 数据库 并发控制(2)死锁和意向锁_旅僧的博客-CSDN博客 同一个对象不能既有slock又有xlock; 冲突可串行化和锁 怎么判断是否可以进行冲突可串行化:简便的方法是优先图 只有不同对象和同一对象都是读才不能发生非串行化调…...

一文说透:低代码开发平台和零代码平台区别是什么?

低代码开发平台和零代码平台区别是什么&#xff1f; 一个简单的例子就可以解释清楚。 假设你想入住一套新房&#xff0c;回看住房变迁史&#xff1a; 最原始方式是&#xff1a;自己建造往后一点&#xff0c;交付“毛坯房”&#xff1a;开发商统一建小区&#xff0c;不需要自…...

4.将图神经网络应用于大规模图数据(Cluster-GCN)

到目前为止&#xff0c;我们已经为节点分类任务单独以全批方式训练了图神经网络。特别是&#xff0c;这意味着每个节点的隐藏表示都是并行计算的&#xff0c;并且可以在下一层中重复使用。 然而&#xff0c;一旦我们想在更大的图上操作&#xff0c;由于内存消耗爆炸&#xff0c…...

pymongo更新数据

使用 PyMongo&#xff0c;可以通过以下步骤将查询到的记录进行更新&#xff1a; 下面是一个简单的示例代码片段&#xff0c;展示如何向名为users的集合中的所有文档添加一个新字段age。 import pymongo # 连接 MongoDB client pymongo.MongoClient("mongodb://localh…...

手机软件测试规范(含具体用例)

菜单基本功能测试规范一、短消息功能测试规范测试选项操作方法观察与判断结果创建、编辑短消息并发送书写短消息1、分别使用菜单或快捷方式进入书写短消息是否有异常&#xff1b; 2、输入0个字符&#xff0c;选择、输入号码发送&#xff0c;应成功&#xff1b; 3、输入1个中文…...

mysql having的用法

having的用法 having字句可以让我们筛选成组后的各种数据&#xff0c;where字句在聚合前先筛选记录&#xff0c;也就是说作用在group by和having字句前。而 having子句在聚合后对组记录进行筛选。我的理解就是真实表中没有此数据&#xff0c;这些数据是通过一些函数生存。 SQ…...

大数据需要学习哪些内容?

大数据技术的体系庞大且复杂&#xff0c;每年都会涌现出大量新的技术&#xff0c;目前大数据行业所涉及到的核心技术主要就是&#xff1a;数据采集、数据存储、数据清洗、数据查询分析和数据可视化。 Python 已成利器 在大数据领域中大放异彩 Python&#xff0c;成为职场人追求…...

【c++】static和const修饰类的成员变量或成员函数

目录 1、静态成员变量 2、静态成员函数 3、常函数 4、常对象 当我们使用c的关键字static修饰类中的成员变量和成员函数的时候&#xff0c;此时的成员变量和成员函数被称为静态成员。 静态成员包含&#xff1a; 静态成员变量静态成员函数 1、静态成员变量 静态成员变量有…...

DVWA-9.Weak Session IDs

大约 了解会话 ID 通常是在登录后以特定用户身份访问站点所需的唯一内容&#xff0c;如果能够计算或轻松猜测该会话 ID&#xff0c;则攻击者将有一种简单的方法来访问用户帐户&#xff0c;而无需暴力破解密码或查找其他漏洞&#xff0c;例如跨站点脚本。 目的 该模块使用四种…...

Bug序列——容器内给/root目录777权限后无法使用ssh免密登录

Linux——创建容器并将本地调试完全的前后端分离项目打包上传docker运行_北岭山脚鼠鼠的博客-CSDN博客 接着上一篇文章结尾出现403错误时通过赋予/root目录以777权限解决403错误。 chmod 777 /root 现在又出现新的问题&#xff0c;远程ssh无法免密登录了&#xff0c;即使通过…...

华为OD机试真题 JavaScript 实现【服务中心选址】【2023Q1 100分 】

一、题目描述 一个快递公司希望在一条街道建立新的服务中心。公司统计了该街道中所有区域在地图上的位置&#xff0c;并希望能够以此为依据为新的服务中心选址&#xff0c;使服务中心到所有区域的距离的总和最小。 给你一个数组 positions&#xff0c;其中 positions[i] [le…...

<Linux>《OpenSSH 客户端配置文件ssh_config详解》

《OpenSSH 客户端配置文件ssh_config详解》 1、 ssh获取配置数据顺序2、关键字2.1 Host2.2 Match2.3 AddKeysToAgent2.4 AddressFamily2.5 BatchMode2.6 BindAddress2.7 BindInterface2.8 CanonicalDomains2.9 CanonicalizeFallbackLocal2.10 CanonicalizeHostname2.11 Canonic…...

Linux内核中内存管理相关配置项的详细解析8

接前一篇文章&#xff1a;Linux内核中内存管理相关配置项的详细解析7 十一、Enable KSM for page merging 对应配置变量为&#xff1a;CONFIG_KSM。 此项只有选中和不选中两种状态&#xff0c;默认为选中。 内核源码详细解释为&#xff1a; Enable Kernel Samepage Merging:…...

深入浅出Vite:Vite打包与拆分

一、背景 在生产环境下,为了提高页面加载性能,构建工具一般将项目的代码打包(bundle)到一起,这样上线之后只需要请求少量的 JS 文件,大大减少 HTTP 请求。当然,Vite 也不例外,默认情况下 Vite 利用底层打包引擎 Rollup 来完成项目的模块打包。 某种意义上来说,对线上环…...

大数据ETL工具Kettle

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言最近公司在搞大数据数字化&#xff0c;有MES,CIM,WorkFlow等等N多的系统&#xff0c;不同的数据源DB&#xff0c;需要将这些不同的数据源DB里的数据进行整治统一…...

内江市住房和城乡建设局网站电话号码/一份完整的电商运营方案

重要提示&#xff1a; 下一版本的 Microsoft SQL Server 将删除该功能。请不要在新的开发工作中使用该功能&#xff0c;并尽快修改当前还在使用该功能的应用程序。 改为使用链接服务器和链接服务器存储过程。 返回远程 SQL Server 数据库服务器在登录记录中显示的名称。 Transa…...

wordpress分享获得积分/网址导航该如何推广

主要考察组合数知识&#xff0c;初始化的时候参考公式首先先推个公式&#xff0c;就是长度为len的Round Numbers的个数。长度为len,第一位肯定是1了。那么后面剩下 len-1位。如果len-1是偶数。那么 C&#xff08;len-1,(len-1)/21)C&#xff08;len-1,(len-1)/22)C(len-1,len-…...

如何登录网站备案/友情链接怎么购买

转自&#xff1a;http://blog.csdn.net/stormbjm/article/details/9086163 1、添加用户&#xff0c;首先用adduser命令添加一个普通用户&#xff0c;命令如下&#xff1a; #adduser tommy //添加一个名为tommy的用户#passwd tommy //修改密码 Changing password for user tom…...

徐州做网站管理的公司/广告联盟app下载

# yum install gconf-editor打开gconf-editor找到/apps/panel/clock/prefs/(这是默认位置)修改custom_format的值为%Y-%m-%d %H:%M&#xff0c;也可自己定制其他修改format的值为custom转载于:https://www.cnblogs.com/dule/archive/2013/03/25/2981115.html...

深圳做门户网站的网络公司/深圳网络公司推广

QPS&#xff1a;Queries Per Second意思是“每秒查询率”&#xff0c;是一台服务器每秒能够相应的查询次数&#xff0c;是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。 TPS&#xff1a;是TransactionsPerSecond的缩写&#xff0c;也就是事务数/秒。它是软件…...

网站开发主流框架/百度官网推广

1、如果只增加集群的存储量&#xff0c;建议增加Hadoop datanode节点。 方法&#xff1a; 停掉集群包括hadoop和hbase&#xff0c;当然也可以不停掉&#xff0c;直接在hadoop namenode的配置文件Slave里添加新节点的host&#xff0c;别忘了在host文件里也要添加新添加的host名…...