数据结构之MySQL独爱B+树(二叉树、AVL树、红黑树、B树对比)

一、二叉查找树 (1)二叉树简介: 二叉查找树也称为有序二叉查找树,满足二叉查找树的一般性质,是指一棵空树具有如下性质: 1、任意节点左子树不为空,则左子树的值均小于根节点的值; 2、任意节点右子树不为空,则右子树的值均大于于根节点的值; 3、任意节点的左右子树也分别是二叉查找树; 4、没有键值相等的节点; 上图为一个普通的二叉查找树,按照中序遍历的方式可以从小到大的顺序排序输出:15、20、30、50、60、70。 对上述二叉树进行查找,如查键值为30的记录,先找到根,其键值是50,50大于30,因此查找50的左子树,找到20;而30大于20,再找其右子树;一共找了3次。如果按15、20、30、50、60、70的顺序来找同样需求3次。用同样的方法在查找键值为70的这个记录,这次用了3次查找,而顺序查找需要6次。计算平均查找次数得:顺序查找的平均查找次数为(1+2+3+4+5+6)/ 6 = 3.3次,二叉查找树的平均查找次数为(3+3+3+2+2+1)/6=2.3次。二叉查找树的平均查找速度比顺序查找来得更快。 (2)局限性及应用 一个二叉查找树是由n个节点随机构成,所以,对于某些情况,二叉查找树会退化成一个有n个节点的线性链。 大家看上图,如果我们的根节点选择是最小或者最大的数,那么二叉查找树就完全退化成了线性结构。上图中的平均查找次数为(1+2+3+4+5+5)/6=3.16次,和顺序查找差不多。显然这个二叉树的查询效率就很低,因此若想最大性能的构造一个二叉查找树,需要这个二叉树是平衡的(这里的平衡从一个显著的特点可以看出这一棵树的高度比上一个输的高度要大,在相同节点的情况下也就是不平衡),从而引出了一个新的定义-平衡二叉树AVL。 二、AVL树 (1)简介 AVL树是带有平衡条件的二叉查找树,一般是用平衡因子差值判断是否平衡并通过旋转来实现平衡,左右子树树高不超过1,和红黑树相比,它是严格的平衡二叉树,平衡条件必须满足(所有节点的左右子树高度差不超过1)。不管我们是执行插入还是删除操作,只要不满足上面的条件,就要通过旋转来保持平衡,而旋转是非常耗时的,由此我们可以知道AVL树适合用于插入删除次数比较少,但查找多的情况。 从上面是一个普通的平衡二叉树,这张图我们可以看出,任意节点的左右子树的平衡因子差值都不会大于1。 (2)局限性 由于维护这种高度平衡所付出的代价比从中获得的效率收益还大,故而实际的应用不多,更多的地方是用追求局部而不是非常严格整体平衡的红黑树。当然,如果应用场景中对插入删除不频繁,只是对查找要求较高,那么AVL还是较优于红黑树。 (3)应用 1、Windows NT内核中广泛存在; 三、红黑树 (1)简介 一种二叉查找树,但在每个节点增加一个存储位表示节点的颜色,可以是red或black。通过对任何一条从根到叶子的路径上各个节点着色的方式的限制,红黑树确保没有一条路径会比其它路径长出两倍。它是一种弱平衡二叉树(由于是若平衡,可以推出,相同的节点情况下,AVL树的高度低于红黑树),相对于要求严格的AVL树来说,它的旋转次数变少,所以对于搜索、插入、删除操作多的情况下,我们就用红黑树。 (2)性质 1、每个节点非红即黑; 2、根节点是黑的; 3、每个叶节点(叶节点即树尾端NULL指针或NULL节点)都是黑的; 4、如果一个节点是红的,那么它的两儿子都是黑的; 5、对于任意节点而言,其到叶子点树NULL指针的每条路径都包含相同数目的黑节点; 6、每条路径都包含相同的黑节点; (3)应用 1、广泛用于C++的STL中,Map和Set都是用红黑树实现的; 2、著名的Linux进程调度Completely Fair Scheduler,用红黑树管理进程控制块,进程的虚拟内存区域都存储在一颗红黑树上,每个虚拟地址区域都对应红黑树的一个节点,左指针指向相邻的地址虚拟存储区域,右指针指向相邻的高地址虚拟地址空间; 3、IO多路复用epoll的实现采用红黑树组织管理sockfd,以支持快速的增删改查; 4、Nginx中用红黑树管理timer,因为红黑树是有序的,可以很快的得到距离当前最小的定时器; 5、Java中TreeMap的实现; 四、B/B+树 (1)简介 B/B+树是为了磁盘或其它存储设备而设计的一种平衡多路查找树(相对于二叉,B树每个内节点有多个分支),与红黑树相比,在相同的的节点的情况下,一颗B/B+树的高度远远小于红黑树的高度(在下面B/B+树的性能分析中会提到)。B/B+树上操作的时间通常由存取磁盘的时间和CPU计算时间这两部分构成,而CPU的速度非常快,所以B树的操作效率取决于访问磁盘的次数,关键字总数相同的情况下B树的高度越小,磁盘I/O所花的时间越少。 注意B-树就是B树,-只是一个符号。 (2)B树的性质 1、定义任意非叶子结点最多只有M个儿子,且M>2; 2、根结点的儿子数为[2, M]; 3、除根结点以外的非叶子结点的儿子数为[M/2, M]; 4、每个结点存放至少M/2-1(取上整)和至多M-1个关键字;(至少2个关键字) 5、非叶子结点的关键字个数=指向儿子的指针个数-1; 6、非叶子结点的关键字:K[1], K[2], …, K[M-1];且K[i] < K[i+1]; 7、非叶子结点的指针:P[1], P[2], …, P[M];其中P[1]指向关键字小于K[1]的子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向关键字属于(K[i-1], K[i])的子树; 8、所有叶子结点位于同一层; 这里只是一个简单的B树,在实际中B树节点中关键字很多的。 五、B+树 (1)简介

NoSQL和SQL简介和对比

在日常的编码中,我们常用的是SQL(结构化的查询语言)数据库,SQL是过去四十年间存储数据的主要方式。现在主流的SQL主要有MySQL、SQLServer、Oracel等数据库。NoSQL数据库自从20世纪60年代就已经存在了,现在主流的NoSQL有MongoDB, CouchDB, Redis 和Memcache等数据库。 SQL就不做过多的介绍了,我们来说一下NoSQL。NoSQL,指的是非关系型的数据库。NoSQL有时也称作Not Only SQL的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称。NoSQL用于超大规模数据的存储。(例如谷歌或Facebook每天为他们的用户收集万亿比特的数据)。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。 菜鸟教程的SQL简介:http://www.runoob.com/sql/sql-tutorial.html 菜鸟教程的NOSQL简介:http://www.runoob.com/mongodb/nosql.html 关于NoSQL和MySQL一点看法: SQL和NoSQL有着相同的目标:存储数据。但是它们存储数据的方式不同,这可能会影响到你开发的项目,一种会简化你的开发,一种会阻碍你的开发。尽管目前NoSQL数据库非常的火爆,但是NoSQL是不能取代SQL的--它仅仅是SQL的一种替代品。一些项目可能会更适合使用SQL数据库,然而一些项目可能会比较适合使用NoSQL,有些项目使用哪一种都可以很好地达到预期的效果。SQL和NoSQL没有明显的区别。一些SQL数据库也采用了NoSQL数据库的特性,反之亦然。在选择数据库方面的界限变得越来越模糊了,并且一些新的混合型数据库将会在不久的将来提供更多的选择。 SQL和NoSQL的区别: SQL数据库提供关系型的表来存储数据,NoSQL数据库采用类JOSN的键值对来存储文档。 SQL中的表结构具有严格的数据模式约束,因此存储数据很难出错。 NoSQL存储数据更加灵活自由,但是也会导致数据不一致性问题的发生。 在SQL数据库中,除非你事先定义了表和字段的模式否则你无法向其中添加数据。在NoSQL数据库中,数据在任何时候都可以进行添加,不需要事先去定义文档和集合。 SQL在进行数据的逻辑操作之前我们必须要定义数据模式,数据模式可以在后期进行更改,但是对于模式的大改将会是非常复杂的。因此NoSQL数据库更适合于那些不能够确定数据需求的的工程项目(MongoDB会在集合中为每一个文档添加一个独一无二的id。如果你仍然想要定义索引,你也可以自己在之后定义)。 模式中包含了许多的信息:主键 — 独一无二的标志就像ISBN唯一确定一条记录;索引 — 通常设置索引字段加快搜索的速度;关系 — 字段之间的逻辑连接;计功能例如触发器和存储程序 SQL具有数据库的规范化。NoSQL虽然可以同样使用规范化,但是更倾向非规范化。 在SQL中我们需要增加一张新表tableB,一张旧表tableB关联新表只需使用外键B_id,用于引用tableB中的信息,这样的设计能够最小化数据的冗余,我们不需要为tableA重复的添加tableB的所有信息—只需要去引用就可以了。这项技术叫做数据库的规范化,具有实际的意义。我们可以更改tableB的信息而不用修改tableA中的数据。而NoSQL更多的是在tableA中为每项数据添加tableB的信息,这样会使查询更快,但是在更新出版社信息的记录变多时效率将会显著地下降。 SQL具有JOIN操作。 NoSQL则没有 SQL语言为查询提供了强大的JOIN操作。我们可以使用单个SQL语句在多个表中获取相关数据。而在NoSQL中没有与JOIN相同的操作,对于具有SQL语言经验的人来说是非常令人震惊的。这也是非规范化存在的原因之一。 SQL具有数据完整性。NoSQL则不具备数据完整性 大多数的数据库允许通过定义外键来进行数据库的完整性约束。在NoSQL数据库中则没有数据完整性的约束选项。你可以存储任何你想要存储的数据。理想情况下,单个文档将是项目的所有信息的唯一来源。 SQL需要自定义事务。NoSQL 操作单个文档时具备事务性,而操作多个文档时则不具备事务性 在SQL数据库中,两条或者多条更新操作可以结合成一个事务(或者全部执行成功否则失败)执行。将两条更新操作绑定为一个事务确保了它们要么全部成功要么全部失败。在NoSQL数据库中,对于一个文档的更新操作是原子性的。换句话说,如果你要更新一个文档中的三个值,要么三个值都更新成功要么它们保持不变。然而,对于操作多个文档时没有与事务相对应的操作。在MongoDB中有一个操作是transaction-like options,但是,需要我们手动的加入到代码中。 SQL使用SQL语言。NoSQL使用类JSON SQL是一种声明性语言。SQL语言的功能强大,并且已经成为了一种国际的通用标准,尽管大多数系统在语法上有一些细微的差别。NoSQL数据库使用类似JOSN为参数的JavaScript来进行查询!基本操作是相同的,但是嵌套的JOSN将会产生复杂的查询。 NoSQL比SQL更快 通常情况下,NoSQL比SQL语言更快。这并没有什么好震惊的,NoSQL中更加简单的非规范化存储允许我们在一次查询中得到特定项的所有信息。不需要使用SQL中复杂的JOIN操作。也就是说,你的项目的设计和数据的需求会有很大的影响。一个好的SQL数据库的设计的表现一定会比一个设计不好的NoSQL数据库性能好很多,反之亦然。 适合使用SQL开发的项目: 可以预先定义逻辑相关的离散数据的需求 数据一致性是必要的 具有良好的开发者经验和技术支持的标准的成熟技术 适合使用NoSQL开发的项目: 不相关,不确定和逐步发展的数据需求 更简单或者更宽松的能够快速开始编程的项目速度和可扩展性至关重要的 总结 SQL数据库: 使用表存储相关的数据 在使用表之前需要先定义标的模式 鼓励使用规范化来减少数据的冗余 支持使用JOIN操作,使用一条SQL语句从多张表中取出相关的数据 需要满足数据完整性约束规则 使用事务来保证数据的一致性 能够大规模的使用 使用强大的SQL语言进行查询操作 提供大量的支持,专业技能和辅助工具 NoSQL数据库: 使用类JSON格式的文档来存储键值对信息 存储数据不需要特定的模式 使用非规范化的标准存储信息,以保证一个文档中包含一个条目的所有信息 不需要使用JOIN操作 允许数据不用通过验证就可以存储到任意的位置 保证更新的单个文档,而不是多个文档 提供卓越的性能和可扩展性 使用JSON数据对象进行查询 是一种新型的技术

读取sftp服务器上的文件内容到指定的数据库表内

引入sftp jar依赖 <dependency> <groupId>com.jcraft</groupId> <artifactId>jsch</artifactId> <version>0.1.27</version> </dependency> 登录sftp的工具类 package com.chenfu; import com.jcraft.jsch.*; import java.util.Properties; public class SftpUtils { private static ChannelSftp sftp = null; private static Session session = null; // 登录 public static ChannelSftp login() throws JSchException, SftpException { JSch jSch = new JSch(); // 设置用户名和主机,端口号一般都是22 session = jSch.getSession("userName", "host", port); // 设置密码 session.setPassword("password"); Properties config = new Properties(); config.put("StrictHostKeyChecking", "no"); session.setConfig(config); session.connect(); Channel channel = session.openChannel("sftp"); channel.connect(); sftp = (ChannelSftp) channel; System.

spring boot security 防止用户重复登录(原创)

原理:在认证成功通过后,在显示登录成功页面之前,也就是在SavedRequestAwareAuthenticationSuccessHandler类中操作。 添加一个集合sessionMap 用于保存认证成功的会话,键名为会话ID, 每次有用户登录认证通过都要判断一下是否重复登录,如果不是继续执行,将会话保存在集合sessionMap里。 如果是就踢除之前登录过的用户的会话,将旧的会话从集合sessionMap里删除,还有一步就是将旧的会话从sessionRegistry里删除(不然你如果要获取所有认证通过的用户,还会从sessionRegistry中获取旧用户),然后将自己的新会话保存到集合sessionMap里。(每次认证通过的用户会话都会保存到sessionRegistry里,所以不必自己再写一遍) package com.test.handler; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.session.SessionRegistry; import org.springframework.security.core.session.SessionRegistryImpl; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; import org.springframework.stereotype.Component; import com.test.domain.SysUser; import com.test.util.SessionUtil; //登录用户认证通过后,显示登录成功页面前,做的操作。 @Component public class MyAuthenctiationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler { private static final Logger logger = LoggerFactory.

matlab —— cftool曲线拟合工具箱的使用

Matlab有一个功能强大的曲线拟合工具箱 cftool ,使用方便,能实现多种类型的线性、非线性曲线拟合。 1、输入数据: 2、启动cftool工具箱 >>cftool 3、导入数据: 4、功能介绍: 第一个是“main plot”,画出主要的图第二个是“Residuals plot”,画出残差图第三个是“Contour plot”,画出轮廓图第六个是“Pan”,可用来拖曳坐标轴第七个是“Data cursor”,进行数据提示第八个是“Exclude outliers”,剔除异常值 对数据进行中心化与比例化处理,当拟合情况较差时,可以通过该选项得到更好的拟合效果 Custom Equations:用户自定义的函数类型Exponential:指数逼近,有2种类型, a*exp(b*x) 、 a*exp(b*x) + c*exp(d*x)Fourier:傅立叶逼近,有7种类型,基础型是 a0 + a1*cos(x*w) + b1*sin(x*w)Gaussian:高斯逼近,有8种类型,基础型是 a1*exp(-((x-b1)/c1)^2)Interpolant:插值逼近,有4种类型,linear、nearest neighbor、cubic spline、shape-preservingPolynomial:多形式逼近,有9种类型,linear ~、quadratic ~、cubic ~、4-9th degree ~Power:幂逼近,有2种类型,a*x^b 、a*x^b + cRational:有理数逼近,分子、分母共有的类型是linear ~、quadratic ~、cubic ~、4-5th degree ~;此外,分子还包括constant型Smoothing Spline:平滑逼近(翻译的不大恰当,不好意思)Sum of Sin Functions:正弦曲线逼近,有8种类型,基础型是 a1*sin(b1*x + c1)Weibull:只有一种,a*b*x^(b-1)*exp(-a*x^b)

Convolution+BatchNorm+Scale模块参数设置 & 融合BatchNorm+Scale层到Convolution层

Convolution+BatchNorm+Scale+Relu的组合模块在卷积后进行归一化,然后在放出非线性Relu层,可以加速训练收敛。但在推理时BatchNorm非常耗时,可以将训练时学习到的BatchNorm+Scale的线性变换参数融合到卷积层,替换原来的Convolution层中weight和bias,实现在不影响准确度的前提下加速预测时间。 一、Convolution+BatchNorm+Scale层在caffe中参数设置示例: layer { name: "Conv1" type: "Convolution" bottom: "Conv1" top: "Conv2" convolution_param { num_output: 64 kernel_h:1 kernel_w:3 pad_h: 0 pad_w: 1 stride: 1 weight_filler { type: "msra" } bias_term: false } } layer { name: "Conv2/bn" type: "BatchNorm" bottom: "Conv2" top: "Conv2" batch_norm_param { use_global_stats: false eps:1e-03 } param { lr_mult: 0 decay_mult: 0 } param { lr_mult: 0 decay_mult: 0 } param { lr_mult: 0 decay_mult: 0 } include { phase: TRAIN } } layer { name: "

京东数据库智能运维平台建设之路

运维自动化来源于工作中的痛点,京东数据库团队面对的是商城成千上万的研发工程师,这种压力推动我们不断变革,然而变革不是一蹴而就,也经历过从手工到脚本化、自动化、平台化、智能化的艰难转变,所以说是需求在驱动运维体系的建设,而运维自动化的真谛在于解放运维人员,促进人率提升,减少人为故障,要学会培养自己“懒”这个好习惯。 京东的自动化运维体系建设始于2012年,下面从两个方面进行介绍: 一、京东数据库智能运维平台 京东业务每年都在以爆发的形式在增长,数据库服务器的数量众多,产品线也多达上千条,要支持如此庞大的业务体系,需要一套完善的运维自动化管理平台。目前京东MySQL数据库管理平台简称DBS,主要涵盖以下内容:完善的资产管理系统、数据库流程管理系统、数据库监控系统、数据库故障管理系统、数据库报表系统、弹性数据库系统以及数据库辅助运维工具,涉及DBA运维的方方面面,实现了DBA对MySQL的自动化、自助化、可视化、智能化、服务化管理,避免DBA因手工操作失误带来的生产事故,保障京东数据库的安全、稳定、高效运行。 这里着重介绍以下部分核心功能组件: 1、元数据管理 作为自动化运维的基石,它的准确性直接关系到整个数据库管理平台的可靠性。京东数据库管理平台从数据库业务方、DBA的运维习惯等方面出发,涵盖机房、主机、业务、集群、实例、库、表等多个维度: 机房和主机维度:主要记录硬件方面的信息。业务维度:主要记录业务的名称、等级及业务部门相关信息。集群维度:主要记录MySQL集群架构信息。实例维度:主要记录MySQL的相关参数,为后续自动化运维提供保障。库维度:主要记录数据库名称及业务人员联系信息。 2、自动化部署 面对繁杂的数据库新增,扩容等运维工作,利用自动安装部署平台可以彻底解放DBA。目前京东的自动化部署系统包含申请服务器、部署数据库实例、同步数据、一致性校验、拆分及切换等操作,整个过程流程化,包含各级业务及DBA的操作审批,最终达到全面的MySQL服务的自动化和流程化部署,如下图: 主要功能点包含以下内容: 安装部署MySQL实例,架构搭建,域名申请。分配规则要求同一集群主从实例不能在同一机柜,硬件性能好的主机优先为主库。监控部署,备份部署,资产注册。MySQL服务采用镜像的形式创建,镜像依赖于K8S的镜像仓库。应用账号是应用方通过自动化上线系统申请创建的。主从数据一致性校验,通常会选择夜间业务低峰期定时执行。 3、智能分析与诊断 京东的智能分析与诊断涵盖4部分重要的内容,数据库监控指标采集、诊断分析、故障自愈、趋势分析: (1)监控系统 监控系统为数据库管理提供了精准的数据依据,能够让运维人员对生产服务系统运行情况了如指掌,核心的监控指标包含:OS负载、MySQL核心指标、数据库日志等。通过分析获得的监控信息,判断被监控数据库的运行状态,对可能出现的问题进行预测,并给出优化方案,保证整个系统稳定、高效。 京东的分布式监控系统采用被动模式,server端和proxy端均做高可用,防止单点故障。以下是整体架构和流程图: (2)监控性能分析 数据库性能智能分析,主要是对数据库监控数据的二次分析,排除安全隐患。在实际的生产中,有些隐患没有达到设置的报警阈值,处于一个报警的临界点,其实这种情况是最危险的,随时可能爆发,为解决这些隐患,我们通过对监控数据的环比、同比、TOP指标等方面进行分组汇总分析,提前发现隐患。 慢SQL分析: 索引分析: 空间分析及预测: 锁分析: (3)故障自愈 故障出现的形态千奇百怪,而最核心的内容依赖于监控的辅助分析,如何提供最为精准的信息,所做内容如下: 告警过滤:将告警中不重要的告警以及重复告警过滤掉 生成派生告警:根据关联关系生成各类派生告警 告警关联:同一个时间窗内不同类型派生告警是否存在关联 权重计算:根据预先设置的各类告警的权重,计算成为根源告警的可能性 生成根源告警:将权重最大的派生告警标记为根源告警 根源告警合并:若多类告警计算出的根源告警相同,则将其合并 4、智能切换系统 京东数据库服务器的量级较大,会导致出故障的概率相对提高,同时对系统稳定性的要求也较为苛刻。因此为确保实现数据库高可用,保证7*24小时的持续服务,我们团队自主研发了数据库自动切换平台,实现了自动和半自动两种切换方式,实现了按单集群级别、多集群级别、机房级别等多维度的场景切换。切换过程包含监控的修改、资产信息的修改、备份策略的修改、主从角色的修改等,一键化完成,避免人为因素带来的二次故障。 (1)分布式检测 作为切换系统的核心组件,分布式检测功能主要解决系统容灾方面的问题。按照京东数据库服务器多数据中心部署的特征,独立的数据中心各部署了一个检测节点,并通过特殊标识的接口域名区分。当发生切换操作时,切换系统会根据传入的故障主机IP等信息,随机选取两个机房接口执行调用,探活操作如果发现有一个节点主机存活,那么认为主机存活;如果发现两个节点都探测为宕机,那么认为主机宕机。 (2)Master故障切换 主库实例故障,切换系统会首先通过分布式检测系统检查实例存活状态,确认宕机后将根据基础信息中的实例切换标识,选择使用自动切换或手动切换,两种切换方式原理相同:先在切换系统上创建切换任务,手动切换需要DBA执行切换按钮,切换操作会通过insert方式插入数据以验证实例运行状态,避免实例夯住和硬盘只读的情况。如果没有存活的从库,则放弃本次操作并以邮件和短信的方式通知DBA。新主库是按照先本地(先连接数少,后QPS负载低),后异地的原则选择,执行切换成功后将变更相应元数据信息,示例如下: 某一主四从的集群,主库 10.66.66.66:3366故障,需要切换,如下: 监控系统检测到主库宕机,则自动创建切换任务,进行自动切换或者手动切换,以手动切换为例: 选目标实例,假如例子中的4个从都是存活的,那么根据先本地后异地原则,选出10.66.66.68:3366,10.66.66.69:3366,然后再去查连接数,在连接数都相同的情况下,则去比较QPS,选出QPS负载低的10.66.66.69:3366作为目标实例: 切换完成结果: (3)Slave故障切换 从库实例故障,将故障实例下的域名变更到该集群下的非故障实例上,选择目标实例方式与主库实例选择规则一致。切换成功或失败都会发邮件及短信告知相应的DBA。故障实例恢复后,DBA判断是否需要回切。示例如下: 有一主四从的集群,从库 10.88.88.89:3366故障,需要切换,如下: 监控系统会自动创建任务,并根据先本地后异地原则,然后再查连接数、QPS,确定目标实例为10.88.88.88:3366,进行自动切换,DBA可在切换任务列表查看详情。 切换成功的任务会显示回切按钮,DBA可以执行回切,并查看回切的具体信息。 (4)主从计划性切换 主从计划性切换实现了按单集群,多集群的批量切换。执行批量切换时可以查看子任务切换的具体步骤,切换后会有前后架构的对比,具体示例如下: 集群1 批量创建任务,选择原则根据先本地后异地,先连接数后QPS,10.66.66.66:3366选择目标主库为:10.88.88.89:3366。 批量执行切换: 切换子任务详细信息,可查看到每个子任务的切换结果,执行步骤及前后架构: 京东MySQL数据库切换系统各功能模块都已组件化、服务简化了DBA的操作流程,缩短了数据库切换的时间。 5、数据库自动化备份恢复 (1)架构设计 京东数据库备份系统在设计之初,就是为了将DBA从繁杂的备份管理工作中解脱出来,实现自动处理,减少人为干预,并提高备份文件的可用性。关于备份文件可用性问题,以轮询恢复的策略确保每个集群在一个周期内都被恢复到。系统架构设计如下图所示: 架构具备以下几个特点: 调度触发多样化 调度中心支持三种类型的触发方式interval、crontab和date: interval是周期调度,可以指定固定间隔时长的任务调度,支持时间单位有weeks、days、hours、minutes、seconds,并支持设定调度开始时间和结束时间以及时区设置。 crontab是定时调度,与Linux的crontab基本相同,支持year、month、day、week、day_of_week、hour、minute、second,并且支持设置调度开始时间和结束时间以及时区设置。 date是一次性定时调度,支持时区设置。 并发控制 由于调度任务设置具有不均衡性,可能某一时刻需要调度的任务较多,容易引起调度系统出现问题,因此执行任务通过控制并发数来使任务调度执行运行更加平稳。 触发和执行分层 任务触发本身是轻量级集的,而任务执行一般都比较重,因此对触发和执行进行了分层设计,来防止因为执行时间过长导致后续触发出现问题。 维护期间任务不丢失

[深入理解Redis]读取RDB文件

最近在做一个解析rdb文件的功能,途中遇到了一些问题,也解决了一些问题。具体为什么要做这件事情之后再详谈,本次主要想聊聊遇到的开始处理文件时遇到的第一个难题:理解RDB文件的协议、如何读取二进制文件。 RDB文件 [Redis源码阅读]redis持久化 文章介绍过,Redis的持久化是通过RDB和AOF实现的。Redis的RDB文件是二进制格式的文件,从这个方面再次体现了Redis是基于内存的缓存数据库,不管对于存储到硬盘还是恢复数据都十分快捷。Redis有多种数据类型:string、list、hash、set、zset,不同数据类型占用的内存大小是不一样的,解析出自然语言可以识别的数据就需要使用不同的方法,保存到文件的时候也需要一些协议或者规则。这有点类似于编程语言里面的数据类型,不同的数据类型占用的字节大小不一致,但是保存到计算机都是二进制的编码,就看是读取多少个字节,以怎样的方式解读。 举个例子,redis的对象类型是特定的几个字符表示,0代表字符串,读取到字符串类型后,紧接着就是字符串的长度,保存着接下来需要读取的字节大小,读取到的字节最终构成完整字符串对象的值。对于保存了"name" => "hoohack"键值对的字符串对象保存到内存可以用下图表示: 当然,除了字符串,redis还有列表,集合,哈希等各种对象,针对这些类型,在RDB文件里面都有不同的规则定义,只需要按照RDB文件格式的协议来解读文件,就能完整无误地把文件解读成自然语言能描述的字符。 仔细对比,可以发现跟计算机的操作方式是类似的,数据保存在计算机都是二进制的,具体的值应该看需要多少个字节,以什么类型解析,读取不同的字节解析到的值是不一样的,同样的字节大小,但是使用不同类型保存,只要做适当的转换,也是正确的。比如在C语言中的void *指针是4个字节,int也是4个字节,定义一个int整数,将它保存到void *也是没问题的,读取的时候只需要做一次类型转换就可以了。 因此,解读RDB文件最关键的就是理解RDB文件的协议,只要理解完RDB文件格式的协议,根据定义好的协议来解析各种数据类型的数据。更详细的RDB文件协议可以参考RDB文件格式的定义文档:RDB file format。 查看RDB文件 先清空redis数据库,保存一个键值对,然后执行save命令将当前数据库的数据保存的rdb文件,得到文件dump.rdb。 127.0.0.1:6379> flushall OK 127.0.0.1:6379> set name hoohack OK 127.0.0.1:6379> save OK 复制代码 cat查看文件: 可以看到是一个包含乱码的文件,因为文件是以二进制的格式保存,要想打印出人类能看出的语言,可以通过linux的od命令查看。od命令用于输出文件的八进制、十六进制或其他格式编码的字节,通常用于输出文件中不能直接显示在终端的字符,注意输出的是字节,分隔符之间的字符都是保存在一个字节的。 od命令输出文件八进制、十六进制等格式 通过man手册可以看到,打印出16进制格式的参数是x,字符是c,将字符与十六进制的对应关系打印出来:od -A x -t x1c -v dump.rdb 打印得出结果如下: 从上图看到,文件打印出来的都是一些十六进制的数字,转换成十进制再去ASCII码表就能查找到对应的字符。比如第一个字符,52=5*16+2*1=82='R'。 在这里说一句,个人觉得这od命令非常有用,在解析数据出现疑惑的时候,就是通过这个命令排查遇到的问题。把文件内容打印出来,找到当前读取的字符,对比RDB文件协议,看看究竟要解析的是什么数据,再对比代码中的解析逻辑,看看是否有问题,然后再修正代码。 如果觉得敲命令麻烦,可以把文件上传然后在线查看:www.onlinehexeditor.com 数据的二进制保存和读取 我们知道,计算机的所有数据都是以二进制的格式保存的,我们看到的字符是通过读取二进制然后解析出来的数据,程序根据不同数据类型做相应的转换,然后展示出来的就是我们看到的字符。 计算机允许多种数据类型,比如有:32位整数、64位整数、字符串、浮点数、布尔值等等,不同的数据类型是通过读取不同大小的字节,根据类型指定的读取方式读取出来,就是想要的数据了。 解析数据的第一步,就是读取数据。在计算机里面,大家所知道的数据都是逐个字节地读取数据。因此,首先要实现的就是按照字节去读取文件。 本次采用实现的解析RDB文件功能的语言是Golang,在Golang的文件操作的API里,提供了按字节读取的函数File.ReadAt。 函数原型如下: func (f *File) ReadAt(b []byte, off int64) (n int, err error) 复制代码 函数从File指针的指向的位置off开始,读取len(b)个字节的数据,并保存到b中。 根据对API的理解,自己实现了一个按照字节读取文件数据的函数,函数接收长度值,代表需要读取的字节长度。具体实现代码如下: type Rdb struct { fp *os.File ... // other field } func (r *Rdb) ReadBuf(length int64) ([]byte, error) { // 初始化一个大小为length的字节数组 buf := make([]byte, length) // 从curIndex开始读取length个字节 size, err := r.

Can驱动芯片MCP2515如何实现位定时功能详解(使用的为8Mhz的晶振,波特率为什么不能达到1Mhz)

在最近的一次项目中,使用到了SPI转CAN芯片MCP2515,此芯片通过SPI转CAN的接收与发送功能。初期看DataSheet时真是一脸懵逼,经过在网上看了一下教学视频,以及慢慢的研究最后才算搞清楚基本的用法以及理解里面各个寄存器的作用。 如果有同学不怎么会使用MCP2515却又不想看那么多页的DataSheet的,可以看以下的教学视频,你就可以了解大概怎么操作的。这个是众想科技出品的视频,里面有相关的MCP2515的驱动视频,您可查看http://www.zxkjmcu.com/。 我在百度传课也看过他们关于STM32部分的CAN视频。https://chuanke.baidu.com/v3322640-160883-676747.html 说了这么多,那就进入今天的主题吧! 一下内容都是是针对MCP2515芯片的。 1.位定时 CAN总线上的所有节点都必须具有相同的标称比特率。CAN 协议采用不归零( Non Return to Zero, NRZ)编码方式,在数据流中不对时钟信号进行编码。因此,接收时钟信号必须由接收节点恢复并与发送器的时钟同步。由于不同节点的振荡器频率和传输时间不同,接收器应具有某种能与数据传输边沿同步的锁相环( Phase LockLoop, PLL)来同步时钟并保持这种同步。鉴于数据采用 NRZ 编码,有必要进行位填充以确保至少每 6 位时间发生一次边沿,使数字锁相环 ( Digital Phase LockLoop, DPLL)同步。MCP2515 通过 DPLL 实现位定时。 DPLL 被配置成同输入数据同步,并为发送数据提供标称定时。 DPLL 将每一 个 位 时 间 分 割 为 由 最 小 单 位 为 时 间 份 额 ( TimeQuanta, TQ)所组成的多个时间段。在位时间帧中执行的总线定时功能,例如与本地振荡器同步、网络传输延迟补偿和采样点定位等,都是由DPLL 的可编程位定时逻辑来规定的。 2. CAN 位时间 CAN 总线上的所有器件都必须使用相同的比特率。然而,并非所有器件都要求具有相同的主振荡器时钟频率。对于采用不同时钟频率的器件,应通过适当设置波特率预分频比以及每一时间段中的时间份额的数量来对比特率进行调整。CAN位时间由互不重叠的时间段组成。 每个时间段又由时间份额 (TQ)组成,在本数据手册的后面部分将对此进行解释。在 CAN 规范中,标称比特率 (NominalBit Rate, NBR)定义为在不需要再同步的情况下,理想发送器每秒发送的位数,它可用下面的公式来表示: 标称位时间: 标称位时间 (Nominal Bit Time, NBT)( tbit)由互不重叠的段时间段组成(图-2) 。因此 NBT 为下列时间 段之和: 以上一个标称位时间,你可以理解为一个一定频率高电平或者一个低电平,它们里面分了如下几段,是为了能够精准的采样到总线上的数据,这个应该是硬件支持的,咱们不多做研究。

yum无法安装软件包

如下所示,显示yum安装服务时程序被占用 解决方法: 结束占用进程的pid号:kill -9 36981

mysql(重点)不看你就后悔吧

mysql(重点) 1:Mysql的安装(参考文档) mysql卸载 https://blog.csdn.net/cxy_summer/article/details/70142322 Mysql(数据库)的基本概念MySql常用命令以及基础操作MySql查询语句; 2:什么是数据库database 数据库就是一个存放数据的仓库; 存放的是什么:文字,声音,视频,图片。。。 要求:这些数据时有关联的,并且是按照一定格式来存放的; 3:数据库管理系统 dbms databasemanagerSystem Crud c create r read u update d delete 4:数据库系统 5:数据模型 数据库管理系统根据数据模型对数据进行存储和管理,数据库管理系统采用的数据模型主要有层次模型、网状模型和关系模型。 5.1层次模型 5.2网状模型 5.3关系模型 以excel表格形式(行和列的形式)来存储数据的模型就是关系模型; 其中每一行被称为一条记录,每一列被称为一个字段,表格的标题被称为字段名; 现在流行的数据库管理系统大多采用关系模型进行数据的组织和管理,因为按关系模型组织的数据表达方式简洁、直观,插入、删除、修改操作方便,而按层次、网状模型组织的数据表达方式复杂,插入、删除、修改操作复杂。因此关系型数据库得以广泛的应用,如Oracle、MySQL、SQLServer、DB2等。 关系型数据库的标准语言是SQL(Structured Query Language,结构化查询语言) SQL语言的功能包括4个部分 数据查询(select) 数据操纵(delete/update/insert) 数据定义(create/alter/drop) 数据控制(grant/revoke) :5.3.1常见的关系型数据库: Mysql , Oracle ,sqlServer , DB2 , 5.3.2Sql数据库 (安全可靠) 依靠sql语句进行操作的数据库 ; 5.3.3NoSql数据库 (高效) 不依赖sql语句来操作的数据库; 主要是用来做缓存的; redis mgdb 6:!!! :7:Mysql的常用命令 7.1打开mysql Linux上: Mysql -u用户名 -p密码 或者: Mysql -u用户名 -p EntryPassword: 密码

c#后台弹出框

ClientScript.RegisterStartupScript(this.GetType(), "message", "<script>alert('提交成功');</script>"); 转载于:https://www.cnblogs.com/lacey/p/9466341.html

C#中Panel控件的使用

大家在创建winform的时候,是不是很多时候都需要建立父窗体,然后再父窗体基础上添加子窗体,然后再单击事件的时候还有可能弹出好多的窗口,今天给大家带来有关panel控件福利。 Panel控件相当于在我们主窗体中添加了一个容器,通过这个容器把我们需要用的控件直接在这个容器中显示,当然也包括我们的窗体,这样每次单击事件就只有这一个窗体中的控件内容在变化。 (有关panel和子父窗体各有各的好处也各有各的不方便,具体小编不在这里多加评论,世界给了你多种选择,哪种开心选哪种) 对于Panel和GroupBox相比,Panel有滚动条而GroupBox没有 首先在我们的工具箱中找到Panel控件并将它添加在父窗体中 如图是我机房中主窗体的构造: 有关于panel的使用 private void btnSearchUpInfo_Click(object sender, EventArgs e) { this.panel2.Controls.Clear(); frmStuSearchUpInfo frmstusearch = new frmStuSearchUpInfo(); frmstusearch.Dock = System.Windows.Forms.DockStyle.Fill; frmstusearch.FormBorderStyle = FormBorderStyle.None; this.panel2.Controls.Add(frmstusearch); frmstusearch.Show(); } 但是这样会报一个错误 也就是我们的控件中添加置顶窗体了,这时我们就要将期属性设置为否 frmstusearch.TopLevel = false; 但是我们在使用过程中又发现了一些问题:例如窗体的位置问题,怎么设置窗体最大化,那么请继续看下去,也会给出相应的解决办法,(如果解决办法出现问题还望大佬多多指点,万分感谢!) //将窗口最大化,并去掉边界 this.FormBorderStyle = FormBorderStyle.None; this.WindowState = FormWindowState.Maximized; this.pl_play.Dock = DockStyle.Fill; //隐藏掉工具栏 this.ms_player.Visible = false; this.ts_player.Visible = false; this.pl_player_bottom.Visible = false; //将panel大小设为设备窗口大小 this.pl_play.Height = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Size.Height; 还有一个解决Winform Panel动态加载Form页wufa无法跟随Panel最大化问题(希望可以用,如果有问题,还希望大家多多指点) Private void ShowForm(Form frm) { frm.MaximizeBox=true; frm.TopLevel=false; frm.FormBordeStyle=FormBorderStyle.None; frm.

cloudera-manager.repo https问题

故障现象: 内部网络安装过程中报如下错误: https://archive.cloudera.com/cm5/redhat/6/x86_64/cm/5.13.3/repodata/repomd.xml: [Errno 14] Peer cert cannot be verified or peer cert invalid Trying other mirror. Error: Cannot retrieve repository metadata (repomd.xml) for repository: cloudera-manager. Please verify its path and try again 故障原因: CM默认生成的cloudera-manager.repo是https的url,导致认证失败。 [root@namenode1 yum.repos.d]# cat cloudera-manager.repo [cloudera-manager] name = Cloudera Manager, Version 5.13.3 baseurl = https://archive.cloudera.com/cm5/redhat/6/x86_64/cm/5.13.3/ gpgkey = https://archive.cloudera.com/redhat/cdh/RPM-GPG-KEY-cloudera gpgcheck = 1 解决思路: 1、Apache httpd服务器上,安装mod_ssl,执行命令 yum -y install mod_ssl 然后重启 httpd服务 2、在本地的yum配置中关闭ssl校验 编辑:/etc/yum.conf 添加: sslverify=false

A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_in

某日在捣鼓pandas时发生了warning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead 意思是一个值正被赋给来自于DataFrame类型的切片的拷贝,使用.loc方法来赋值。 遂研究了下,感觉很奇怪 In [233]: import pandas as pd In [234]: A = pd.DataFrame([[1,2,3], [7,8,9],[14,15,16]], columns = ['a', 'b', 'c']) In [235]: A Out[235]: a b c 0 1 2 3 1 7 8 9 2 14 15 16 把A的第一列赋值给B,B是Series对象,修改B的某一个数发现A也被修改了 In [236]: B = A['a'] In [237]: B Out[237]: 0 1 1 7 2 14 Name: a, dtype: int64 In [238]: type(B) Out[238]: pandas.

RabbitMQ学习(六)——消息确认机制(Confirm模式)

在上一篇文章中我们讲解了RabbitMQ中的AMQP事务来保证消息发送到Broker端,同时我们可以在事务之间发送多条消息(即在channel.txSelect()和channel.txCommit()之间发送多条消息,通过使用事务来保证它们准确到达Broker),如果忘记了事务的使用,可以复习一下上一篇文章——RabbitMQ学习(五)——消息确认机制(AMQP事务)。 但是使用事务虽然可以保证消息的准确达到,但是它极大地牺牲了性能,因此我们为了性能上的要求,可以采用另一种高效的解决方案——通过使用Confirm模式来保证消息的准确性。 这里的Confirm模式可以分为两个方面来讲解,一是消息的生产者(Producer)的Confirm模式,另一个是消息的消费者(Consumer)的Confirm模式。其实这两种模式在前面几节的代码里我们都有涉及到的,只是没有详细分析,这里我们将详细讲解一下它们的具体用法和原理。 一、生产者(Producer)的Confirm模式 通过生产者的确认模式我们是要保证消息准确达到Broker端,而与AMQP事务不同的是Confirm是针对一条消息的,而事务是可以针对多条消息的。 发送原理图大致如下: 为了使用Confirm模式,client会发送confirm.select方法帧。通过是否设置了no-wait属性,来决定Broker端是否会以confirm.select-ok来进行应答。一旦在channel上使用confirm.select方法,channel就将处于Confirm模式。处于 transactional模式的channel不能再被设置成Confirm模式,反之亦然。 这里与前面的一些文章介绍的一致,发布确认和事务两者不可同时引入,channel一旦设置为Confirm模式就不能为事务模式,为事务模式就不能为Confirm模式。 在生产者将信道设置成Confirm模式,一旦信道进入Confirm模式,所有在该信道上面发布的消息都会被指派一个唯一的ID(以confirm.select为基础从1开始计数),一旦消息被投递到所有匹配的队列之后,Broker就会发送一个确认给生产者(包含消息的唯一ID),这就使得生产者知道消息已经正确到达目的队列了,如果消息和队列是可持久化的,那么确认消息会将消息写入磁盘之后发出,Broker回传给生产者的确认消息中deliver-tag域包含了确认消息的序列号,此外Broker也可以设置basic.ack的multiple域,表示到这个序列号之前的所有消息都已经得到了处理。 Confirm模式最大的好处在于它是异步的,一旦发布一条消息,生产者应用程序就可以在等信道返回确认的同时继续发送下一条消息,当消息最终得到确认之后,生产者应用便可以通过回调方法来处理该确认消息,如果RabbitMQ因为自身内部错误导致消息丢失,就会发送一条basic.nack来代替basic.ack的消息,在这个情形下,basic.nack中各域值的含义与basic.ack中相应各域含义是相同的,同时requeue域的值应该被忽略。通过nack一条或多条消息, Broker表明自身无法对相应消息完成处理,并拒绝为这些消息的处理负责。在这种情况下,client可以选择将消息re-publish。 在channel 被设置成Confirm模式之后,所有被publish的后续消息都将被Confirm(即 ack)或者被nack一次。但是没有对消息被Confirm的快慢做任何保证,并且同一条消息不会既被Confirm又被nack。 开启confirm模式的方法 生产者通过调用channel的confirmSelect方法将channel设置为Confirm模式,如果没有设置no-wait标志的话,Broker会返回confirm.select-ok表示同意发送者将当前channel信道设置为Confirm模式(从目前RabbitMQ最新版本3.6来看,如果调用了channel.confirmSelect方法,默认情况下是直接将no-wait设置成false的,也就是默认情况下broker是必须回传confirm.select-ok的)。 编程模式 对于固定消息体大小和线程数,如果消息持久化,生产者Confirm(或者采用事务机制),消费者ack那么对性能有很大的影响. 消息持久化的优化没有太好方法,用更好的物理存储(SAS, SSD, RAID卡)总会带来改善。生产者confirm这一环节的优化则主要在于客户端程序的优化之上。归纳起来,客户端实现生产者confirm有三种编程方式: 普通Confirm模式:每发送一条消息后,调用waitForConfirms()方法,等待服务器端Confirm。实际上是一种串行Confirm了,每publish一条消息之后就等待服务端Confirm,如果服务端返回false或者超时时间内未返回,客户端进行消息重传;批量Confirm模式:批量Confirm模式,每发送一批消息之后,调用waitForConfirms()方法,等待服务端Confirm,这种批量确认的模式极大的提高了Confirm效率,但是如果一旦出现Confirm返回false或者超时的情况,客户端需要将这一批次的消息全部重发,这会带来明显的重复消息,如果这种情况频繁发生的话,效率也会不升反降;异步Confirm模式:提供一个回调方法,服务端Confirm了一条或者多条消息后Client端会回调这个方法。 1、普通Confirm模式 主要代码为: channel.basicPublish("", QUEUE_NAME, MessageProperties.PERSISTENT_BASIC, (" Confirm模式, 第" + (i + 1) + "条消息").getBytes()); if (channel.waitForConfirms()) { System.out.println("发送成功"); }else{ //进行消息重发 } 普通Confirm模式最简单,publish一条消息后,等待服务器端Confirm,如果服务端返回false或者超时时间内未返回,客户端就进行消息重传。 我们还是结合代码来讲解,下载原来的代码 rabbitmq-demo,然后在sender和receiver中分别新建代码ConfirmSender1.java和ConfirmReceiver1.java。 ConfirmSender1.java: package net.anumbrella.rabbitmq.sender; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.MessageProperties; import org.apache.commons.lang.StringUtils; import org.springframework.amqp.core.AmqpTemplate; import org.springframework.beans.factory.annotation.Autowired; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * 这是java原生类支持RabbitMQ,直接运行该类 */ public class ConfirmSender1 { private final static String QUEUE_NAME = "

opencv入门书籍推荐 opencv-Python书籍推荐

opencv入门书籍入门推荐: 1. OpenCV3编程入门_毛星云编著_电子工业出版 最好的opencv入门书籍之一,通过实际代码与原理解释opencv知识。使用编程环境为:vs+opencv+contrib,使用语言 c++; CSDN pdf电子版:https://download.csdn.net/download/harrison509/10554475 (建议入手实体书) 2. Opencv3机器视觉Python语言实现_刘波 市面上少见的Python语言版本Opencv入门书籍,从实际代码出发,简述理论,是一门较好的工程开发入门书籍; 使用编程环境:Python+opencv+contrib CSDN pdf电子版:https://download.csdn.net/download/harrison509/10572682(建议入手实体书) 如果工程和人工智能、深度学习联系紧密,建议先看第一本书籍(浅陌),了解jich基础知识后再看第二本Python版本。 推荐一本简易Python入门书籍:Python编程:从入门到实践 白话文编写,通俗易懂,幽默风趣,适合毫无编程经验的初学者 CSDN pdf电子版:https://download.csdn.net/download/harrison509/10572555

LeetCode 455. 分发饼干

题目描述: 分发饼干 给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。 示例 1: 输入: 2 输出: [0,1,1] 示例 2: 输入: 5 输出: [0,1,1,2,1,2] 进阶: 给出时间复杂度为O(n*sizeof(integer))的解答非常容易。但你可以在线性时间O(n)内用一趟扫描做到吗?要求算法的空间复杂度为O(n)。你能进一步完善解法吗?要求在C++或任何其他语言中不使用任何内置函数(如 C++ 中的 __builtin_popcount)来执行此操作。 解题思路: 设i的二进制后缀有n个连续的1,则v[i+1] = v[i] - n + 1。 代码: class Solution { public: vector<int> countBits(int num) { vector<int> v; v.push_back(0); for(int i = 0 ; i < num ; i ++){ int n = i; v.push_back(v[i]); while(n%2 == 1){ n = n/2; v[i+1]--; } v[i+1] ++; } return v; } };

Vue源码学习之callHook钩子函数

Vue实例在不同的生命周期阶段,都调用了callHook方法。比如在实例初始化(_init)的时候调用callHook(vm, 'beforeCreate')和callHook(vm, 'created')。 这里的"beforeCreate","created"状态并非随意定义,而是来自于Vue内部的定义的生命周期钩子。 var LIFECYCLE_HOOKS = [ 'beforeCreate', 'created', 'beforeMount', 'mounted', 'beforeUpdate', 'updated', 'beforeDestroy', 'destroyed', 'activated', 'deactivated', 'errorCaptured' ]; 再研究Vue官网的生命周期图示,是不是更容易理解了。 接下来我们来看一下Vue中实现钩子函数的源码: function callHook (vm, hook) { // #7573 disable dep collection when invoking lifecycle hooks pushTarget(); var handlers = vm.$options[hook]; if (handlers) { for (var i = 0, j = handlers.length; i < j; i++) { try { handlers[i].call(vm); } catch (e) { handleError(e, vm, (hook + " hook"

关于Vue中props的详解

看一下官方文档: 组件实例的作用域是孤立的。这意味着不能 (也不应该) 在子组件的模板内直接引用父组件的数据。父组件的数据需要通过 prop 才能下发到子组件中。 也就是props是子组件访问父组件数据的唯一接口。 详细一点解释就是: 一个组件可以直接在模板里面渲染data里面的数据(双大括号)。 子组件不能直接在模板里面渲染父元素的数据。 如果子组件想要引用父元素的数据,那么就在prop里面声明一个变量(比如a),这个变量就可以引用父元素的数据。然后在模板里渲染这个变量(前面的a),这时候渲染出来的就是父元素里面的数据。 1. 基本用法 图1-props <div id="app1"> <!-- hello引用父元素的hello,它也可以引用message,greet,world等 --> <child :hello='hello'></child> </div> <script> var com1 = Vue.component('child',{ // 声明在prop中的变量可以引用父元素的数据 props:['hello'], // 这里渲染props中声明的那个hello template:'<div><p>{{ hello }}</p></div>', }) var app1 = new Vue ({ el: '#app1', data: { greet: { hello:'hello,', world: 'world', }, message: 'message1', } }) </script> 2. camelCase vs. kebab-case:js中用驼峰式命名,在html中替换成短横线分隔式命名 <!-- 在 HTML 中使用 kebab-case --> <child my-message="hello!"></child> <script> Vue.