头像

大菜狗

太原理工大学




离线:1天前


最近来访(1178)
用户头像
Acwer
用户头像
violet_garden
用户头像
莉亚
用户头像
dafangtou
用户头像
玛卡玛卡
用户头像
chenjx529
用户头像
ruidongtd1996
用户头像
叔叔糖掉了
用户头像
selfknow
用户头像
卷心菜的卷
用户头像
RyanMoriarty
用户头像
淼淼_5
用户头像
大伟老师的亲传弟子
用户头像
YzWait2-4YsZth
用户头像
QLW
用户头像
郫县林俊杰
用户头像
-浪漫主义狗-
用户头像
霹雳暴龙战士
用户头像
_blank
用户头像
Lytics


大菜狗
11天前

考研题目




大菜狗
1个月前

各数据类型的范围与精度

基本类型 字节数 位数 取值范围(二进制) 取值范围(十进制) 大概范围(十进制) 精度(取决于尾数的范围)
byte 1 byte 8 bit $-2^7$ ~ $2^7 - 1$ $-128$ ~ $+127$
short 2byte 16bit $-2^ $-32767$ ~ $+32768$ $3.2*10^4$
int 4byte 32bit $-2^ $-2147483648$ ~ $+2147483647$ $2.1*10^9$
unsigned int 4byte 32bit $0$ ~ $2^ $0$ ~ $4294967295$ $4.3*10^9$
long long 8byte 64bit $-2^ $-9223372036854775808$ ~ $+9223372036854775807$ $9.2*10^
unsigned long long 8byte 64bit $0$ ~ $2^ $0$ ~ $18446744073709551615$ $1.8*10^
float 4byte 32bit $-3.402823466×10^ $10^
double 8byte 64bit $1.7976931348623157*10^ $10^
char 2byte 16bit $0$ ~ $2^



大菜狗
3个月前

网络带宽相关知识和计算

*一、带宽*

带宽应用的领域非常多,可以用来标识信号传输的数据传输能力、标识单位时间内通过链路的数据量、标识显示器的显示能力。

\1. 在模拟信号系统又叫频宽,是指在固定的时间可传输的资料数量,亦即在传输管道中可以传递数据的能力。通常以每秒传送周期或赫兹(Hz)来表示。

\2. 在数字设备中,带宽指单位时间能通过链路的数据量。通常以bps来表示,即每秒可传输之位数。

  • 带宽在计算机系统中的意义

在计算机系统中,用带宽作为标识总线和内存性能的指标之一。

总线带宽指的是总线在单位时间内可以传输的数据总量,等于总线位宽工作频率的乘积。例如:对于64位、800MHz的前端总线,它的数据传输率就等于64bit×800MHz÷8(Byte)=6.4GB/s

内存带宽指的是内存总线所能提供的数据传输能力。例如:DDR400内存的数据传输频率为400MHz,那么单条模组就拥有64bit×400MHz÷8(Byte)=3.2GB/s的带宽。

带宽的应用

一、表示频带宽度

信号的带宽是指该信号所包含的各种不同频率成分所占据的频率范围频宽对基本输出入系统 (BIOS ) 设备尤其重要,如快速磁盘驱动器会受低频宽的总线所阻碍。

二、表示通信线路所能传送数据的能力

带宽带宽

在单位时间内从网络中的某一点到另一点所能通过的“最高数据率”。对于带宽的概念,比较形象的一个比喻是高速公路。单位时间内能够在线路上传送的数据量,常用的单位是bps(bit per second)。计算机网络的带宽是指网络可通过的最高数据率,即每秒多少比特

严格来说,数字网络的带宽应使用波特率来表示(baud),表示每秒的脉冲数。而比特是信息单位,由于数字设备使用二进制,则每位电平所承载的信息量是以2为底2的对数,如果是四进制,则是以2为底的4的对数,每位电平所承载的信息量为2。因此,在数值上,波特与比特是相同的。由于人们对这两个概念分的并不是很清楚,因此常使用比特率来表示速率,也正是用比特的人太多,所以比特率也就成了一个带宽事实的标准叫法了。

img

bit/s=1Kbit/s

img

bit/s=1Mbit/s

img

bit/s=1Gbit/s

描述带宽时常常把“比特/秒”省略。例如,带宽是1M,实际上是1Mbps,这里的Mbps是指兆位/s。

在网络中有两种不同的速率:

1、信号(即电磁波)在传输媒体上的传播速率(米/秒,或公里/秒)。

2、计算机向网络发送比特的速率(比特/秒)。

这两种速率的意义和单位完全不同。

在理解带宽这个概念之前,我们首先来看一个公式:带宽=时钟频率x总线位数/8,从公式中我们可以看到,带宽和时钟频率、总线位数是有着非常密切的关系的。其实在一个计算机系统中,不仅显示器、内存有带宽的概念,在一块板卡上,带宽的概念就更多了,完全可以说是带宽无处不在。

那到底什么是带宽呢?带宽的意义又是什么?为了更形象地理解带宽、位宽时钟频率的关系,我们举个比较形象的例子,工人加工零件,如果一个人干,在大家单个加工速度相同的情况下,肯定不如两个人干的多,带宽就像是工人能够加工零件的总数量,位宽仿佛工人数量,时钟工作频率相当于加工单个零件的速度,位宽越宽,时钟频率越高则总线带宽越大,其好处也是显而易见的。

主板上通常会有两块比较大的芯片,一般将靠近CPU的那块称为北桥,远离CPU的称为南桥北桥的作用是在CPU与内存显卡之间建立通信接口,它们与北桥连接的带宽大小很大程度上决定着内存与显卡效能的大小。南桥是负责计算机的I/O设备、PCI设备和硬盘,对带宽的要求,相比较北桥而言,是要小一些的。而南北桥之间的连接带宽一般就称为南北桥带宽。随着计算机越来越向多媒体方向发展,南桥的功能也日益强大,对于南北桥间的连接总线带宽也是提出了新的要求,在INTEL的9X5系列主板上,南北桥的带宽将从以前一直为人所诟病的266MB/S发展到空前的2GB/S,一举解决了南北桥间的带宽瓶颈

带宽带宽

显卡中的带宽

再来说说显卡,玩游戏的朋友都知道,当玩一些大制作游戏的时候,画面有时候会卡的比较厉害。其实这就是显卡带宽不足的问题,再具体点说,这是显存带宽不足。众所周知,当道的AGP接口是AGP 8X,而AGP总线的频率是PCI总线的两倍,也就是266MHz,很容易就可以换算出它的带宽是2.1Gbps,这样的带宽就显得很微不足道了,因为连最普通的ATI R9000的显存带宽都要达到400MHz*128Bit/8=6.4GB/s,其余的高端显卡更是不用说了。正因为如此,INTEL在最新的9X5芯片组中,采用了PCI-Express总线来替代老态龙钟的AGP总线,与传统PCI以及更早期的计算机总线的共享并行架构相比,PCI Express最大的特点是在设备间采用点对点串行连接,如此一来即允许每个设备都有自己的专用连接,不需要向整个总线请求带宽,同时利用串行的连接特点将能轻松将数据传输速度提到一个很高的频率。在传输速度上,由于PCI Express支持双向传输模式,因此连接的每个装置都可以使用最大带宽。AGP所遇到的带宽瓶颈也迎刃而解。

带宽带宽

总线中的带宽

计算机系统中,总线的作用就好比是人体中的神经系统,它承担的是所有数据传输的职责,而各个子系统间都必须籍由总线才能通讯,例如,CPU和北桥间有前端总线、北桥与显卡间为AGP总线、芯片组间有南北桥总线,各类扩展设备通过PCI、PCI-X总线与系统连接;主机外部设备的连接也是通过总线进行,流行的USB2.0、IEEE1394总线等等,一句话,在一部计算机系统内,所有数据交换的需求都必须通过总线来实现!

按照工作模式不同,总线可分为两种类型,一种是并行总线,它在同一时刻可以传输多位数据,好比是一条允许多辆车并排开的宽敞道路,而且它还有双向单向之分;另一种为串行总线,它在同一时刻只能传输一个数据,好比只容许一辆车行走的狭窄道路,数据必须一个接一个传输、看起来仿佛一个长长的数据串,故称为“串行”。

对串行总线来说,带宽工作频率的概念与并行总线完全相同,只是它改变了传统意义上的总线位宽的概念。在频率相同的情况下,并行总线比串行总线快得多,但它存在并行传输信号间的干扰现象,频率越高、位宽越大,干扰就越严重,因此要大幅提高现有并行总线的带宽是非常困难的;而串行总线不存在这个问题,总线频率可以大幅向上提升,这样串行总线就可以凭借高频率的优势获得高带宽。而为了弥补一次只能传送一位数据的不足,串行总线常常采用多条管线(或通道)的做法实现更高的速度——管线之间各自独立,多条管线组成一条总线系统,从表面看来它和并行总线很类似,但在内部它是以串行原理运作的。对这类总线,带宽的计算公式就等于“总线频率×管线数”,这方面的例子有PCIExpress和HyperTransport,前者有×1、×2、×4、×8、×16和×32多个版本,在第一代PCIExpress技术当中,单通道的单向信号频率可达2.5GHz,我们以×16举例,这里的16就代表16对双向总线,一共64条线路,每4条线路组成一个通道,二条接收,二条发送。这样我们可以换算出其总线的带宽为2.5GHz×16/10=4GB/s(单向)。除10是因为每字节采用10位编码

并行总线和串行总线的描述参数存在一定差别。对并行总线来说,描述的性能参数有以下三个:总线宽度、时钟频率、数据传输频率。其中,总线宽度就是该总线可同时传输数据的位数,好比是车道容许并排行走的车辆的数量;例如,16位总线在同一时刻传输的数据为16位,也就是2个字节;而32位总线可同时传输4个字节,64位总线可以同时传输8个字节......显然,总线的宽度越大,它在同一时刻就能够传输更多的数据。不过总线的位宽无法无限制增加。

总线的带宽指的是这条总线在单位时间内可以传输的数据总量,它等于总线位宽工作频率的乘积。例如,对于64位、800MHz的前端总线,它的数据传输率就等于64bit×800MHz÷8(Byte)=6.4GB/s;32位、33MHzPCI总线的数据传输率就是32bit×33MHz÷8=133MB/s,等等,这项法则可以用于所有并行总线上面——看到这里,读者应该明白我们所说的总线带宽指的就是它的数据传输率,其实“总线带宽”的概念同“电路带宽”的原始概念已经风马牛不相及

带宽带宽

内存中的带宽

总线之外,内存也存在类似的带宽概念。其实所谓的内存带宽,指的也就是内存总线所能提供的数据传输能力,但它决定于内存芯片内存模组而非纯粹的总线设计,加上地位重要,往往作为单独的对象讨论。

SDRAM、DDR和DDRⅡ的总线位宽为64位,RDRAM的位宽为16位。而这两者在结构上有很大区别:SDRAM、DDR和DDRⅡ的64位总线必须由多枚芯片共同实现,计算方法如下:内存模组位宽=内存芯片位宽×单面芯片数量(假定为单面单物理BANK);如果内存芯片的位宽为8位,那么模组中必须、也只能有8颗芯片,多一枚、少一枚都是不允许的;如果芯片的位宽为4位,模组就必须有16颗芯片才行,显然,为实现更高的模组容量,采用高位宽的芯片是一个好办法。而对RDRAM来说就不是如此,它的内存总线为串联架构,总线位宽就等于内存芯片的位宽。

并行总线一样,内存的带宽等于位宽与数据传输频率的乘积,例如,DDR400内存的数据传输频率为400MHz,那么单条模组就拥有64bit×400MHz÷8(Byte)=3.2GB/s的带宽;PC800标准RDRAM的频率达到800MHz,单条模组带宽为16bit×800MHz÷8=1.6GB/s。为了实现更高的带宽,在内存控制器中使用双通道技术是一个理想的办法,所谓双通道就是让两组内存并行运作,内存的总位宽提高一倍,带宽也随之提高了一倍!带宽可以说是内存性能最主要的标志,业界也以内存带宽作为主要的分类标准,但它并非决定性能的唯一要素,在实际应用,内存延迟的影响并不亚于带宽。如果延迟时间太长的话相当不利,此时即便带宽再高也无济于事。

带宽带宽

带宽匹配的问题

计算机系统中存在形形色色的总线,这不可避免带来总线速度匹配问题,其中最常出问题的地方在于前端总线内存南北桥总线和PCI总线

前端总线与内存匹配与否对整套系统影响最大,最理想的情况是前端总线带宽与内存带宽相等,而且内存延迟要尽可能低。在Pentium4刚推出的时候,Intel采用RDRAM内存以达到同前端总线匹配,但RDRAM成本昂贵,严重影响推广工作,Intel曾推出搭配PC133SDRAM的845芯片组,但SDRAM仅能提供1.06GB/s的带宽,仅相当于400MHz前端总线带宽的1/3,严重不匹配导致系统性能大幅度下降;后来,Intel推出支持DDR266的845D才勉强好转,但仍未实现与前端总线匹配;接着,Intel将P4前端总线提升到533MHz、带宽增长至5.4GB/s,虽然配套芯片组可支持DDR333内存,可也仅能满足1/2而已;P4的前端总线提升到800MHz,而配套的865/875P芯片组可支持双通道DDR400——这个时候才实现匹配的理想状态,当然,这个时候继续提高内存带宽意义就不是特别大,因为它超出了前端总线的接收能力。

南北桥总线带宽曾是一个尖锐的问题,早期的芯片组都是通过PCI总线来连接南北桥,而它所能提供的带宽仅仅只有133MB/s,若南桥连接两个ATA-100硬盘、100M网络、IEEE1394接口......区区133MB/s带宽势必形成严重的瓶颈,为此,各芯片组厂商都发展出不同的南北桥总线方案,如Intel的Hub-Link、VIA的V-Link、SiS的MuTIOL,还有AMD的HyperTransport等等,它们的带宽都大大超过了133MB/s,最高纪录已超过1GB/s,瓶颈效应已不复存在。

PCI总线带宽不足还是比较大的矛盾,PC上使用的PCI总线均为32位、33MHz类型,带宽133MB/s,而这区区133MB/s必须满足网络、硬盘控制卡(如果有的话)之类的扩展需要,一旦使用千兆网络,瓶颈马上出现,业界打算自2004年开始以PCIExpress总线来全面取代PCI总线,届时PCI带宽不足的问题将成为历史。

  • 带宽在数字信号系统中的意义

数字信号系统中,带宽用来标识通讯线路所能传送数据的能力,即在单位时间内通过网络中某一点的最高数据率,常用的单位为bps(又称为比特率—bit per second,每秒多少比特)。在日常生活中中描述带宽时常常把bps省略掉,例如:带宽为4M,完成的称为应为4Mbps。

针对于带宽成本降低,用户接入速率也是越来越高,从最初的拨号上网,到20M甚至100M光纤。

但是随着计算机的发展,用户对‘带宽’的认识也应该有更大的提高。

一般来说,带宽是以 bit(比特)表示,而电信,联通,移动等运营商在推广的时候往往忽略了这个单位。

正常换算情况如下:

1Mbit=128KB

2Mbit=256KB

(以此类推)

而换算后的速度才是您真实上网的速度

也就是说,如果你从你的运营商开通的带宽是10M,那么代入计算公式,以上面换算的1M来计量

则为:

(1M=1024K)

1M/128K=1024/128=8

10/8=1.25M

也就是说你如果开通10M带宽,可以达到最高1.25M的速度

一般来说,一台计算机观看电影,玩游戏等,4M带宽足够。但是如果你需要经常下载大文件,建议还是使用更高带宽。

  • 在模拟信号系统中的意义

在模拟信号系统中,带宽用来标识传输信号所占有的频率宽度,这个宽度由传输信号的最高频率和最低频率决定,两者之差就是带宽值,因此又被称为信号带宽或者载频带宽,单位为Hz。

带宽其实就是信号所占用的频谱的度量,可以看做是一种与空间相关的量。与之相比,信号的传输速率就是一种与空间和时间都相关的物理量,定义为单位时间内在信道上传输的数据量。

为了合理使用频谱资源,国际电信联盟(ITU)为每种通信系统都规定了频率范围,这种频率范围又称为频段,而频段的频谱宽度又被称之为工作带宽。例如GSM的工作带宽为25 MHz,WCDMA和CDMA均为30 MHz。

  • 带宽在人力资源领域中的意义

所谓“带宽”就是指各等级薪资的最大值与最小值之差,又将其成为薪值的分布区间。一般而言,由于职位高低不同,职位或职层所涉及技能与职责的复杂性程度也会有所不同,因此,各职等级的薪资带宽也就应该有所不同(薪资带宽应当能反应一个职位或职层的任职者由一个初入者到能力与业绩十分突出者所需要的难度大小)。如果职位或职层所涉及的技能与职责能在较短时间内得以掌握,则此等级薪资的带宽较窄;而如果职位或职层所涉及的技能和职责需要学习的时间较长,继续提升的机会也较小,则其相应的带宽较大。根据这个理论,变革者在设计职等带宽时应当坚持的原则是:职等越高,其带宽就应越大,因为职等越高,任职者胜任的速度就越慢。

  • 带宽在显示器系统中的意义

在采用正弦输入研究传感器频率动态特性时,常用频率特性和相频特性来描述传感器的动态特性,其重要指标是频带宽度,简称带宽。[1]

带宽(Bandwidth)是显示器视频放大器通频宽度的简称,指的是电子枪在一秒钟内扫描过像素(Pixel)的总个数,即单位时间内所有行(水平方向)扫描线和场(竖直方向)扫描线上显示出的像素个数之总和,单位是MHz。[1]

带宽的详细计算公式: B=r(x) ×r(y) ×V

  • B表示显示器的带宽
  • r(x)表示每条水平扫描线上的图素个数
  • r(y)表示每帧画面的水平扫描线数
  • V 表示每秒画面刷新率(即场频

二、网络带宽相关知识

信道带宽与数据传输速率的关系可以奈奎斯特(Nyquist)准则与香农(Shanon)定律描述。奈奎斯特定理描述了有限带宽、无噪声信道的最大数据传输速率与信道带宽的关系。香农定理则描述了有限带宽、有随机热噪声信道的最大传输速率与信道带宽、信噪比之间的关系。

奈奎斯特准则指出:如果间隔为π/ω(ω=2πf),通过理想通信信道传输窄脉冲信号,则前后码元之间不产生相互窜扰。因此,对于二进制数据信号的最大数据传输速率Rmax与通信信道带宽B(B=f,单位Hz)的关系可以写为:

Rmax=2.f(bps)

香农定理指出:在有随机热噪声的信道上传输数据信号时,数据传输速率Rmax与信道带宽B、信噪比S/N的关系为:

Rmax=B.log2(1+S/N)

式中,Rmax单位为bps,带宽B单位为Hz,信噪比S/N通常以dB(分贝)数表示。

1、数据传输速率R

数据传输速率在数值上等于每秒钟传输构成数据代码的二进制比特数,单位为比特/秒(bit/second),记作bps。对于二进制数据,数据传输速率为:S=1/T(bps)

其中,T为发送每一比特所需要的时间。

常用的数据传输速率单位有:kbps、Mbps和Gbps。其中:1kbps=103bps 1Mbps=106bps 1Gbps=109bps

2、信号传输速率B

B也称码元率、调制速率或波特率,表示单位时间内通过信道传输的码元个数,单位记做BAND。

3、信道带宽W

模拟信道:

模拟信道的带宽 W=f2-f1 其中f1是信道能够通过的最低频率,f2是信道能够通过的最高频率,两者都是由信道的物理特性决定的。当组成信道的电路制成了,信道的带宽就决定了。为了使信号的传输的失真小些,信道要有足够的带宽。

数字信道:

数字信道是一种离散信道,它只能传送离散值的数字信号,信道的带宽决定了信道中能不失真的传输脉序列的最高速率。

一个数字脉冲称为一个码元,我们用码元速率表示单位时间内信号波形的变换次数,即单位时间内通过信道传输的码元个数。若信号码元宽度为T秒,则码元速率B=1/T。码元速率的单位叫波特(Baud),所以码元速率

也叫波特率。

早在1924年,贝尔实验室的研究员亨利·尼奎斯特就推导出了有限带宽无噪声信道的极限波特率,称为尼奎斯特定理。若信道带宽为W,则尼奎斯特定理指出最大码元速率为B=2W(Baud)

尼奎斯特定理指定的信道容量也叫尼奎斯特极限,这是由信道的物理特性决定的。超过尼奎斯特极限传送脉冲信号是不可能的,所以要进一步提高波特率必须改善信道带宽。

码元携带的信息量由码元取的离散值个数决定。若码元取两个离散值,则一个码元携带1比特(bit)信息。若码元可取四种离散值,则一个码元携带2比特信息。总之一个码元携带的信息量n(bit)与码元的种类数N

有如下关系:n=log2N

单位时间内在信道上传送的信息量(比特数)称为数据速率(信息速率)。在一定的波特率下提高速率的途径是用一个码元表示更多的比特数。如果把两比特编码为一个码元,则数据速率可成倍提高。

我们有公式: R=Blog2N=2Wlog2N(b/s)

其中R表示数据速率,单位是每秒比特,简写为bps或b/s

数据速率和波特率是两个不同的概念。仅当码元取两个离散值时两者才相等。

对于普通电话线路,带宽为3000HZ,最高波特率为6000Baud。而最高数据速率可随编码方式的不同而取不同的值。这些都是在无噪声的理想情况下的极限值。实际信道会受到各种噪声的干扰,因而远远达不到按

尼奎斯特定理计算出的数据传送速率。

香农(shannon)的研究表明,有噪声的极限数据速率可由下面的公式计算:

C =W log2(1+s/n)这个公式叫做香农定理,其中C也称为信道容量,W为信道带宽,S为信号的平均功率,N为噪声的平均功率,s/n叫做信噪比。

由于在实际使用中S与N的比值太大,故常取其分贝数(db)。分贝与信噪比的关系为: db=10log10s/n

例如当s/n为1000,信噪比为30db。这个公式与信号取的离散值无关,也就是说无论用什么方式调制,只要给定了信噪比,则单位时间内最大的信息传输量就确定了。

例如信道带宽为3000HZ,信噪比为30db,则最大数据速率为C=3000log2(1+1000)≈3000×9.97≈30000b/s

这是极限值,只有理论上的意义。实际上在3000HZ带宽的电话线上数据速率能达到9600b/s就很不错了。

综上所述,我们有两种带宽的概念,在模拟信道,带宽按照公式W=f2-f1 计算,例如CATV电缆的带宽为600HZ或1000HZ;数字信道的带宽为信道能够达到的最大数据速率,例如以太网的带宽为10MB/S或100MB/S,两者可通过香农定理互相转换。数字信道是一种离散信道,它只能传送离散值的数字信号,信道的带宽决定了信道中能不失真的传输脉序列的最高速率。

4、奈氏准则与香农定理

奈氏准则

1924年,奈奎斯特(Nyquist)就推导出在理想低通信道下的最高码元传输速率的公式:理想低通信道下的最高码元传输速率=2WBaud

其中W是理想低通信道的带宽,单位为赫兹;Baud是波特,即码元传输速率的单位,1波特为每秒传送1个码元。奈氏准则的另一种表达方法是:每赫兹带宽的理想低通信道的最高码元传输速率是每秒2个码元。

若码元的传输速率超过了奈氏准则所给出的数值,则将出现码元之间的互相干扰,以致在接收端就无法正确判定码元是1还是0。对于具有理想带通矩形特性的信道(带宽为W),奈氏准则就变为:理想带通信道的最高码元传输速率=1WBaud,即每赫宽带的带通信道的最高码元传输速率为每秒1个码元。奈氏准则是在理想条件下推导出的。在实际条件下,最高码元传输速率要比理想条件下得出的数值还要小些。电信技术人员的任务就是要在实际条件下,寻找出较好的传输码元波形,将比特转换为较为合适的传输信号。需要注意的是,奈氏准则并没有对信息传输速率(b/s)给出限制。要提高信息传输速率就必须使每一个传输的码元能够代表许多个比特的信息。这就需要有很好的编码技术。

香农公式

1948年,香农(Shannon)用信息论的理论推导出了带宽受限且有噪声干扰的信道的极限信息传输速率。当用次速率进行传输时,以做到不出差错。用公式表示,则信道的极限信息传输速率C可表达为

C=Blog 2(1+S/N)信噪比SNR=S(信号功率)/N(噪声功率) 其中B为信道的宽度,S为信道内所传信号的平均功率,N为信道内部的噪声功率。香农公式表明,信道的带宽或信道中的信噪比越大,则信息的极限传输速率就越高。它给出了信息传输速率的极限,即对于一定的传输带宽(以赫兹为单位)和一定的信噪比,信息传输速率的上限就确定了。这个极限是不能够突破的。要想提高信息的传输速率,或者必须设法提高传输线路的带宽,或者必须设法提高所传信号的信噪比,此外没有其他任何办法。至少到现在为止,还没有听说有谁能够突破香农公式给出的信息传输速率的极限。香农公式告诉我们,若要得到无限大的信息传输速率,只有两个办法:要么使用无限大的传输带宽(这显然不可能),要么使信号的信噪比为无限大,即采用没有噪声的传输信道或使用无限大的发送功率。

三、网络带宽相关计算

1.计算光纤传输的真实速度

使用光纤连接网络具有传输速度快,衰减少等特点。

因此很多公司的网络出口都使用光纤,一般网络服务商声称光纤的速度为“ 5M”,那么他的下载真实速度究竟是多少呢?我们来计算一下,一般的情况下,“5M”实际上就是5000Kbit/s(按千进位计算)这就存在一个换算的问题。Byte和bit是不同的。1Byte=8bit.而我们常说的下载速度都指的是Byte/s 因此电信所说的“5M”经过还换算后就成为了(5000/8)KByte/s=625KByte/s这样我们平时下载速度最高就是625KByte/s常常表示625KB/S。

这里理论计算最高值为625KB/S。在实际的应用中,那么还要排除网络损耗以及线路衰减等因素,因此真正的下载速度可能还不到600KB/S,不过只要是550KB/S以上都算正常。

2.计算内网的传输速度

经常有人抱怨内网的传输的速度慢,那么真实情况下的10/100MBPS网卡的速度应该有多块呢?

网卡的100Mbps同样是以bit/s来定义的,所以100Mb/S=100 000KByte/s=(100 000/8)KByte/s=12 500KByte/s,因此在理论上1秒钟可以传输12.5MB的速率,考虑到干扰的因素每秒传输只要超过10MB就是正常了,现在出现了1000Mbps的网卡那么速度就在100MB/S左右。

3.计算ADSL的真实速度,ADSL是大家经常使用的上网方式,那么电信和网通声称的“512K”ADSL下载速度是多少呢?

换算方法为512Kbit/s=(512/8)KByte/s=64KByte/s,考虑线路等损耗实际的下载速度在50KB/S以上就算正常了 那么“1MB”那?大家算算吧答案是125KByte/s。

特别提示:

(1)关于bit(比特)/second(秒)与Byte(字节)/s(秒)的换算说明:线路单位是bps,表示bit(比特)/second(秒),注意是小写字母b;用户在网上下载时显示的速率单位往往是Byte(字节)/s(秒),注意是大写字母B。字节和比特之间的关系为1Byte=8Bits;再加上IP包头、HTTP包头等因网络传输协议增加的传输量,显示1KByte/s下载速率时,线路实际传输速率约10kbps。例如:下载显示是50KByte/s时,实际已经达到了500Kbps的速度。切记注意单位!!!

(2)用户申请的宽带业务速率指技术上所能达到的最大理论速率值,用户上网时还受到用户电脑软硬件的配置、所浏览网站的位置、对端网站带宽等情况的影响,故用户上网时的速率通常低于理论速率值。

(3)理论上:2M(即2Mb/s)宽带理论速率是:256KB/s(即2048Kb/s),实际速率大约为103–200kB/s;(其原因是受用户计算机性能、网络设备质量、资源使用情况、网络高峰期、网站服务能力、线路衰耗,信号衰减等多因素的影响而造成的)。4M(即4Mb/s)的宽带理论速率是:512KB/s,实际速率大约为200—440kB/s。

附带基础知识:

在计算机科学中,bit是表示信息的最小单位,叫做二进 制位;一般用0和1表示。Byte叫做字节,由8个位(8bit)组成一个字节(1Byte),用于表示计算机中的一个字符。bit与Byte之间可以进行换算,其换算关系为:1Byte=8bit(或简写为:1B=8b);在实际应用中一般用简称,即1bit简写为1b(注意是小写英文字母b),1Byte简写为1B(注意是大写英文字母B)。

在计算机网络或者是网络运营商中,一般宽带速率的单位用bps(或b/s)表示;bps表示比特每秒即表示每秒钟传输多少位信息,是bit per second的缩写。在实际所说的1M带宽的意思是1Mbps(是兆比特每秒Mbps不是兆字节每秒MBps)。

建议能记住以下换算公式:

1B=8b 1B/s=8b/s(或1Bps=8bps)

1KB=1024B 1KB/s=1024B/s

1MB=1024KB 1MB/s=1024KB/s

规范提示:实际书写规范中B应表示Byte(字节),b应表示bit(比特),但在平时的实际书写中有的把bit和Byte都混写为b ,如把Mb/s和MB/s都混写为Mb/s,导致人们在实际计算中因单位的混淆而出错。切记注意!!!

实例: 在我们实际上网应用中,下载软件时常常看到诸如下载速度显示为128KBps(KB/s),103KB/s等等宽带速率大小字样,因为ISP提供的线路带宽使用的单位是比特,而一般下载软件显示的是字节(1字节=8比特),所以要通过换算,才能得实际值。然而我们可以按照换算公式换算一下:

128KB/s=128×8(Kb/s)=1024Kb/s=1Mb/s即128KB/s=1Mb/s。

四、按需分配带宽

按需分配带宽(bandwidth on demand,BOD)是根据接受服务的信道的需要,以带宽增量方式增加吞吐量的能力。BOD是最能体现自动交换光网络(ASON)特点和优势的一种业务。通过BOD服务提供者按照用户需求提供可以使用的带宽。

  • 简介

目前,BOD是最能体现ASON动态特点和优势的一种业务。BOD业务能够适应网络业务日益数据化的趋势,能够增强用户和网络的交互能力,由用户自己定制和控制自己需要的网络带宽,在满足用户个性化需求、降低用户费用的同时,提高网络资源的有效利用率。

所谓BOD,顾名思义,就是服务提供者按照用户的需求提供可以使用的带宽。BOD包含两个层面的含义:一是能够快速地建立和拆除符合用户带宽需求的业务,二是对于已经建立的业务,可以根据用户的需求动态地调整带宽(增大或减小)。第一种情况是第二种情况的特例,利用ASON的交换连接(SC)或半永久连接(SPC)方式可以快速地建立和拆除连接,从而满足用户需求,其实现相对简单,而第二种情况,如果不希望业务损断的话,其实现要复杂得多。

  • 特点

BOD业务具有以下特性:

  1. 客户或其代理可以直接通过网管配置或用户网络接口(UNI)发起BOD业务建立。BOD业务可以由用户通过UNI以SC连接的方式发起以及进行带宽调整,也可以通过网络管理以SPC或SR连接的方式发起以及进行带宽调整。
  2. 根据所使用的互连模式和网络管理策略不同,光网络对客户可以不具有或者具有有限的可见性。
  3. 根据控制平面互连模型的不同,连接的建立依赖于网络或用户的智能。对于对等模型,由于客户和网络的资源共享,所以可以由用户进行资源优化和路由配置;而对于重叠模型:由于信息隐藏,用户只能通过接口请求,而由网络提供者进行资源优化和路由配置。

对于动态调整带宽的方法,也有多种选择:一种是有业务损断的调整方式,就是建立一个新的满足用户带宽需求的连接,替换旧的连接,具体方式包括先拆后建、先建后拆、同时拆建等等,由于存在连接的切换,需要消耗时间,所以这种方式也会产生一定时间的业务中断,但是其实现相对简单;还有一种方式就是不损断业务的动态调整方式,这需要使用一些特殊的技术,包括虚级联(VC)、链路容量调整方案(LCAS)等,通过动态增加或者减少业务所绑定的虚容器的数量来调整带宽。

  • 关键技术

在实现BOD业务过程中,需要使用通用成帧协议(GFP)实现数据帧到SDH虚容器的有效映射,同时使用VC和LCAS来进行带宽的动态绑定和调整,这是实现带宽无损调整的基础。

通用成帧协议

GFP是由ITU-T G.7041标准化的一种面向无连接的新型数据链路层封装协议,可以透明地将高层的各种数据格式封装为可以在同步数字体系/光传送网(SDH/OTN)传输网络中有效传输的信号,具有封装效率高、误码扩展小、无随机带宽膨胀代价等优点。GFP封装的高层客户信号可以是面向协议数据单元(PDU)数据流,也可以是面向块状编码的固定比特速率数据流。GFP使用了基于差错控制的帧定界机制,不需要对业务数据流进行特别处理。GFP封装方式具有协议透明性和通用性,能够后向兼容,目前已经得到大多数厂家的支持。

虚级联

虚级联是SDH中的一种数据传输技术,它可将多个虚容器组合起来,作为一个保持比特序列完整性的单容器使用,实现大颗粒业务的传输,存在着两种级联方式,相邻级联和虚级联。相邻级联要求所有级联容器在时隙上连续相邻排列,组成单一的逻辑传送实体在网络中进行交叉、复用和传输,它要求传输通道的所有节点都必须支持相邻级联方式。而虚级联则没有此要求,它可以把不同路径的多个物理流合并成单个逻辑流,实现传送层的链路汇聚。一般来说,虚级联要完成发送和接收两个方向的功能:在发送方向将接入信号分装至若干各高阶或低阶容器中,使相邻级联业务转化为可在现有SDH设备上传输的虚级联业务;在接收方向,将线路上传输的虚级联业务转换成相邻级联业务,从而获得原始的接入信号。

相对于相邻级联,虚级联在技术上需要考虑的主要问题是时延。由于虚级联每个虚容器的传输所通过的路径有可能不同,因此在各虚容器之间可能出现传输时差,在极端情况下,可能会出现序列号偏后的虚容器比序列号靠前的虚容器先到达终节点,这无疑给信号的还原带来了困难。目前,解决这一问题的有效方法是采用一个大的延时对齐存储器对数据进行缓存,并尽可能地让各个虚容器沿相同的路由传输。

虚级联技术对网络中间节点透明,只要求在接入业务的源、宿端支持虚级联功能,并且虚级联组中的各条成员链路可沿不同的路由独立进行传送,所以对网络资源的使用相当灵活,能够提高网络资源利用率。

链路容量调整方案

LCAS最初被称为可变带宽分配技术(VBA)。LCAS是对虚级联技术的扩充,建立在虚级联技术基础之上,是一种收发双方握手的传送层信令协议,可以通过该协议来动态地调整虚级联组的数量和状态,从而无损地调整连接的带宽。此外,LCAS技术还提供一种容错机制,可增强虚级联的健壮性:当虚级联组中有一个成员失效,不会使整个虚级联组失效,而是自动地将失效的成员从虚级联组中剔除,剩下的正常的成员继续传输业务、当失效成员恢复后,系统自动地又将该成员重新加入虚级联组。

  • ASON中带宽按需分配的实现

虚级联和LCAS为无损带宽调整提供了技术基础。在传统的网管方式下,可以通过虚级联和LCAS按照需求来调整连接的带宽,当网元管理系统/网络管理系统(EMS/NMS)接收到用户发来的带宽请求后,EMS/NMS首先进行端到端的选路,然后利用网管命令建立新增的通道,为新增的带宽做好准备。然后EMS/NMS就下发命令,在业务的源、宿两端触发LCAS,执行LCAS带宽调整动作序列,从而将新增的成员通道无损地增加到虚级联组中,从而实现带宽的无损调整。但是这种传统网管的调整方式,由于过程中需要大量的人工操作,所以调整周期长,实时性差。随着ASON的出现,人们可以利用其控制平面提供的强大的信令和路由功能,来自动、快速高效地实现BOD。

业务实现

在ASON中,当BOD业务有带宽改变请求时,可以通过控制平面来快速地建立和拆除BOD业务所需要的连接,然后由控制平面通知传送平面启动LCAS带宽调整过程,从而实现快速的带宽无损调整。ASON中的BOD业务模型如图所示。

img

ASON的BOD业务模型

BOD业务建立后,可以通过UNI接口发起带宽调整请求,也可以由网管系统通过控制平面网管接口(NMI-A)发起带宽调整,将请求发送给控制平面。控制平面负责根据带宽请求参数以及网络的拓扑和资源情况,通过路由和信令建立新的连接(带宽增加),或者拆除已有的连接(带宽减少)。然后控制平面通过连接控制接口(CCI)将增加/减少的通道通知给传送平面。传送平面在业务的源,宿两节点上启动LCAS调整过程,将需要调整的通道添加到虚级联组中。或者从虚级联组中移去。

带宽调整过程

以客户通过UNI接口发起的带宽增加为例。给出带宽调整的过程,信令采用资源预留协议(PSVP),带宽增加过程如图所示。

img

ASON带宽调整过程

  1. 源客户通过UNI接口发出带宽调整请求,控制平面接收到请求后。进行呼叫过程,PATH命令从源控制节点直接到达宿控制节点。然后传递给宿客户。宿客户确认后。通过PSVP命令返回给源控制节点。
  2. 源控制节点根据带宽调整的参数,确定是新建连接还是拆除连接,以及连接的带宽。根据当前的网络拓扑和资源使用情况,确定新建连接的路由,在进行选路时,还需要考虑BOD业务当前的虚级联通道分布情况,为避免不同通道的时延差别过大、不利于信号合并、所以在选择新的路由时,应尽可能地和原来的通道走相同的路由。然后控制平面通过信令过程控制传送平面,在传送平面里建立起新的连接。信令过程完成后,控制平面通过CCI接口发出命令,通知传送平面的源,宿节点启动LCAS。
  3. 传送平面接收到控制平面命令后,源,宿节点启动LCAS动作命令,将新增的连接增加到BOD业务所关联的虚级联组中,LCAS过程完成后,传送平面将执行结果反馈给控制平面。
  4. 控制平面收到传送平面反馈后,知道LCAS执行完毕,然后向源客户返回调整结果,源客户可以发起ResvConf命令对带宽的调整进行确认,表明新的带宽已可以使用.。

带宽保证

当网络发生故障时,BOD业务的带宽也会受到影响,这就需要采取措施保证BOD业务的带宽,使网络故障给用户带来的影响最小,通常,在传输网中都会对连接采用保护、恢复等方式来保证连接的可用性,但是BOD业务和普通的连接不同,有一些独特的特点、BOD业务采用虚级联,对应多个成员通道连接,并且各个成员通道的路径可能是不一样的;BOD承载的都是数据业务,不同数据业务类型的实时性要求是不一样的,所以当BOD业务受到故障影响时,不能简单地等同于普通的连接恢复,需要在恢复启动条件和恢复方式上作一些特殊考虑。

  1. BOD业务故障恢复启动条件的确定。当网络故障时,可能只会影响到BOD业务的部分成员通道,但整个业务并没有断掉,只是业务的带宽减小,当BOD所承载的是一些非实时性的业务时,如上网浏览、下载数据、收发邮件等等,带宽的小幅减小对用户的使用影响并不大,但当BOD业务承载的是一些实时性很强的业务,如实时视频、语音等,即使是带宽的小幅减小,也会给用户的使用带来较大的影响,所以,针对BOD业务,可以根据业务的性质和用户需求划分等级,根据不同的等级设定一个带宽容量减少比率门限值,作为BOD业务是否启动保护/恢复的一个依据,当网络故障对BOD业务产生影响时,如果容量的减少小于门限值,系统可以不启动恢复机制,只是采用LCAS,将产生故障的通道暂时从虚级联组中删除,降低数据业务的丢包率和时延,待故障的通道修复后,系统再自动地将修复好的通道增加到虚级联组中,恢复业务原来的带宽,如果容量的减少大于门限值,系统需要将故障的通道从虚级联组中删除,同时立即启动保护/恢复机制,快速找到替换通道并将其增加到虚级联组中,保证业务的带宽不变。
  2. BOD业务故障恢复方式选择一个BOD业务包含多个成员连接,很自然地,可以针对BOD业务的每个成员连接独立地进行恢复,找到替代的连接并切换过去,如果多个成员连接同时发生故障,各个通道连接的恢复过程互不影响,这种恢复方式思路清晰,处理相对简单,对于那种包含的成员连接的路由比较分散、并且同时故障的成员连接数目较少的BOD业务来说是比较有效的,如果BOD业务的成员连接的路由比较集中,在同一路径中包含了数个成员连接,如果该路径某处发生故障,则该路径上的所有成员连接都会失效,都要触发恢复,在这种情况下如果对每个成员连接独立地恢复,总的恢复时间可能会比较长,针对这种情况,可以将多条成员连接作为一个整体,统一进行一次恢复,这种恢复的效果要好得多,图3给出了两种恢复方式的特点和适用场景。

img

自动带宽调整

除了可以由用户或者网管系统发起带宽调整请求外,还可以设置一些自动触发带宽调整的条件,当条件满足时,系统可以自动发起BOD业务的带宽调整请求,通过ASON的智能化和自动化能力来完成带宽的调整,为BOD业务增加更多的智能特性。

  1. 定时调整带宽。存在某一类业务,可能在不同的时间段内,有着不同的带宽需求,这是事先已经明确好的,从减少用户带宽租用费用和提高网络的使用效率的角度,系统可以设定一个定时机制,按照事先约定好的协议,在规定的时间点自动发起带宽调整请求,由ASON来自动地完成带宽调整,为用户提供满意的带宽。
  2. 根据流量自动调整带宽。可以在ASON中增加业务流量自动检测能力,收集、统计BOD业务的流量变化,分析业务流量变化规律,得到业务流量变化的趋势,制订相应的策略,当业务流量变化满足设定条件时,系统就自动触发业务带宽调整,改变业务的带宽,实现网络根据流量自主地调整带宽,提高网络资源的有效利用率,这应该是BOD业务发展的趋势。

五、怎样计算一个网站服务器需要多少带宽

在选择一个托管服务之前,你需要考虑许多方面的因素,其中,计算带宽是最有挑战性的一个。带宽指的是在一段时间内,从你的主机服务器传送到访客电脑的数据总量。不像桌面存储空间,你只需要删除一部分大的图片和视频即可控制。带宽需要仔细地计算因为如果有很多访客从你的网站查看或者下载大的文件的话,你的网站可能中途就要关闭了。

实际上,有很多主机公司在他们的计划中都提供了几种带宽的选择,所以你完全可以选择到一个合适大小的带宽,这样的话你既不会因为买多而浪费钱也不会因为买少导致用超而被罚钱。但是怎么知道自己需要多少带宽呢?接下来的文章中我们将会具体回答这个问题。

一个网站需要多少带宽

事实上,计算需要多少带宽很容易,你只需记录你网站的日常活动然后做一个数学计算即可。

  • 估计你网站上一个网页的平均字节数,单位为KB
  • 估计你所预计的网站每日访问量
  • 估计你所预计的每人平均访问页面数
  • 将以上三步的结果相乘再乘以一个月的天数,即30

这个简单的公式用于计算带宽非常直观,但是如果你只计算了一个账户的话,不要忘了计算你服务器上的所有网站。

考虑额外带宽

实际上,以上计算的结果只是一个估计,你应该知道理论计算值和实际值是有区别的。比如说,如果你的网站每个页面有45KB大,每天有1000个访问者,每个访问者平均看4个页面,这样得出来的理论值大概是4.5GB一个月。但实际应用时这些带宽是不够的,你还需要考虑以下几个方面:

  • 文件下载

如果你允许访客从你的网站下载文件的话,为了这些下载进程,你就需要额外的带宽。所以,你还要计算访客从你的网站下载的文件的平均大小和你预计的下载数,然后把这个值乘以你计算的理论值。

  • 多媒体

如果你打算在你的网站上放一些视频,音乐,Flash动画或其他多媒体资料的话,比起只是放HTML文本内容和图片,你可能需要更多地带宽。例如,如果你提供一个200MB的文件给访客下载,22.5个下载数大概需要4.5GB的带宽。

  • 不断增长的流通量

如果你的网站拥有高质量的内容的话,你就可能会拥有越来越多的访客,这也就意味着你预计的每日访客量,网页访问数,每日下载数等都会明显增加,进而所需带宽也会增加。简而言之,你需 要考虑这个到动态的增长过程,为未来做计划,给网站留一个提升的空间。

  • 布局变化

如果你对现在的网站界面不满意的话,你可以改变它的布局。但是,你要知道的是这个改变可能会改变你的页面大小,所以可能会用到更多的带宽。

总结

实际上,带宽好比高速公路,如果一条高速公路上只有一辆车,你就可以开得很快。但是如果一条高速公路上同时存在太多车的话,你可能就会堵在中途或者开得很慢,因为所有线路都被占用了。因此,计算带宽和提前计划是非常重要的。

最后,如果你想选择一个合适的主机供应商的话,有很多因素需要考虑而不仅仅是带宽,例如速度,价格,可信度和技术支持等等。




大菜狗
5个月前

面试深入之Spring(SpringBoot)

Bean的生命周期

bean的创建

整体流程

spring会扫描指定路径的的包,看包下面的每一个类,如果类上面有相关注解,spring就会帮你创建这个类的bean对象,经过依赖注入,初始化前,初始化,AOP,一系列流程创建对象,并管理bean的生命周期

流程总结:

  1. 扫描包(指定包路径)
  2. 推断构造方法
  3. 用构造方法实例化对象(单例bean,即所有getbean的哈希值相同)
  4. 依赖注入
  5. 初始化前
  6. 执行初始化方法
  7. 初始化后(AOP)
  8. 生成代理对象
  9. 得到bean

构造方法的选取

bean要帮你创建对象,依据就是类的构造方法,spring默认用无参构造方法,当只有一个有参构造方法,就用这个,如果有多个有参构造方法,就会报错,这时要手动指定某个构造方法为默认构造方法,就是在方法前加上 @AutoWrite.

构造方法中参数的注入

入果参数传入的是对象,应该怎么注入?从spring对象池里找

spring对象池可以理解为1个map对象池里放这所有注册过的bean。找的时候先通过反射根据类型找,如果有多个 ,则根据参数名字去找

上面这个方法叫推断构造方法

AOP和代理对象

手写spring容器的思路

首先要实现一个根据类名,获取对象的getbean方法

如何获取到这些类

想想spring的实现方法,是通过在类上写一些注解。Spring在扫描包的时候,通过这些注解,识别这些类,并

AOP

Sping Bean

Bean的创建

@SpringBootTest
class JavaallApplicationTests {
    @Autowired
    ApplicationContext applicationContext;

    @Test
    void isBeanSingleton() {
        System.out.println(applicationContext.getBean("BeanTest"));
        BeanTest beanTest1 = (BeanTest) applicationContext.getBean("BeanTest");
        BeanTest beanTest2 = (BeanTest) applicationContext.getBean("BeanTest");


        BeanTest beanTest3 = new BeanTest();

        System.out.println("两个通过spring创建的bean:"+(beanTest1 == beanTest2));
        System.out.println("两个通过spring创建的bean的成员对象:"+(beanTest1.getBeanContent() == beanTest2.getBeanContent()));
        System.out.println("通过spring创建的bean和手动创建的对象:"+(beanTest1 == beanTest3));
        System.out.println("通过spring创建的bean和手动创建的对象的成员对象:"+(beanTest1.getBeanContent() == beanTest3.getBeanContent()));


    }
    @Test
    void testClone() throws IOException, ClassNotFoundException {
        BeanTest beanTest1 = new BeanTest();
        BeanTest beanTest2 = beanTest1.clone();
        BeanTest beanTest3 = (BeanTest) beanTest1.deepClone();

        System.out.println("浅拷贝的2个对象:"+(beanTest1 == beanTest2));
        System.out.println("浅拷贝的2个对象的int:"+(beanTest1.getAge()== beanTest2.getAge()));
        System.out.println("浅拷贝的2个对象的string:"+(beanTest1.getName()== beanTest2.getName()));
        System.out.println("浅拷贝的2个对象成员对象:"+(beanTest1.getBeanContent()==beanTest2.getBeanContent()));
        System.out.println("================================================================================");
        System.out.println("浅拷贝的2个对象:"+(beanTest1 == beanTest3));
        System.out.println("浅拷贝的2个对象的int:"+(beanTest1.getAge()== beanTest3.getAge()));
        System.out.println("浅拷贝的2个对象的string:"+(beanTest1.getName()== beanTest3.getName()));
        System.out.println("浅拷贝的2个对象成员对象:"+(beanTest1.getBeanContent()==beanTest3.getBeanContent()));
    }

}

结果:

两个通过spring创建的bean:true
两个通过spring创建的bean的成员对象:true
通过spring创建的bean和手动创建的对象:false
通过spring创建的bean和手动创建的对象的成员对象:false

Bean的注册

beanDefinitionMap

SpringBoot中@Component是如何生效的

SpringBoot帮助Spring解决了哪些问题

1.统一的依赖版本管理

pom.xml里点开

<artifactId>spring-boot-starter-parent</artifactId>

再点开里面的

<artifactId>spring-boot-dependencies</artifactId>

就可以看到

其对开发场景中常用框架的依赖文件做了统一版本号管理,所以被管理的这些依赖在pom.xml中引入是不需要写版本号

形如:

<artifactId>spring-boot-starter-xxx</artifactId>

就是官方提供的依赖启动器

即提供了官方认为的开发者在该场景业务开发中需要的依赖统一配置

2.自动配置

回忆ssm阶段,当我们想使用第三方依赖,如mybatis ,需要在xml中自己进行手动配置,把这个依赖交给spring管理

   <!-- 配置整合mybatis -->
    <!-- 1.关联数据库文件 -->
    <context:property-placeholder location="classpath:database.properties"/>

    <!-- 2.数据库连接池 -->
    <!--数据库连接池
        dbcp 半自动化操作 不能自动连接
        c3p0 自动化操作(自动的加载配置文件 并且设置到对象里面)
    -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!-- 配置连接池属性 -->
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>

        <!-- c3p0连接池的私有属性 -->
        <property name="maxPoolSize" value="30"/>
        <property name="minPoolSize" value="10"/>
        <!-- 关闭连接后不自动commit -->
        <property name="autoCommitOnClose" value="false"/>
        <!-- 获取连接超时时间 -->
        <property name="checkoutTimeout" value="10000"/>
        <!-- 当获取连接失败重试次数 -->
        <property name="acquireRetryAttempts" value="2"/>
    </bean>

    <!-- 3.配置SqlSessionFactory对象 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 注入数据库连接池 -->
        <property name="dataSource" ref="dataSource"/>
        <!-- 配置MyBatis全局配置文件:mybatis-config.xml -->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>

    </bean>

可以想像,我们开发一个业务,需要的依赖很多,如果每一个都需要这么配置的话,将会使开发变的异常麻烦

于是对于这些依赖,spring官方将这些配置帮我们搞好了,无须我们再自己手写这些配置

我们只需要对我们自己写的代码进行配置即可

3.由xml配置文件变为注解+ymal

注:springboot中仍然可以用xml配置,只是现在的开发习惯不用而已,并不是不能用

xml中仍然有许多重复的代码,springboot将配置方式再次简化,用注解实现类的注册




大菜狗
5个月前

面试深入之mysql

mysql中的专有名词解释

  1. 脏页:当内存数据页跟磁盘数据页内容不一致的时候,我们称这个内存页为“脏页”。
  2. 干净页:内存数据写入到磁盘后,内存和磁盘上的数据页的内容就一致了,称为“干净页”。
  3. redo log:重做日志,确保事务的持久性。防止在发生故障的时间点,尚有脏页未写入磁盘,在重启mysql服务的时候,根据redo log进行重做;redo log通常是物理日志,记录的是数据页的物理修改,而不是某一行或某几行修改成怎样怎样,它用来恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)。
  4. undo log:回滚日志,保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读;undo log一般是逻辑日志,根据每行记录进行记录。
  5. binlog:归档日志,二进制日志,用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。 用于数据库的基于时间点的还原。
  6. 聚集(簇)索引:数据行的物理顺序与列值(一般是主键的那一列)的逻辑顺序相同,一个表中只能拥有一个聚集索引。索引的叶子节点就是对应的数据节点
  7. 非聚集索引:该索引中索引的逻辑顺序与磁盘上行的物理存储顺序不同,一个表中可以拥有多个非聚集索引。非聚集索引叶节点仍然是索引节点,只是有一个指针指向对应的数据块,此如果使用非聚集索引查询,而查询列中包含了其他该索引没有覆盖的列,那么他还要进行第二次的查询,查询节点上对应的数据行的数据。
  8. 慢查询:,全名是慢查询日志,是MySQL提供的一种日志记录,用来记录在MySQL中响应时间超过阀值的语句。

Mysql体系结构

组成

  1. 连接池组件
  2. 管理服务和工具组件
  3. SQL接口组件
  4. 查询分析器组件

  5. 优化器组件

  6. 缓冲(Cache)组件,
  7. 插件式存储引擎。
  8. 物理文件

MySQL存储引擎

背景

MySQL5对其结构体系做了较大的改造,并引入了一个新的概念:插件式存储引擎体系结构

存储引擎层和sql 层各自更为独立,耦合更小,甚至可以做到在线加载新的存储引擎,也就是完全可以将一个新的存
储引擎加载到一个正在运行的MySQL 中,而不影响MySQL 的正常运行。

插件式存储引擎的架构,为存储引擎的加载和移出更为灵活方便,也使自行开发存储引擎更为方便简单

MySQL 的插件式存储引擎主要包括MyISAM,Innodb,NDB Cluster,Maria,Falcon,Memory,Archive,Merge,Federated 等,其中最著名而且使用最为广泛的MyISAM 和Innodb两种存储引擎。

MyISAM

MyISAM的文件结构

MyISAM 存储引擎的表在数据库中,每一个表都被存放为三个以表名命名的物理文件

  1. 存放表结构定义信息的.frm 文件
  2. 存放了表的数据的.MYD文件
  3. 存放索引数据的.MYI文件

每个表都有且仅有这样三个文件做为MyISAM 存储类型的表的存储,也就是说不管这个表有多少个索引,都是存放在
同一个.MYI文件中。

MyISAM的索引类型

1.B-Tree索引

B-Tree 索引,顾名思义,就是所有的索引节点都按照balance tree 的数据结构来存储,所有的索引数据节点都在叶节点。

那就是参与一个索引的所有字段的长度之和不能超过1000 字节

2.R-Tree 索引

R-Tree 索引的存储方式和b-tree 索引有一些区别,主要设计用于为存储空间和多维数据的字段做索引,所以目前的MySQL 版本来说,也仅支持geometry 类型的字段作索引。

3.Full-text 索引

Full-text 索引就是我们长说的全文索引,他的存储结构也是b-tree。主要是为了解决在我们需要用like 查询的低效问题。

最经常使用的就是B-Tree 索引了,偶尔会使用到Fulltext,但是R-Tree 索引一般系统中都是很少用到的。另外MyISAM 的B-Tree 索引有一个较大的限制,那就是参与一个索引的所有字段的长度之和不能超过1000 字节。

MyISAM的索引存储格式

MyISAM 的数据存放格式是分为静态固定长度(FIXED)、动态可变长度(DYNAMIC)以及压缩(COMPRESSED)这三种格式

虽然每一个MyISAM 的表都是存放在一个相同后缀名的.MYD 文件中,但是每个文件的存放格式实际上可能并不是完全一样的

三种格式中是否压缩是完全可以任由我们自己选择的,可以在创建表的时候通过ROW_FORMAT 来指定{COMPRESSED | DEFAULT},也可以通过myisampack 工具来进行压缩,默认是不压缩的

在非压缩的情况下,是静态还是动态,就和我们表中个字段的定义相关了。只要表中有可变长度类型的字段存在,那么该表就肯定是DYNAMIC 格式的,如果没有任何可变长度的字段,则为FIXED 格式

MyISAM引擎的缺点

MyISAM 存储引擎的某个表文件出错之后,仅影响到该表,而不会影响到其他表,更不会影响到其他的数据库

如果我们的出据苦正在运行过程中发现某个MyISAM 表出现问题了,则可以在线通过check table 命令来尝试校验他,并可以通过repairtable命令来尝试修复

Innodb 存储引擎

特点

1、支持事务安装

2、数据多版本读取

Innodb 在事务支持的同时,为了保证数据的一致性已经并发时候的性能,通过对undo信息,实现了数据的多版本读取。

3、锁定机制的改进

Innodb 改变了MyISAM 的锁机制,实现了行锁(MyISAM为表锁)。Innodb 的行锁机制的实现是通过索引来完成的

4、实现外键

innodb的文件结构

分为两大部分

数据文件(存放表数据和索引数据)

存放数据表中的数据和所有的索引数据,包括主键和其他普通索引

Innodb 的表空间分为两种形式

一种是共享表空间,也就是所有表和索引数据被存放在同一个表空间(一个或多个数据文件)中,通过innodb_data_file_path 来指定,增加数据文件需要停机重启。

另外一种是独享表空间,也就是每个表的数据和索引被存放在一个单独的.ibd 文件中

注意事项

1.我们可以自行设定使用共享表空间还是独享表空间来存放我们的表

2.共享表空间都是必须存在的,因为Innodb 的undo 信息和其他一些元数据信息都是存放在共享表空间里面的

3.共享表空间的数据文件是可以设置为固定大小和可自动扩展大小两种形式的,自动扩展形式的文件可以设置文件的最大大小和每次扩展量

4.Innodb 不仅可以使用文件系统,还可以使用原始块设备,也就是我们常说的裸设备。

5.当我们的文件表空间快要用完的时候,我们必须要为其增加数据文件,当然,只有共享表空间有此操作

6.Innodb 在创建新数据文件的时候是不会创建目录的,如果指定目录不存在,则会报错并无法启动。

7.Innodb 在给共享表空间增加数据文件之后,必须要重启数据库系统才能生效,如果是使用裸设备,还需要有两次重启。

日志文件

特点

1.Innodb 的日志文件和Oracle 的redo 日志比较类似,同样可以设置多个日志组(最少2个),同样采用轮循策略来顺序的写入,甚至在老版本中还有和Oracle 一样的日志归档特性。

2.由于Innodb 是事务安全的存储引擎,所以系统Crash 对他来说并不能造成非常严重的损失,

3.由于有redo 日志的存在,有checkpoint 机制的保护,Innodb 完全可以通过redo 日志将数据库Crash 时刻已经完成但还没有来得及将数据写入磁盘的事务恢复,也能够将所有部分完成并已经写入磁盘的未完成事务回滚并将数据还原。

4.Innodb 的所有参数基本上都带有前缀“innodb_”,不论是innodb 数据和日志相关,还是其他一些性能,事务等等相关的参数都是一样。

Innodb体系架构详解

InnoDB有多个内存块,你可以认为这些内存块组成了一个大的内存池,负责如下工作:

  1. 维护所有进程/线程需要访问的多个内部数据结构。
  2. 缓存磁盘上的数据,方便快速地读取,并且在对磁盘文件的数据进行修改之前在这里缓存。
  3. 重做日志 (redo log)缓冲。

image-20220326104828327.png

后台线程

查看后台线程信息

show engine innodb status

内存

InnoDB存储引擎内存由以下几个部分组成:

  1. 缓冲池(buffer pool)、
  2. 重做日志缓冲池(redo log buffer)
  3. 额外的内存池(additional memory pool),分别由配置文件中的参数innodb_buffer_pool_size和innodb_log_buffer_size的大小定。

缓冲池是占最大块内存的部分,用来存放各种数据的缓存。

InnoDB的存储引擎的工作方

因为InnoDB的存储引擎的工作方式总是将数据库文件按页(每页16K)读取到缓冲池然后按最近最少使用(LRU)的算法来保留在缓冲池中的缓存数据。如果数据库文件需要修改,总是首先修改在缓存池中的页(发生修改后,该页即为脏页),然后再按照一定的频率将缓冲池的脏页刷新(flush)到文件

innodb存储引擎内存结构.png

在InnoDB存储引擎中,对内存的管理是通过一种称为内存堆(heap)的方式进行的。在对一些数据结构本身分配内存时,需要从额外的内存池中申请,当该区域的内存不够时,会从缓冲池中申请。InnoDB实例会申请缓冲池(innodb_buffer_pool)的空间,但是每个缓冲池中的帧缓冲(frame buffer)还有对应的缓冲控制对象(buffercontrol block),而且这些对象记录了诸如LRU、锁、等待等方面的息,而这个对象的内存需要从额外内存池中申请。因此,当你申请了很大的InnoDB缓冲池时,这个值也应该相应增加。

在InnoDB存储引擎中,对内存的管理是通过一种称为内存堆(heap)的方式进行的。在对一些数据结构本身分配内存时,需要从额外的内存池中申请,当该区域的内存不够时,会从缓冲池中申请。InnoDB实例会申请缓冲池(innodb_buffer_pool)的空间,但是每个缓冲池中的帧缓冲(frame buffer)还有对应的缓冲控制对象(buffercontrol block),而且这些对象记录了诸如LRU、锁、等待等方面的信息,而这个对象的内存需要从额外内存池中申请。因此,当你申请了很大的InnoDB缓冲池时,额外内存池也应该相应增加。

主线程

InnoDB存储引擎的主要工作都是在一个单独的后台线程master thread中完成的

master thread的线程优先级别最高。其内部由几个循环(loop)组成:主循环(loop)后台循环 (background loop)、刷新循环(flush loop)、暂停循环(suspend loop)。masterthread会根据数据库运行的状态在loop、background loop、 flush loop和suspend loop中进行切换。

循环中每秒一次的操作包括:

日志缓冲刷新到磁盘,即使这个事务还没有提交(总是)。

即使某个事务还没有提交,InnoDB存储引擎仍然会每秒将redo log缓冲中的内容刷新到redo log文件,这就是为什么再大的事务也会提交的很快

合并插人缓冲(可能)。

合并插人缓冲(insert buffer)并不是每秒都发生。InnoDB存储引擎会判断当前一秒内发生的IO次数是否小于5次,如果小于5次,InnoDB认为当前的IO压力很小,可以执行合并插人缓冲的操作。

至多刷新100个InnoDB的缓冲池中的脏页到磁盘(可能)。

刷新100个脏页也不是每秒都在发生。InnoDB存储引擎通过判断当前缓冲池中脏页的比例(buf_get_modified_ratio_pct)是否超过了配置文件中innodb.maxdirty_pages_pct这个参数(默认为90,代表90%),如果超过了这个阈值,InnoDB存储引擎认为需要做磁盘同步操作,将100个脏页写人磁盘。

如果当前没有用户活动,切换到background loop(可能)。

若当前没有用户活动(数据库空闲时)或者数据库关闭时,就会切换到这个循环。这个循环会执行以下操作:
删除无用的Undo页 (总是)。
合并20个插人缓冲(总是)。
跳回到主循环 (总是)。
不断刷新100个页,直到符合条件(可能,跳转到flush loop中完成)。

两次写

如果说插人缓冲带给InnoDB存储引擎的是性能,那么两次写带给InnoDB存储引擎的是数据的可靠性。当数据库宕机时,可能发生数据库正在写一个页面,而这个页只写了一部分(比如16K的页,只写前4K的页)的情况,我们称之为部分写失效(partial page write)。在InnoDB存储引擎未使用double write技术前,曾出现过因为部分写失效而导致数据失的情况。

innodb的索引

b+树索引

b+树的结构及特点

1、b+树其实有点类似于线段树,非叶子节点中存放的是子树中某一段的头指针

2、b+树的子树间无高度差,所有叶子节点都在同一层,且用一个双向指针连接,且是严格按照主键从左到右排序;且每个叶子节点都是大小相同的页

b+树的插入操作

b+树的插入.png

这里总结一下:

1、首先,叶子节点的页大小是固定的,每页存放的数据的条数也是固定的

2、当要插入的那一页,页满的时候,先看看左边相邻的页有没有空间,有的话进行旋转,没有的话再考虑拆页

一个案例,插入

插入前:

b+树插入案例插入前.png

插入70(旋转):

b+树插入时旋转.png

插入95(拆页):

b+树插入时拆页.png

聚集索引

聚集索引.png

自适应哈希索引

InnoDB存储引擎会监控对表上索引的查找,如果观察到建立哈希索引可以带来速度的提升,则建立哈希索引,所以称之为自适应(adaptive)的。自适应哈希索引通过缓冲池
的B+树构造而来,因此建立的速度很快。而且不需要将整个表都建哈希索引,InnoDB存储引擎会自动根据访问的频率和模式来为某些页建立哈希索引。

MySQL安全管理

数据库系统安全的三大防线

1.网络

2.主机

3.数据库

4.代码

权限系统

相关权限信息主要存储在几个被称为granttables 的系统表中,即: mysql.Usermysql.dbmysql.Hostmysql.table_privmysql.column_priv

由于权限信息数据量比较小,而且访问又非常频繁,所以Mysql 在启动的时候,就会将所有的权限信息都Load 到内存中保存在几个特定的结构中

权限的5大级别

  1. Global Level:全局权限控制,所有权限信息都保存在mysql.user 表中。Global Level 的所有权限都是针对整个mysqld 的,对所有的数据库下的所有表及所有字段都有效。
  2. Database Level:Database Level 是在Global Level 之下,其他三个Level 之上的权限级别,其作用域
    即为所指定整个数据库中的所有对象
  3. Table Level:Table Level 的权限作用范围是授权语句中所指定数据库的指定表
  4. Column Level
  5. Routine Level

访问控制实现原理

用户想要访问数据库,必须提供:主机名或ip地址用户名密码

如果要通过localhost 访问的话,必须要有一条专门针对localhost 的授权信息,即使不对任何主机做限制也不行

如果MySQL 正在运行之中的时候,我们对系统做了权限调整,那调整之后的权限什么时
候会生效呢?

Mysql数据备份

MyISAM 存储引擎的数据备份

1.MyISAM 存储引擎文件的物理文件比较集中,而且不支持事务没有redo和undo 日志,对数据一致性的要求也并不是特别的高,所以MyISAM 存储引擎表的物理备份也比较简单,只要将MyISAM 的物理文件copy 出来即可

2.MyISAM存储引擎的同一个表的数据文件和索引文件之间是有一致性要求的。

3.当MyISAM 存储引擎发现某个表的数据文件和索引文件不一致的时候,会标记该表处于不可用状态,并要求你进行修复动作,

4.我们自己必须至少保证数据库在备份时候的数据是处于某一个时间点的,这样就要求我们必须做到在备份MyISAM 数据库的物理文件的时候让MyISAM 存储引擎停止写操作,仅仅提供读服务,其根本实质就是给数据库表加锁来阻止写操作

5.MySQL 自己提供了一个使用程序mysqlhotcopy,这个程序就是专门用来备份MyISAM 存储引擎的

Innodb 存储引擎的数据备份

1.Innodb 存储引擎由于是事务性存储引擎有redo 日志和相关的undo 信息,而且对数据的一致性和完整性的要求也比MyISAM 要严格很多,所以Innodb 的在线(热)物理备份要比MyISAM 复杂很多,一般很难简单的通过几个手工命令来完成,大都是通过专门的Innodb
在线物理备份软件来完成

2.Innodb 存储引擎的开发者(Innobase 公司)开发了一款名为ibbackup 的商业备份软件,专门实现Innodb 存储引擎数据的在线物理备份功能。该软件可以在MySQL 在线运行的状态下,对数据库中使用Innodb 存储引擎的表进行备份,不过仅限于使用Innodb 存储引擎的表。

影响MySQL性能的相关因素

适合利用Cache提前缓存数据的场景

  1. 系统各种配置及规则数据;
  2. 活跃用户的基本信息数据;
  3. 活跃用户的个性化定制信息数据;
  4. 准实时的统计信息数据;
  5. 其他一些访问频繁但变更较少的数据;

合理的sql语句的应用

一个经典的对比案例

在我们的示例网站系统中,现在要实现每个用户查看各自相册列表(假设每个列表显示10 张相片)
的时候,能够在相片名称后面显示该相片的留言数量。这个需求大家认为应该如何实现呢?

方案一:

1、通过

SELECT id,subject,url FROM photo WHERE user_id = ? limit 10

得到第一页的相片相关信息;

2、通过第1 步结果集中的10 个相片id 循环运行十次

SELECT COUNT(*) FROM photo_commentWHERE photh_id = ?

来得到每张相册的回复数量然后再瓶装展现对象。

方案二:

1、通过

SELECT id,subject,url FROM photo WHERE user_id = ? limit 10

得到第一页的相片相关信息;

2、通过程序拼装上面得到的10 个photo 的id,再通过in 查询

SELECT photo_id,count(*) FROM photo_comment WHERE photo_id in (拼装后的id) GROUP BY photo_id

一次得到10 个photo 的所有回复数量,再组装两个结果集得到展现对象。

两种方案的复杂度对比
  1. 从MySQL 执行的SQL 数量来看,第一种解决方案为11(1+10=11)条SQL 语句,第二种解决方案
    为2 条SQL 语句(1+1);
  2. 从应用程序与数据库交互来看,第一种为11 次,第二种为2 次;
  3. 从数据库的IO 操作来看,简单假设每次SQL 为1 个IO,第一种最少11 次IO,第二种小于等于11
    次IO,而且只有当数据非常之离散的情况下才会需要11 次;
  4. 从数据库处理的查询复杂度来看,第一种为两类很简单的查询,第二种有一条SQL 语句有GROUP
    BY 操作,比第一种解决方案增加了了排序分组操作;
  5. 从应用程序结果集处理来看,第一种11 次结果集的处理,第二中2 次结果集的处理,但是第二种
    解决方案中第二词结果处理数量是第一次的10 倍;
  6. 从应用程序数据处理来看,第二种比第一种多了一个拼装photo_id 的过程。
消耗性能上的对比
  1. 由于MySQL 对客户端每次提交的SQL 不管是相同还是不同,都需要进行完全解析,这个动作主要
    消耗的资源是数据库主机的CPU,那么这里第一种方案和第二种方案消耗CPU 的比例是11:2。SQL 语句的
    解析动作在整个SQL 语句执行过程中的整体消耗的CPU 比例是较多的;
  2. 应用程序与数据库交互所消耗的资源基本上都在网络方面,同样也是11:2;
  3. 数据库IO 操作资源消耗为小于或者等于1:1;
  4. 第二种解决方案需要比第一种多消耗内存资源进行排序分组操作,由于数据量不大,多出的消耗
    在语句整体消耗中占用比例会比较小,大概不会超过20%,大家可以针对性测试;
  5. 结果集处理次数也为11:2,但是第二中解决方案第二次处理数量较大,整体来说两次的性能消
    耗区别不大;
  6. 应用程序数据处理方面所多出的这个photo_id 的拼装所消耗的资源是非常小的,甚至比应用程
    序与MySQL 做一次简单的交互所消耗的资源还要少。
总结

综合上面的这6 点比较,我们可以很容易得出结论,从整体资源消耗来看,第二中方案会远远优于第一种解决方案。

而在实际开发过程中,我们的程序员却很少选用。主要原因其实有两个,

一个是第二种方案在程序代码实现方面可能会比第一种方案略为复杂,尤其是在当前编程环境中面向对象思想的普
及,开发工程师可能会更习惯于以对象为中心的思考方式来解决问题。

还有一个原因就是我们的程序员可能对SQL 语句的使用并不是特别的熟悉,并不一定能够想到第二条SQL 语句所实现的功能。对于

探究sql语句对性能的影响

当MySQL Server 的连接线程接收到Client 端发送过来的SQL 请求之后,会经过一系列的分解Parse,进行相应的分析。然后,MySQL 通过查询优化器模块(Optimizer)根据该SQL 所设涉及到的数据表的相关统计信息进行计算分析,然后再得出一个MySQL 认为最合理最优化的数据访问方式,也就是我们常说的“执行计划”,然后再根据所得到的执行计划通过调用存储引擎借口来获取相应数据。然后再将存储引擎返回的数据进行相关处理,并以Client 端所要求的格式作为结果集返回给Client 端的应用程序。

两种锁的级别

InnoDB存储引擎实现了如下两种标准的行级锁:

  1. 共享锁 (S Lock),允许事务读一行数据。
  2. 排他锁 (X Lock),允许事务删除或者更新一行数据。

当一个事务已经获得了行r的共享锁,那么另外的事务可以立即获得行r的共享锁,因为读取并没有改变行r的数据,我们称这种情况为锁兼容。但如果有事务想获得行r的排他
锁,则它必须等待事务释放行r上的共享锁这种情况我们称为锁不兼容。

意向锁

InnoDB存储引擎支持多粒度锁定,这种锁定允许在行级上的锁和表级上的锁同时存在。为了支持在不同粒度上进行加锁操作,InnoDB存储引擎支持一种额外的锁方式,我们称之
为意向锁。意向锁是表级别的锁,其设计目的主要是为了在一个事务中揭示下一行将被请求的锁的类型。InnoDB存储引擎支持两种意向锁:

  1. 意向共享锁 (IS Lock),事务想要获得一个表中某几行的共享锁。
  2. 意向排他锁 (IX Lock),事务想要获得一个表中某几行的排他锁。

因为InnoDB存储引擎支持的是行级别的锁,所以意向锁其实不会阻塞除全表扫以外的任何请求。

查看锁的信息

版本的InnoDB Plugin中,在INFORMATION_SCHEMA架构下添加了INNODB_TRX、INNODB_LOCKS、INNODB_LOCK_WAITS。通过这三张表,可以更简单地监控当前的
事务并分析可能存在的锁的问题。通过实例我们来分析这三张表,先看表INNODB_TRX,

INNODB_TRX由8个字段组成:

  1. trx_id:InnoDB存储引擎内部唯一的事务ID。
  2. trx_state:当前事务的状态。
  3. trx_started:事务的开始时间。
  4. trx_requested_lock_id:等待事务的锁ID。如trx_state的状态为LOCK WAIT,那么该值代表当前的事务等待之前事务占用锁资源的ID。若trx_state不是LOCK WAIT,则该值为NULL。
  5. trx_wait_started:事务等待开始的时间。
  6. trx_weight:事务的权重,反映了一个事务修改和锁住的行数。在InnoDB存储引擎中,当发生死锁需要回滚时,InnoDB存储引擎会选择该值最小的进行回滚。
  7. trx_mysql_thread_id:MySQL中的线程ID,SHOW PROCESSLIST显示的结果。
  8. trx_query:事务运行的SQL语句。在实际使用中发现,该值有时会显示为NULL(不知道是不是Bug)。

INNODB_LOCK_WAITS由4个字段组成:

  1. requesting_trx_id:申请锁资源的事务ID.
  2. requesting_lock_id:申请的锁的ID。
  3. blocking_trxid:阻塞的事务ID。
  4. blocking_trx_id:阻塞的锁的ID。

一致性非锁定读

一致性的非锁定行读(consistent nonlocking read)是指InnoDB存储引擎通过行多版本控制(multi versioning)的方式来读取当前执行时间数据库中行的数据。如果读取的行正
在执行DELETE、UPDATE操作,这时读取操作不会因此而会等待行上锁的释放,相反,InnoDB存储引擎会去读取行的一个快照数据

快照数据是指该行之前版本的数据该实现是通过Undo段来实现。而Undo用来在事务中回滚数据,因此快照数据本身是没有额外的开销。此外,读取快照数据是不需要上锁的,因为没有必要对历史的数据进行修改。

可以看到,非锁定读的机制大大提高了数据读取的并发性,在InnoDB存储引擎默认设置下,这是默认的读取方式,即读取不会占用和等待表上的锁。但是在不同事务隔离级别
下,读取的方式不同,并不是每个事务隔离级别下读取的都是一致性读。同样,即使都是使用一致性读,但是对于快照数据的定义也不相同。

快照

快照数据其实就是当前行数据之前的历史版本,可能有多个版本。一个行可能有不止一个快照数据。我们称这种技术为行多版本技术。由此带来的并发控制,称之为多版本并发控制(MultiVersionConcurrencyControl,MVCC)。

不同事务隔离级别下的快照

在Read Committed和Repeatable Read(InnoDB存储引擎的默认事务隔离级别)下,InnoDB存储引擎使用非锁定的一致性读。

在ReadCommitted事务隔离级别下,对于快照数据,非一致性读总是读取被锁定行的最新一份快照数据,这其实不太符合事务的隔离性原则。

在Repeatable事务隔离级别下和Repeatable Read事务隔离级别下,对于快照数据,非一致性读总是读取事务开始时的行数据版本

自增长和锁

从MySQL 5.1.22版本开始,InnoDB存储引擎中提供了一种轻量级互斥量的自增长实现机制,这种机制大大提高了自增长值插人的性能。InnoDB
存储引擎提供了一个参数innodb_autoinc_lock_mode,默认值为1。

另外,InnoDB存储引擎下,自增长值的列必须是索引,并且是索引的第一个列,如果是第二个列则会报错;而MyISAM存储引擎则没有这个问题

innodb_autoinc_lock_mode=1:·。对于在插入前就能确定行数的语句(Simple inserts),该值会用互斥量(mutex)去对内存中的计数器进行累加的操作

对于插入前不能得到确定行数的语句(Bulk inserts),还是使用传统表锁的AUTO-INC Locking方式。这样做,如果不考虑回滚操作,对于自增值的增长还是连续的。而且在这种方式下Statement-Based方式的Replication还是能很好地工作。需要注意的是,如果已经使用表锁(AUTO-INC Locing)的方式产生自增长的值,而这时需要再进行“Simple inserts”的操作时,还是要等待AUTO-INC Locking的释放。

innodb_autoinc_lock_mode=2在这个模式下,对于所有“INSERT-like”自增长值的产生都是通过互斥量,而不是AUTO-INC Locking的方式。显然,这是最高性能的方式。然而,这带来一定的问题。因为并发插人的存在,所以每次插人时,自增长的值可能不是连续的。此外,最重要的是,基于Statement-Base Replication会出现问题。因此,使用这个模式,任何时候都应该使用Row-Base Replication。这样才能保证最大的并发性能和Replication数据的同步。

外键和锁

前面已经介绍了外键,外键主要用于引用完整性的约束检查。在InnoDB存储引擎中,对于一个外键列,如果没有显式地对这个列加索引,InnoDB存储引擎自动对其加一个索引
因为这样可以避免表锁这比Oracle做得好,Oracle不会自动添加索引,用户必须自己手工添加,这也是导致很多死锁问题产生的原因。

对于外键值的插入或者更新,首先需要查询父表中的记录,即SELECT父表。但是对于父表的SELECT操作,不是使用一致性非锁定读的方式,因为这样会发生数据不一致的
问题,因此这时使用的是SELECT…LOCK IN SHARE MODE方式,主动对父表加一个S锁。如果这时父表上已经这样加X锁,那么子表上的操作会被阻塞,

锁的算法

InnoDB存储引擎有3中行锁的算法设计,分别是:

  1. Record Lock:单个行记录上的锁。
  2. Gap Lock:间隙锁,锁定一个范围,但不包含记录本身。
  3. Next-Key Lock:Gap Lock + Record Lock,锁定一个范围,并且锁定记录本身。

例子

对于:

select * from sys_user where user_id = 5 lock in share mode

如果主键5,前面的数字是1,间隙锁会锁住(1,5);不包括1,5,行锁会锁住1

Record Lock总是会去锁住索引记录。如果InnoDB存储引擎表建立的时候没有设置任何一个索引,这时InnoDB存储引擎会使用隐式的主键来进行锁定。

Next-Key Lock是结合了Gap Lock和Record Lock的一种锁定算法,在Next-Key Lock算法下,InnoDB对于行的查询都是采用这种锁定算法。对于不同SQL查询语句,可能设置共
享的(Share)Next-Key Lock和排他的(exlusive)Next-Key Lock。

锁的一些问题

丢失更新

丢失更新(lost update)是一个经典的数据库问题。实际上,所有多用户计算机系统
环境下有可能产生这个问题。简单说来,出现下面的情况时,就会发生丢失更新:
(1)事务T1查询一行数据,放人本地内存,并显示给一个终端用户User1。
(2)事务T2也查询该行数据,并将取得的数据显示给终端用户User2。
(3)User1修改这行记录,更新数据库并提交。
(4)User2修改这行记录,更新数据库并提交。
显然,这个过程中用户User1的修改更新操作“丢失”了。即第一次更新的值被第二次更新覆盖了

想要解决,就得把更新的行加一个排他锁

脏读

理解脏读之前,需要理解脏数据的概念。脏数据和脏页有所不同。

脏页指的是在缓冲池中已经被修改的页,但是还没有刷新到磁盘,即数据库实例内存中的页和磁盘的页中的数据是不一致的,当然在刷新到磁盘之前,日志都已经被写人了重做日志文件中。

而所谓脏数据,是指在缓冲池中被修改的数据,并且还没有被提交(commit)。对于脏页的读取,是非常正常的。脏页是因为数据库实例内存和磁盘的异步同步造成的,这并不影响数据的一致性。并且因为是异步的,因此可以带来性能的提高。而脏数据却不同,脏数据是指未提交的数据。如果读到了脏数据,即一个事务可以读到另外一个事务中未提交的据,则显然违反了数据库的隔离性。脏读指的就是在不同的事务下,可以读到另外事务未提交的数据,简单来说,就是可以读到脏数据。比如下面的例子所示:

不可重复读

不可重复读是指在一个事务内多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务的两次读数据之间,由于第二个事务的修改,第一个事务两次读到的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为不可重复读。

可重复读和脏读的区别是:脏读是读到未提交的数据;而不可重复读读到的确实是已经提交的数据,但是其违反了数据库事务一致性的要求。




大菜狗
5个月前

面试深入之java多线程

使用多线程的方式

1.继承Thread类

缺点:java语言不支持多继承

Thread类底层也是实现的Rannable,执行run方法的调用顺序与其执行顺序无关

2.实现Runnable接口

在run方法前添加 synchronized关键字,可以使多个线程在执行 run 方法时,以排队的方式进行处理。

多线程共享变量可能引发的问题

实例与变量的线程安全问题

1.在使用synchronized关键字修饰方法时,在多线程情况下会出现指令重排问题

在某些 JVM 中, i– 的操作要分成如下 3 步:
1)取得原有ⅰ值。
2)计算 i-1。
3)对i进行赋值。
在这3个步骤中,如果有多个线程同时访问,那么一定会出现非线程安全问题。

2.一个书中的案例:

用println打印全局变量的$i–$,在多线程环境下会引发线程安全问题,因为:

虽然$println()$方法在内部是同步的,但$i–$的操作却是在进入$println()$之前发生的,所以有发生非线程安全问题的概率,

常用方法

1.currentTread0方法

可以返回该方法在被哪个线程调用,书中案例为:构造方法被main线程调用,run方法被Thread线程调用

isAlive()方法

可以判断线程当前是否在活动状态

停止线程

1.interrupet()停止线程

书中案例:在for循环中停止的线程,for循环下面的语句还可以正常输出;要解决这一问题,可以将代码块放入try中,并在for循环内抛出异常

2.在sleep状态下停止线程

如果在sleep状态下停止线程,则会进入catch语句,并清除停止的状态值

如果先停止再sleep,则会进入catch

3.用stop()方法停止线程

会造成数据不一致的后果,所以已经作废

暂停线程

suspend与resume方法

缺点:

1.独占:在使用suspend与resume方法时,如果使用不当,极易造成公共的同步对象的独占,使得其他线程无法访问公共同步对象。

2.不同步:会造成因线程暂停导致数据不同步的情况

线程的优先级

可以使用setPriority()方法设置线程的优先级,优先级为$1-10$

优先级具有继承的特性:A线程调用的B线程,B线程会继承A线程的优先级

线程先执行不代表先执行完,线程的优先级具有随机性

守护线程

线程分为2种,一种为用户线程,一种为守护线程

main线程和GC线程是经典的两个守护线程

对象和变量的并发访问

“非线程安全”其实会在多个线程对同一个对象中的实例变量进行并发访问时发生,

产生的后果就是“脏读”,也就是取到的数据其实是被更改过的。而“线程安全”就是以获得的实例变量的值是经过同步处理的,不会出现脏读的现象。

方法内的变量是线程安全的

synchronized

1.锁的是谁?

关键字synchronized 取得的锁都是对象锁,而不是把一段代码或方法(函数)当作锁,哪个线程先执行带synchronized关键字的方法,哪个线程就持有该方法所属对象的锁 Lock;

也就是说,一个线程调用某个对象的方法时,这个对象就被锁住了,如果有另一个线程调用该对象的其他方法,就只能等待持有锁的线程把锁释放

但如果多个线程访问多个对象,则 JVM 会创建多个锁。

2.synchronized的性质

1.是可重入锁

可重人锁的概念是:自己可以再次获取自己的内部锁。
比如有1条线程获得了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获取这个对象的锁的时候还是可以获取的,如果不可重人的话,就会造成死锁。

2.是悲观锁

3.出现异常自动释放

4.同步不可继承

父类中的方法用synchronized修饰,子类在继承这个方法时,不会同时继承锁

3.弊端及其解决方案(同步代码块)

如果一个对象长时间的持有锁,其他对象只能等待,就会等待很久

解决方案:使用同步代码块

方法内部的同步代码块,形如:

synchronized (this) {
//you code
}

而不是在方法上加synchronized,这样就做到了:在方法中:不在代码块中的语句异步执行,代码块中的语句同步执行

当有多个同步代码块时,当线程访问一个同步代码块,其他代码块将被阻塞;即多个同步代码块之间也是同步(按顺序执行的)

synchronized与synchronized (this)都是锁的对象

4.synchronized与synchronized (this)异同

书上的大段原话

多个线程调用同一个对象中的不同名称的 synchronized 同步方法或 synchronized(this)同步代码块时,调用的效果就是按顺序执行,也就是同步的,阻塞的。这说明synchronized 同步方法或 synchronized(this)同步代码块分别有两种作用。

1.synchronized同步方法:

  1. 对其他synchronized 同步方法或 synchronized(this) 同步代码块调用呈阻塞状态。
  2. 同一时间只有一个线程可以执行 synchronized 同步方法中的代码。

2.synchronized(this)同步代码块

  1. 对其他synchronized 同步方法或 synchronized(this) 同步代码块调用呈阻塞状态。
  2. 同一时间只有一个线程可以执行 synchronized(this)同步代码块中的代码。

其实Java还支持对“任意对象”作为“对象监视器”来实现同步的功能。这个“任意对象”大多数是实例变量及方法的参数,使用格式为synchronized(非this对象).

5.同步代码块synchronized(任意对象)做对象监视器

1)当多个线程同时执行 synchronized(x)(} 同步代码块时呈同步效果。
2)当其他线程执行ⅹ对象中synchronized 同步方法时呈同步效果。
3)当其他线程执行ⅹ对象方法里面的synchronized(this)代码块时也呈现同步效果。
但需要注意:如果其他线程调用不加 synchronized 关键字的方法时,还是异步调用。

6.synchronized应用在静态方法前锁Class

和将 synchronized 关键字加到非static 方法上使用的效果是一样的。其实还是有本质上的不同的,synchronized 关键字加到static静态方法上是给 Class 类上锁,而synchronized 关键字加到非static 静态方法上是给对象上锁。

7.synchronized与String连用时的问题

synchronized(String)使用时会由于jvm中有string常量池缓存功能导致多个线程持有相同的锁,所以同步代码块不与String连用

如果非要实现字符串的操作可以用new String()解决,原因如下:

Object a = new String("A");
Object b = new String("B");
System.out.println(a.hashCode()==b.hashCode());
String c = "B";
String d = "B";
System.out.println(c.hashCode()==d.hashCode());
//输出结果为:
//false
//true

原因猜想:用new关键字,定义出两个不同的字符串对象,直接写两个相同的字符串,在常量池中是同一个对象

volatile

Java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。Java语言提供了volatile,在某些情况下比锁要更加方便。

与vlolatile实现相关一些名词解释

JMM名词解释.png

1)将当前处理器缓存行的数据写回到系统内存。
2)这个写回内存的操作会使在其他CPU里缓存了该内存地址的数据无效。

Java内存模型的基础

在并发编程中,需要处理两个关键问题:线程之间如何通信及线程之间如何同步

线程之间的通信机制有两种:共享内存消息传递

在执行程序时,为了提高性能,编译器和处理器常常会对指令做重排序。重排序分3种类型。

1)编译器优化的重排序。编译器在不改变单线程程序语义的前提下,可以重新安排语句
的执行顺序。
2)指令级并行的重排序。现代处理器采用了指令级并行技术(Instruction-Level
Parallelism,ILP)来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应
机器指令的执行顺序。
3)内存系统的重排序。由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上
去可能是在乱序执行。

2和3属于处理器重排序

JMM的编译器重排序规则会禁止特定类型的编译器重排
序(不是所有的编译器重排序都要禁止)。对于处理器重排序,JMM的处理器重排序规则会要
求Java编译器在生成指令序列时,插入特定类型的内存屏障(Memory Barriers,Intel称之为
Memory Fence)指令,通过内存屏障指令来禁止特定类型的处理器重排序。




大菜狗
5个月前

面试前必看基础sql语句

面试常用4表

学生表(Student)、课程表(Course)、成绩表(Score)以及教师信息表(Teacher)

建表

begin;
DROP TABLE IF EXISTS `Teacher`;

CREATE TABLE `Teacher`
(
    `Tno`       varchar(3)  NOT NULL comment '教师编号',
    `Tname`     varchar(4)  NOT NULL comment '老师姓名',
    `Tsex`      varchar(2)  NOT NULL comment '老师性别',
    `Tbirthday` date       DEFAULT NULL comment '老师生日',
    `Tprof`     varchar(6) DEFAULT NULL comment '老师职称',
    `Depart`    varchar(10) NOT NULL comment '老师专业',
    PRIMARY KEY (`Tno`)
) ENGINE = InnoDB
  CHARSET = utf8;


INSERT INTO `Teacher` ( `Tno`, `Tname`, `Tsex`, `Tbirthday`, `Tprof`
                      , `Depart`)
VALUES ('804', '李诚', '男', '1958-12-02', '副教授', '计算机系'),
       ('825', '王萍', '女', '1972-05-05', '助教', '计算机系'),
       ('831', '刘冰', '女', '1977-08-14', '助教', '电子工程系'),
       ('856', '张旭', '男', '1969-03-12', '讲师', '电子工程系');


DROP TABLE IF EXISTS `Course`;

CREATE TABLE `Course`
(
    `Cno`   varchar(5)  NOT NULL comment '课程号',
    `Cname` varchar(10) NOT NULL comment '查看名',
    `Tno`   varchar(3)  NOT NULL comment '授课教师编号',
    PRIMARY KEY (`Cno`),
    KEY `Tno` (`Tno`),
    CONSTRAINT `Course_ibfk_1` FOREIGN KEY (`Tno`) REFERENCES `Teacher` (`Tno`)
) ENGINE = InnoDB
  CHARSET = utf8;

INSERT INTO `Course` (`Cno`, `Cname`, `Tno`)
VALUES ('3-105', '计算机导论', '825'),
       ('3-245', '操作系统', '804'),
       ('6-166', '数字电路', '856'),
       ('9-888', '高等数学', '831');

/*Table structure for table `Score` */
DROP TABLE IF EXISTS `Score`;

/*Table structure for table `Student` */
DROP TABLE IF EXISTS `Student`;

CREATE TABLE `Student`
(
    `Sno`       varchar(3) NOT NULL comment '学生学号',
    `Sname`     varchar(8) NOT NULL comment '学生姓名',
    `Ssex`      varchar(2) NOT NULL comment '学生性别',
    `Sbirthday` date       DEFAULT NULL comment '学生出生年月',
    `Sclass`    varchar(5) DEFAULT NULL comment '学生所在班级',
    PRIMARY KEY (`Sno`)
) ENGINE = InnoDB
  CHARSET = utf8;

INSERT INTO `Student` (`Sno`, `Sname`, `Ssex`, `Sbirthday`, `Sclass`)
VALUES ('101', '李军', '男', '1976-02-20', '95033'),
       ('103', '陆君', '男', '1974-06-03', '95031'),
       ('105', '匡明', '男', '1975-10-02', '95031'),
       ('107', '王丽', '女', '1976-01-23', '95033'),
       ('108', '曾华', '男', '1977-09-01', '95033'),
       ('109', '王芳', '女', '1975-02-10', '95031');

/*Table structure for table `Teacher` */

CREATE TABLE `Score`
(
    `Sno`    varchar(3) NOT NULL comment '学号',
    `Cno`    varchar(5) NOT NULL comment '课程号',
    `Degree` decimal(4, 1) DEFAULT NULL comment '成绩',
    PRIMARY KEY (`Sno`, `Cno`),
    KEY `Cno` (`Cno`),
    CONSTRAINT `Score_ibfk_1` FOREIGN KEY (`Sno`) REFERENCES `Student` (`Sno`),
    CONSTRAINT `Score_ibfk_2` FOREIGN KEY (`Cno`) REFERENCES `Course` (`Cno`)
) ENGINE = InnoDB
  CHARSET = utf8;

INSERT INTO `Score` (`Sno`, `Cno`, `Degree`)
VALUES ('101', '3-105', '64.0'),
       ('101', '6-166', '85.0'),
       ('103', '3-105', '92.0'),
       ('103', '3-245', '86.0'),
       ('105', '3-105', '88.0'),
       ('105', '3-245', '75.0'),
       ('107', '3-105', '91.0'),
       ('107', '6-166', '79.0'),
       ('108', '3-105', '78.0'),
       ('108', '6-166', '81.0'),
       ('109', '3-105', '76.0'),
       ('109', '3-245', '68.0');

commit;

表内容

学生表图片.png

sql语句练习

1.查询与李军选至少一门相同课的所有学生姓名

select distinct Sname
from Student join Score on Student.Sno = Score.Sno
where Cno in (select distinct Cno from Student, Score where Student.Sno = Score.Sno and Sname = '李军');

2.查询与李军选至少2门相同课的所有学生姓名

select Sname
from score join Student on score.Sno = Student.Sno
where Cno IN (select distinct Cno from Student, Score where Student.Sno = Score.Sno and Sname = '李军') and Sname!='李军'
group by Score.Sno having count(*)>1;

3.查询与学号为101的同学选至少2门相同课的所有学生姓名

SELECT Sname
FROM student JOIN score s1 ON s1.Sno = student.Sno
WHERE EXISTS (
              SELECT Sno
              FROM score s2
              WHERE s1.Sno != 101 and
                      s2.Sno = 101 and
                      s1.Cno = s2.Cno
          )
GROUP BY s1.Sno
HAVING COUNT(Cno) > 1;







3张表

学生表(Student)、课程表(Course)、成绩表(Score)

建表

begin;
-- (1)创建Student表
CREATE TABLE Student
(
    Sno   CHAR(8) PRIMARY KEY,
    Sname CHAR(8),
    Ssex  CHAR(2) NOT NULL,
    Sage  INT,
    Sdept CHAR(20)
);
-- (2)创建Course表
CREATE TABLE Course
(
    Cno     CHAR(4) PRIMARY KEY,
    Cname   CHAR(40) NOT NULL,
    Cpno    CHAR(4),
    Ccredit SMALLINT
);
-- (3)创建SC表
CREATE TABLE SC
(
    Sno   CHAR(8),
    Cno   CHAR(4),
    Grade SMALLINT,
    CONSTRAINT `SC_ibfk_1` FOREIGN KEY (Sno) REFERENCES Student (Sno),
    CONSTRAINT `SC_ibfk_2` FOREIGN KEY (Cno) REFERENCES Course (Cno)

);



-- (6)修改表结构及约束
--  增加班级列
ALTER TABLE Student
    ADD Sclass char(4);
--  修改年龄列
ALTER TABLE Student
    MODIFY Sage smallint;
--  增加约束
ALTER TABLE Course
    ADD UNIQUE (Cname);
-- (7)删除表


-- (1)为Course表按课程名称创建索引
CREATE INDEX cname_index On Course (Cname);
-- (2)为Student表按学生姓名创建唯一索引
CREATE UNIQUE INDEX sname_index ON Student (Sname);
-- (3)为SC表按学号和课程号创建聚集索引
CREATE INDEX sno_cno_index On SC (Sno, Cno desc);

-- (4)为Course表按课程号创建唯一索引
CREATE UNIQUE INDEX iSCno ON Course (Cno);


-- 3.创建视图
-- 建立信息系学生的视图:

CREATE VIEW IS_Student
AS
SELECT Sno, Sname, Sage
FROM Student
WHERE Sdept = 'IS';


-- (1)插入到Student表

INSERT INTO Student
VALUES ('20100001', '李勇', '男', 20, 'CS', '1001'),
       ('20100002', '刘晨', '女', 19, 'CS', '1001');

INSERT INTO Student(Sno, Sname, Ssex, Sage, Sdept, Sclass)
VALUES ('20100021', '王敏', '女', 18, 'MA', '1002'),
       ('20100031', '张立', '男', 19, 'IS', '1003');

INSERT INTO Student(Sno, Sname, Ssex, sclass)
VALUES ('20100003', '刘洋', '女', '1001');


INSERT INTO Student(Sno, Sname, Ssex, Sage, Sdept, sclass)
VALUES ('20100010', '赵斌', '男', '19', 'IS', '1005');

INSERT INTO Student
VALUES ('20100022', '张明明', '男', 19, 'CS', '1002');


-- (2)插入到Course表

INSERT INTO Course(Cno, Cname, Cpno, Ccredit)
VALUES ('1', '数据库系统原理', '5', 4);
INSERT INTO Course(Cno, Cname, Cpno, Ccredit)
VALUES ('2', '高等数学', null, 2);
INSERT INTO Course(Cno, Cname, Cpno, Ccredit)
VALUES ('3', '管理信息系统', '1', 4);

-- 请写出插入其余行的插入语句,并插入数据。
INSERT INTO Course(Cno, Cname, Cpno, Ccredit)
VALUES ('6', '数据处理', null, '2');
INSERT INTO Course(cno, cname, cpno, ccredit)
values ('7', 'c语言', null, '4');

-- (3)插入到SC表
INSERT INTO SC
VALUES ('20100001', '1', 92);
INSERT INTO SC
VALUES ('20100002', '2', 80);
INSERT INTO SC(Sno, Cno)
VALUES ('20100003', '1');
INSERT INTO SC(Sno, Cno, Grade)
VALUES ('20100010', '3', null);

-- 请写出插入其余行的插入语句,并插入数据。
INSERT INTO SC
VALUES ('20100002', '2', 85);
INSERT INTO SC
VALUES ('20100002', '3', 88);
INSERT INTO SC
VALUES ('20100002', '1', 90);


commit ;

表内容

学校数据库实验student表.png

sql语句练习

1.为SC表按学号和课程号创建聚集索引

CREATE CLUSTERED INDEX iSnoCno On SC(Sno,Cno desc)

3.为Course表按课程号创建唯一索引

CREATE UNIQUE INDEX iSCno ON Course(Cno)

4.填写赵斌同学的管理信息系统课程的成绩

UPDATE SC SET Grade = 85
 WHERE Sno='20100010' AND Cno='3'

5.将计算机科学系全体学生的成绩加5分

UPDATE sc SET Grade=Grade + 5
 WHERE 'CS'=(select Sdept from student where student.Sno=sc.Sno)

删除计算机科学系所有学生的选课记录

DELETE FROM SC WHERE 'CS'=(select Sdept from student where student.Sno=SC.Sno );

查询全体学生的姓名、出生年份和所有系,要求用小写字母表示所有系名。

SELECT Sname, 'Year of Birth:' as BIRTH, 2000-Sage BIRTHDAY, DEPARTMENT = LOWER(Sdept)
FROM Student;

查询选修了课程的学生学号:比较ALL和DISTINCT的区别

SELECT Sno FROM SC;
SELECT DISTINCT Sno FROM SC;

按范围查询
查询年龄在20~23岁之间的学生的姓名、系别和年龄

SELECT Sname,Sdept,Sage FROM Student WHERE Sage BETWEEN 20 AND 23

查询属性值属于指定集合的行
查询信息系(IS)、数学系(MA)和计算机科学系(CS)学生的姓名和性别

SELECT Sname,Ssex FROM Student WHERE Sdept IN ('IS','MA','CS');

模糊查询
查询所有姓刘学生的姓名、学号和性别

SELECT Sname,Sno,Ssex FROM Student WHERE Sname LIKE '刘%'

查询空值
查询缺少成绩的学生的学号和相应的课程号

SELECT Sno,Cno FROM sc WHERE Grade is null;





大菜狗
5个月前

关于服务器自动化配置的一些操作

自动化配置服务器,其本质就是开机自动运行脚本

开机自动运行脚本的思路

1.以某一用户身份去登陆服务器,在linux系统下会默认运行用户家目录下的.bashrc 配置文件

2.linux或unix系统下,/etc/rc.d/rc.local 用于添加开机启动命令

问题:基于 Debian 的 Linux 系统默认支持 rc-local.service 服务,这个服务主要用来在系统启动时运行用户自定义的脚本命令等。只有在centos或Ubuntu16以下的才有。

3.对于docker容器内脚本自运行的方法,是在dockerFile 中用 ENTRYPOINT[/bin/bash,脚本]

docker-compose启动容器后执行脚本或命令不退出 | 运行内部程序

知道了以上的思路,我们想开机自动执行某脚本的思路是:

1.在.bashrc中执行对应脚本

2./etc/rc.local是/etc/rc.d/rc.local的软连接,软连接相当于windows的快捷键

研究.bashrc

让我们来看一下阿里云ubuntu20.04的默认.bashrc,(我把其中的英文注释都翻译的一遍)

# ~.bashrc:由 bash(1) 为非登录 shell 执行。有关别名定义的示例,请参见 usrsharedocbashexamplesstartup-files(在 bash-doc 包中)。
# 您可能希望将所有添加到一个单独的文件中,例如 ~.bash_aliases,而不是直接在此处添加它们。
# 请参阅 bash-doc 包中的 usrsharedocbash-docexamples。

# 如果不以交互方式运行,则不要执行任何操作
[ -z "$PS1" ] && return

# 不要在历史记录中放置重复的行。有关更多选项,请参见 bash(1)
# ...或强制ignoreups和ignorespace
HISTCONTROL=ignoredups:ignorespace

# 追加到历史文件,不要覆盖它
shopt -s histappend

# 要设置历史长度,请参见 bash(1) 中的 HISTSIZE 和 HISTFILESIZE
HISTSIZE=1000
HISTFILESIZE=2000

# 检查每个命令后的窗口大小,如有必要,
# 更新 LINES 和 COLUMNS 的值。
shopt -s checkwinsize

# 对非文本输入文件更友好,请参阅lesspipe(1)
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"

# 设置变量标识您工作的 chroot(在下面的提示中使用)
if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then
    debian_chroot=$(cat /etc/debian_chroot)
fi

# 设置一个花哨的提示(非颜色,除非我们知道我们“想要”颜色)
case "$TERM" in
    xterm-color) color_prompt=yes;;
esac

# 如果终端有能力,取消注释彩色提示;转身
# 默认关闭以不分散用户的注意力:终端窗口中的焦点
# 应该在命令的输出上,而不是在提示符上
# 强制颜色提示=是

if [ -n "$force_color_prompt" ]; then
    if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
    # 我们有颜色支持;假设它符合 Ecma-48
    # (ISOIEC-6429)。 (缺乏这样的支持是极其罕见的,而且这样的
    # 案例倾向于支持 setf 而不是 setaf。)
    color_prompt=yes
    else
    color_prompt=
    fi
fi

if [ "$color_prompt" = yes ]; then
    PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
else
    PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
fi
unset color_prompt force_color_prompt

# 如果这是一个 xterm,则将标题设置为 user@host:dir
case "$TERM" in
xterm*|rxvt*)
    PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"
    ;;
*)
    ;;
esac

# 启用 ls 的颜色支持并添加方便的别名
if [ -x /usr/bin/dircolors ]; then
    test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
    alias ls='ls --color=auto'
    #别名 dir='dir --color=auto'
    #别名 vdir='vdir --color=auto'

    alias grep='grep --color=auto'
    alias fgrep='fgrep --color=auto'
    alias egrep='egrep --color=auto'
fi

# 更多 ls 别名
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'

# ~.bashrc:由 bash(1) 为非登录 shell 执行。有关别名定义的示例,
# 请参见 usrsharedocbashexamplesstartup-files(在 bash-doc 包中)。
# 您可能希望将所有添加到一个单独的文件中,例如 ~.bash_aliases,
# 而不是直接在此处添加它们。请参阅 bash-doc 包中的 usrsharedocbash-docexamples。

if [ -f ~/.bash_aliases ]; then
    . ~/.bash_aliases
fi

# 启用可编程完成功能(您不需要启用,如果 /etc/bash.bashrc and /etc/profile/sources /etc/bash.bashrc 已经启用 
#if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
#    . /etc/bash_completion
#fi

下面是一段.bashrc详细的说明:

如果你运行一个基于 Unix 或者类 Unix 的操作系统,bash 很有可能是作为默认终端被安装的。虽然存在很多不同的 shell,bash 却是最常见或许也是最主流的。如果你不明白那意味着什么,bash 是一个能解释你输入进终端程序的东西,并且基于你的输入来运行命令。它在一定程度上支持使用脚本来定制功能,这时候就要用到 .bashrc 了。

为了加载你的配置,bash 在每次启动时都会加载 .bashrc 文件的内容。每个用户的 home 目录都有这个 shell 脚本。它用来存储并加载你的终端配置和环境变量。

终端配置可以包含很多不同的东西。最常见的,.bashrc 文件包含用户想要用的别名。别名允许用户通过更短的名字或替代的名字来指向命令,对于经常在终端下工作的人来说这可是一个省时利器。

总结.bashrc的作用

1.配置命令的一些别名

2.配置颜色支持

3.在bash终端被启动时,执行文件中的一些shell语句

一个实际的案例

对于一个把所有服务都放在一个容器中的项目,启动项目需要运行多个环境

由于有多个需要一直启动的服务,所以需要通过shell来操作tmux,来同时运行多个服务

启动每个项目的脚本runacapp:

#! /bin/bash


USER_PASSWORD=
USERNAME=doctao
WORKDIR=/home/$USERNAME/acapp
#
cd $WORKDIR || exit
#su- $USERNAME

echo $USER_PASSWORD | sudo -S /etc/init.d/nginx start
echo $USER_PASSWORD | sudo -S redis-server /etc/redis/redis.conf

# 后台新建一个session
tmux new-session -d -s acapp_workspace

#向选择的窗口发送指令

tmux send-keys "uwsgi --ini scripts/uwsgi.ini" C-m

#多次切割后每个小窗口的编号会变化
tmux split-window -v

#启动`django_channels`服务

tmux send-keys "daphne -b 0.0.0.0 -p 5015 acapp.asgi:application" C-m

#多次切割后每个小窗口的编号会变化

#该命令会把当前工作区域分成左右两个小窗格,光标会移动到右面的窗口
tmux split-window -h

tmux send-keys "cd match_system/src/" C-m
tmux send-keys "chmod +x main.py" C-m
tmux send-keys "./main.py" C-m


#tmux select-pane -t 1
#tmux send-keys "command" C-m
#tmux send-keys "cd /home/zcmlc/go/src/zcm_activity" C-m
#tmux select-pane -t 2
#tmux send-keys "mysql -uroot -p123456 --host 192.168.1.221 --sigint-ignore --auto-vertical-output" C-m
#tmux send-keys "use data" C-m
#tmux -2 attach-session -t ssh  //挂载到之前运行的session上

想要在容器启动时自运行这个脚本,只需要在 .bashrc 中添加:

if [ -f /home/doctao/acapp/runacapp.sh ]; then
      bash /home/doctao/acapp/runacapp.sh
fi

关于配置容器ssh连接的方法

想要容器可以被ssh,需要sshd

要想在镜像构建时下载sshd,或其他各种软件时,会碰到如下问题:

1.容器是一个极简的操作系统,容器中自带的软件源几乎没有东西可以下载

2.在运行语句时,一旦某一句下载命令失败,构建会停止,如果选择 -y,也需要输出错误日志

3.sshd要想可以连接,需要更改配置文件参数

4.由于需要copy一些配置文件,需要解决跨系统传输时文件格式的问题(行末的\n)

apt-get命令详解(超详细)

1.下载问题的解决

要想让容器可以下载软件,必须更换软件源

方法

1.阿里源/etc/apt/sources.list的文件内容

deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse

2.将阿里源写在文件中通过dockerfile中的COPY命令将文件传在容器中

# 更换阿里源
COPY ./db/sources.list /etc/apt/sources.list

3.要想成功使用阿里源,必须安装其共钥,具体公钥的key,需要先运行一遍看一下日志中缺少的key

apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 467B942D3A79BD29
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3B4FE6ACC0B21F32
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 871920D1991BC93C
#每一行最后的一串字符,就是在日志中需要你自己找的key

4.更新软件源的命令

 #更新软件源
 apt-get clean
 apt-get update

5.下载必要软件

apt-get -y install vim
apt-get -y install openssh-server
apt-get -y install tofrodos

6.想要用户可以远程ssh登陆容器,必须修改配置文件/etc/ssh/sshd_config

将配置信息写入文件

echo 'RSAAuthentication yes \n\
        PubkeyAuthentication yes \n\
        AuthorizedKeysFile .ssh/authorized_keys \n\
        PermitRootLogin yes \n\
        ClientAliveInterval 60'\
>> /etc/ssh/sshd_config

7.将容器运行自启后的脚本文件放入容器并修正其格式,并放入.bashrc配置文件

#将开机运行脚本放入容器
COPY ./db/startup_run.sh /root/startup_run.sh

#修正文件格式
RUN fromdos /root/startup_run.sh

#添加脚本的运行权限
RUN chmod +x /root/startup_run.sh

#将bashrc脚本放入容器
COPY ./db/.bashrc /root/.bashrc

#修正文件格式
RUN fromdos /root/.bashrc

8.容器的root账户是默认没有密码的,需要设置一个密码

#添加root用户的密码
RUN  echo root:密码|chpasswd



大菜狗
5个月前

本地Git仓库关联多个远程仓库的两种方法

背景

通常情况下,一个本地Git仓库对应一个远程仓库,每次pullpush仅涉及本地仓库和该远程仓库的同步;然而,在一些情况下,一个本地仓库需要同时关联多个远程仓库,比如:同时将一个项目发布在GithubCoding上,以兼顾国内外的访客。

那么,如何让一个本地仓库同时关联多个远程仓库呢?

方法1:每次pushpull时需分开操作

首先,查看本地仓库所关联的远程仓库:(假定最初仅关联了一个远程仓库)

$ git remote -v
origin  git@github.com:keithnull/keithnull.github.io.git (fetch)
origin  git@github.com:keithnull/keithnull.github.io.git (push)

然后,用git remote add <name> <url>添加一个远程仓库,其中name可以任意指定(对应上面的origin部分),比如:

$ git remote add coding.net git@git.coding.net:KeithNull/keithnull.github.io.git

再次查看本地仓库所关联的远程仓库,可以发现成功关联了两个远程仓库:

$ git remote -v
coding.net      git@git.coding.net:KeithNull/keithnull.github.io.git (fetch)
coding.net      git@git.coding.net:KeithNull/keithnull.github.io.git (push)
origin  git@github.com:keithnull/keithnull.github.io.git (fetch)
origin  git@github.com:keithnull/keithnull.github.io.git (push)

此后,若需进行push操作,则需要指定目标仓库,git push <repo> <branch>,对这两个远程仓库分别操作:

$ git push origin master
$ git push coding.net master

同理,pull操作也需要指定从哪个远程仓库拉取,git pull <repo> <branch>,从这两个仓库中选择其一:

$ git pull origin master
$ git pull coding.net master

方法2:pushpull无需额外操作

在方法1中,由于我们添加了多个远程仓库,在pushpull时便面临了仓库的选择问题。诚然如此较为严谨,但是在许多情况下,我们只需要保持远程仓库完全一致,而不需要进行区分,因而这样的区分便显得有些“多余”。

同样地,先查看已有的远程仓库:(假定最初仅关联了一个远程仓库)

git remote -v
origin  git@github.com:keithnull/keithnull.github.io.git (fetch)
origin  git@github.com:keithnull/keithnull.github.io.git (push)

然后,不额外添加远程仓库,而是给现有的远程仓库添加额外的URL。使用git remote set-url -add <name> <url>,给已有的名为name的远程仓库添加一个远程地址,比如:

git remote set-url --add origin git@gitee.com:liuyutaocode/web-multiplayer-online-games.git

再次查看所关联的远程仓库:

git remote -v
origin  git@github.com:keithnull/keithnull.github.io.git (fetch)
origin  git@github.com:keithnull/keithnull.github.io.git (push)
origin  git@git.coding.net:KeithNull/keithnull.github.io.git (push)

可以看到,我们并没有如方法1一般增加远程仓库的数目,而是给一个远程仓库赋予了多个地址(或者准确地说,多个用于push的地址)。

因此,这样设置后的pushpull操作与最初的操作完全一致,不需要进行调整。

总结

以上是给一个本地仓库关联多个远程仓库的两种方法,二者各有优劣,不过出于简便考虑,我最终采用了方法2。

此外,上述内容中涉及到的Git指令略去了许多不常用的参数,如需更加详细的说明,可以查阅Git文档,或者直接在命令行运行git remote --help




大菜狗
5个月前

WordPress建站踩坑历程

搭建

docker官方wordpress

为了后期的维护,在docker-compose.yml中配置端口映射的同时,添加对22端口的映射

主题

WordPress 主题 Sakura 🌸 | 樱花庄的白猫 (2heng.xin)

WordPress Sakura主题配置博客

Hexo 博客美化

hexo+sakura主题美化合集

容器管理

1.更新软件园

apt-get update

2.下载ssh

apt-get install ssh

3.下载git

apt-get install git

4.创建.git,并在其中生成密钥


5.想要容器可以被ssh,需要sshd

sudo apt-get install openssh-server
sudo /etc/init.d/ssh start

6.

#启用公钥私钥配对认证方式 
PubkeyAuthentication yes 
#公钥文件路径(和上面生成的文件同)
AuthorizedKeysFile .ssh/authorized_keys  
PermitRootLogin yes #root能使用ssh登录
#参数数值是秒 , 是指超时时间
ClientAliveInterval 60  
#设置允许超时的次数
ClientAliveCountMax 3 

阿里源镜像

FROM ubuntu:20.04

RUN mv /etc/apt/sources.list /etc/apt/sources.list.bak && \
    echo "deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted" >/etc/apt/sources.list && \
    echo "deb http://mirrors.aliyun.com/ubuntu/ focal universe" >/etc/apt/sources.list && \
    echo "deb http://mirrors.aliyun.com/ubuntu/ focal-updates universe" >/etc/apt/sources.list && \
    echo "deb http://mirrors.aliyun.com/ubuntu/ focal multiverse" >/etc/apt/sources.list && \
    echo "deb http://mirrors.aliyun.com/ubuntu/ focal-updates multiverse" >/etc/apt/sources.list && \
    echo "deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse" >/etc/apt/sources.list && \
    echo "deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted" >/etc/apt/sources.list && \
    echo "deb http://mirrors.aliyun.com/ubuntu/ focal-security universe" >/etc/apt/sources.list && \
    echo "deb http://mirrors.aliyun.com/ubuntu/ focal-security multiverse" >/etc/apt/sources.list

插件

链接管理跳转 Pretty Links

docker容器下mysql更改WordPress的site address和home(URL)------局域网 - dora_shao - 博客园 (cnblogs.com)