https://www.nowcoder.com/discuss/369302?type=2&order=0&pos=1&page=1来源:牛客网
为什么想做测试
以前实习是怎么测试的 没有实习过 所以没谈了
如果打不开百度网页,怎么排查错误
测试删除文件功能
http状态码都说一下 单独问了404
https了解吗http+ssl
数据库内连接外连接左连接右连接 用得不多 所以没继续问了
想怎么建立索引?学生学号姓名年级成绩老师入学时间 可以根据什么来建立索引
linux常用命令 管道有常用吗
https://www.nowcoder.com/discuss/249789?type=2&order=0&pos=5&page=1来源:牛客网
***一面 1H2MIN* **
**1. 解释一些项目;
\2. linux常用指令;
\3. sql了解吗?
\4. 网络基础知识:http中的get和post有什么区别;
\5. tcp三次握手、四次挥手
\6. 测试登录功能【编写测试用例】
\7. 智力题:一根绳子烧尽60分钟,怎么烧出75分钟。
\8. new和malloc的区别
**
二面 20MIN 1. 介绍项目
\2. 一瓶水怎么进行测试(口述测试用例)
这个面试进行的比较糟心,就是全程我自己在表演,时间有点久了也有点记不住了。
三面 10MIN
主要就是hr考察一下你留在深圳的可能性,舔的太厉害有点后悔。然后就是问你的期望待遇,由于舔的太厉害说的很低,有点后悔。
https://www.nowcoder.com/discuss/247222?type=2&order=0&pos=6&page=1来源:牛客网
判断两个数组中是否存在相同的数字,两个已经排好序的数组,写代码判断这两个数组中是否存在相同的数字?要求时间复杂度越低越好。
讲输入 url 到页面呈现的过程(下面几个很细节的问)
拿到 http 响应后,怎么渲染页面,html 的组成,js、css 这些静态文件是存在哪里?(不清楚前端,瞎讲,我说到 http 缓存,面试官一脸疑惑,我也搞不懂)
服务端有很多服务,关于 http、ftp 等等,怎么知道你发的是 http 请求,我要响应的是 http 请求(端口)
客户端向服务器发一个 1kb 数据,怎么保证是无损传输(答 tcp 保证可靠传输,超时重传和 seq/ack 机制
一个 tcp 链接最多能同时发多少个 http 请求(可能是这个问题,记不清,又引申到高并发)
有没有了解高并发,我说不了解,问不了解的话,那但你从学过的计算机基础知识,来看怎么实现这个过程(凉凉,完全不了解,一顿瞎扯)
老板给一个需求,不具体,输入一个生日,实现生日前一天给人发邮件祝福,从产品、开发、测试角度来怎么设计、怎么实现、怎么测试(说产品的时候,告诉我要多问,去细化需求)
如果要实现生日可以修改,一直往后面推,怎么做(我说直接覆盖数据库的数据,他最后说需要设置一个用户登录之类的)
这个数据库要有哪些字段
实现方面,还问你怎么能每天去执行,谁去扫库吗,我说可以用 linux crontab 去设置定时任务,每天去扫库(瞎扯,不懂后台)
测试方面,说还要考虑一年的最后一天的跳转,闰年之类的
问对深圳,对未来有什么规划
问想做前端方面还是后台服务器方面
另外附上一面面经
\1. 讲项目
\2. 编程,找出一个字符串中所有回文子串(长度 >=3,长度为奇数的),并记录他的起始位置(暴力)
\3. linux 命令讲一下,打印某个进程查询出来的第二列(pid)
\4. 在 student_course 表(sid, cid, score) 查询课程 1(cid=1) 成绩第2高的学生.
\5. appium 的原理了解吗
\6. 实习用到哪些测试理论
\7. 测 QQ 登录页面
\8. 性能测试除了时间、并发还有哪些? (面试官说到错误率)
\9. http 有状态吗? cookie 和 session 区别,既然 session 比 cookie 更好,那只用 session 可以吗? http 缓存知道吗? keep-alive?
https://www.nowcoder.com/discuss/238991?type=2&order=0&pos=7&page=1来源:牛客网
自我介绍
讲项目
Linux用过哪些基础命令
查看某个日志(cat)
查找关键字的错误(grep)
数据库按某列排序(order by)
数据库的内联和外联,左联和右联
数据库怎么分页
死锁,四个必要条件,怎么避免
给你一个杯子,要测试哪些属性
一个细胞,1s分裂一次,由一个变成两个,1分钟后填满一瓶子,问初始3个细胞,多久填满瓶子?
浏览器输入一个url,后面要经过哪些过程?
为什么发送http请求,却建立的是TCP连接?
服务器返回响应结果后,客户端要做什么?
https://www.nowcoder.com/discuss/379545?type=2&order=0&pos=1&page=1来源:牛客网
2.给一个有序数组和它的大小,给定一个val,求这个数组里有没有这个val,有或者有不止一个的话,求第一次出现这个 val 的位置;
3.按照简历上面的语言提问(栽了 T-T );
4.给一瓶矿泉水,怎么测试;
5.开发说没有办法解决的bug,你会怎么做;
6.有什么想问的
https://www.nowcoder.com/discuss/379510?type=2&order=0&pos=2&page=1来源:牛客网
自我介绍
项目情况,主要负责什么功能(我自己说了他没问了)
如何分析ANR和崩溃,发生的时候怎么做(因为项目情况里说了)
有没有用过抓包软件
测试用例题:测试一瓶矿泉水
场景题:如果开发说这个bug他无法解决或者不解决,怎么办
多表查询(我答了会用到内外链接。。他就说我错了)
事务一致性
数据索引优缺点
对加班怎么看
对自己学习能力怎么判断,如果吸收能力弱是否会花时间跟上团队节奏
https://www.nowcoder.com/discuss/379343?type=2&order=0&pos=4&page=1来源:牛客网
中间还问了。数据库。索引的优缺点。还有一个概念我不记得了。
web访问域名经过啥步骤。
tcp三次握手。
进程和线程的区别。
线程同步。
黑盒白盒的方法。
https://www.nowcoder.com/discuss/378375?type=2&order=0&pos=5&page=1来源:牛客网
数据库:索引的作用|group by|聚合函数|连接
数据结构:队和栈的区别|树的遍历|求一棵树的镜像|排序算法|
操作系统:线程和进程区别|
项目介绍|难点|编程语言
http和https的区别?
作者:大树555
https://www.nowcoder.com/discuss/167676?type=2&order=3&pos=14&page=1来源:牛客网
1、tcp和udp的区别并说说他们实际的应用场景
2、说说tcp滑动窗口机制,还有是怎么实现的
3、http和HTTPS区别
4、三次握手四次挥手
二、数据结构和算
1、数组和链表区别
2、说说你了解的排序算法
三、操作系统
1、进程和线程区别
2、什么是死锁,出现死锁如何解决
四、测试
1、给一个登陆界面,设计相关测试用例
2、给一段代码输入两个数还有操作符,也就是计算两个数加减乘除。设计相关测试用例
五、数据库
1.常见的增删改查
2.连表查询
3.数据库存储过程和触发器区别
六、程序题
1、给三个数值,根据大小,输出中间那个数
2、求N阶矩阵的对角线数值之和
3、N个人,互相交换礼物,每个人不能拿到自己的礼物。设计一种算法
超文本传输协议
https://harttle.land/2015/08/10/cookie-session.html
作者:woow_wu7链接:https://juejin.im/post/5e2aaa406fb9a02fb75d68df来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
分类 | 描述 |
---|---|
1** | 指示信息-收到请求,继续处理 |
2** | 成功-请求被成功接收 |
3** | 重定向-需要进一步的操作,以完成请求 |
4** | 客户端错误-请求包含语法错误或无法完成请求 |
5** | 服务器错误-服务器在处理请求的过程中发生了错误 |
作者:吾儿滨滨链接:https://juejin.im/post/5e4d5af7518825492442c55d来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
200(OK):请求成功。
206(Partial Content):客户端发送了一个Range的get请求,服务器完成了它。
301 (Moved Permanently):永久重定向至新的 url。
302(Found):临时重定向至新的url。
304(Not Modified):服务器告诉浏览器缓存可以继续使用。
400(Bad Request):客户端请求有语法错误,服务器理解不了。
401 (Unauthorized/未授权)
403(Forbidden):请求页面禁止访问。
404 (Not Found):请求资源不存在。
**500 (Internal Server Error):**服务器内部错误,无法完成请求。
501 | 服务器不支持当前请求所需要的某个功能。当服务器无法识别请求的方法,并且无法支持其对任何资源的请求。 |
---|---|
502 | 作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。 |
作者:吾儿滨滨链接:https://juejin.im/post/5e4d5af7518825492442c55d来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
https://juejin.im/post/5e5152be6fb9a07ce31ee4bd#heading-25
1. DNS域名解析 // 将域名解析成IP地址
2. 建立TCP链接 // 三次握手
3. 客户端发起HTTP请求
4. 服务器处理请求,并返回HTTP报文
5. 浏览器解析渲染页面
6. 断开TCP链接 // 四次挥手
( 浏览器 ) 中查询 DNS 缓存,有则进入建立tcp链接阶段,下面同理
( 本机的系统 )中查询 DNS 缓存
( 路由器 ) 中查询 DNS 缓存
( 运营商服务器 ) 中查询 DNS 缓存
递归查询 // 根域名/一级域名/二级域名 …blog.baidu.com
建立tcp链接 // 三次握手
第一次握手
第二次握手
第三次握手
客户端发送一个 SYN=0,ACK=1,确认号Ack=y+1,序号Seq=x+1的确认包给服务器
为什么需要三次握手
客户端发送http请求
服务端处理请求,并返回http响应报文
浏览器解析渲染
IP 用于计算机之间的通信。
IP 是无连接的通信协议。它不会占用两个正在通信的计算机之间的通信线路。这样,IP 就降低了对网络线路的需求。每条线可以同时满足许多不同的计算机之间的通信需要。
通过 IP,消息(或者其他数据)被分割为小的独立的包,并通过因特网在计算机之间传送。
IP 负责将每个包路由至它的目的地。
TCP/IP 意味着 TCP 和 IP 在一起协同工作。
TCP 负责应用软件(比如你的浏览器)和网络软件之间的通信。
IP 负责计算机之间的通信。
TCP 负责将数据分割并装入 IP 包,然后在它们到达的时候重新组合它们。
IP 负责将包发送至接受者。
在HTTP/1.0中,默认使用的是短连接。也就是说,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接。
但从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头有加入这行代码:Connection:keep-alive
在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的 TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接要客户端和服务端都支持长连接。
域名系统(英文:Domain Name System,缩写:DNS)是互联网的一项服务。它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。DNS使用TCP和UDP端口53[1]。
TCP的主要特点是:
UDP的主要特点是:
采用TCP,一旦发生丢包,TCP会将后续的包缓存起来,等前面的包重传并接收到后再继续发送,延时会越来越大。
UDP对实时性要求较为严格的情况下,采用自定义重传机制,能够把丢包产生的延迟降到最低,尽量减少网络问题对游戏性造成影响。
TCP: 文件传输、发送接收邮件,远程登录。
UDP:( 对数据准确性和丢包要求比较低,但速度必须快 )在线视频,语音电话、游戏等
[1] 确认和重传机制
建立连接时三次握手同步 号 + 窗口大小信息”,是确认重传、流控的基础传输过程中,如果Checksum校验失败、丢包或延时,发送端重传。
[2] 数据排序
[3] 流量控制
滑动窗口和计时器的使用。TCP窗口中会指明双方能够发送接收的最大数据量,发送方通过维持一个发送滑动窗口来确保不会发生由于发送方报文发送太快接收方无法及时处理的问题。
[4] 拥塞控制
TCP的拥塞控制由4个核心算法组成:
“慢启动”(Slow Start)
“拥塞避免”(Congestion avoidance)
“快速重传 ”(Fast Retransmit)
“快速恢复”(Fast Recovery)
https://blog.csdn.net/hyg0811/article/details/102366854
ACK是标志位、 确认号ack 、初始序列号seq、SYN同步序列编号
三次握手:
四次挥手
为什么要使用ARP协议
OSI模型把网络工作分为七层,彼此不直接打交道,只通过接口(layer interface)。IP地址工作在第三层,MAC地址工作在第二层。当协议在发送数据包时,需要先封装第三层IP地址,第二层MAC地址的报头,但协议只知道目的节点的IP地址,不知道目的节点的MAC地址,又不能跨第二、三层,所以得用ARP协议服务,来帮助获取到目的节点的MAC地址。
ARP协议是第几层协议
工作在二层,是三层协议。
ARP在生成环境产生的问题及解决办法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HY9mCqsr-1585126522514)(C:\Users\zhangboyi\AppData\Roaming\Typora\typora-user-images\1584096807131.png)]
1、查询DNS,获取域名对应的ip
2、得到目标服务器的IP地址以及其端口号,调用系统库socket函数,请求一个TCP流套接字,客户端向服务器发送http请求报文:
3、服务器端经过物理层、数据链路层、网络层、传输层、应用层,解析请求报文,发送http响应报文
html页面的解析与渲染
1.PC网络故障
2.400客户端出错
3.401服务器拒绝提供服务
5.500服务器内部错误
6.请求或者响应在网络传输中途被劫走了
7.可能是DNS出错了。
Socket
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,
图片中的数组的优缺点写错,参考下方
数组
数组是可以在内存中连续存储多个元素的结构,在内存中的分配也是连续的 。
其查询效率,修改的效率相对链表来说比较高。
插入、删除数据的时候
链表
栈
队列
散列表
散列表,也叫哈希表,是根据关键码和值 (key和value) 直接进行访问的数据结构,通过key和value来映射到集合中的一个位置,这样就可以很快找到集合中的对应元素。
树
红黑树
红黑树的特点:
速度特别快,趋近平衡树,查找叶子元素最少和最多次数不多于二倍。
节点可以是红色的或者黑色的
根节点是黑色的
叶子节点(特指空节点)是黑色的
每个红色节点的子节点都是黑色的
任何一个节点到其每一个叶子节点的所有路径上黑色节点数相同
堆
图
https://blog.csdn.net/racheil/article/details/90763011
public static void BubbleSort(int[] array){
for(int i=0;i<array.length-1;i++){// 趟数
for(int j=0;j<array.length-1-i;j++){//每趟比较次数
if(array[j]>array[j+1]){
int temp = array[j];
array[j] = array[j+1];
a[j+1] = temp;
}
}
}
}
基本思想:
每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。
public static void selectSort(int[] array){
for(int i=0;i<array.length;i++){
for(int j = i+1;j<array.length;j++){
if(array[i]>array[j]){//从小到大排序
int temp = array[i];
array[i]= array[j];
array[j] = temp;
}
}
}
}
//找基准,返回第一趟排序后的基准(low)的位置
public static int partion(int[] array,int low,int high){
int tmp=array[low];
//hign向前走找比tmp小的值
while(low<high){
while(low<high&&array[high]>=tmp){
high--;
}
if(low>=high){
array[low] = tmp;
break;
}else{
array[low] = array[high];
}
//low向后走找比tmp大的值
while(low<high&&array[low]<=tmp){
low++;
}
if(low>=high){ //low与high相遇,即没有比tmp大的值了,此时需把基准放在相遇的位置
array[low] = tmp;
break;
}else{
array[high] = array[low];
}
}
return low;//此时low和high相遇,返回第一趟排序后的基准(low)的位置
}
public static void quick(int[] array,int start,int end) {
int par = partion(array,start,end); //找基准
//递归左边
if(par>start+1){ //至少保证有两个数据
quick(array,start,par-1);
}
//递归右边
if(par<end-1){
quick(array,par+1,end);
}
}
public static void quickSort1( int[] array){
quick(array,0, array.length-1);
}
算法名称 | 平均时间复杂度 | 最好时间复杂度 | 最坏时间复杂度 | 空间复杂度 | 稳定性 |
---|---|---|---|---|---|
直接插入排序 | O(N^2) | O(N) | O(N^2) | O(1) | 稳定 |
希尔排序 | O(nlogn) | O(n^1.3) | O(n^2) | O(1) | 不稳定 |
选择排序 | O(N^2) | O(N^2) | O(N^2) | O(1) | 不稳定 |
冒泡排序 | O(N^2) | O(N) | O(N^2) | O(1) | 稳定 |
快速排序 | O(nlogn) | O(nlogn) | O(N^2) | O(logn)~ O(n) | 不稳定 |
归并排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 稳定 |
//版本1
public int BinarySearch(int ary[] ,int value ,int n){
int low,middle,high;
low = 0;
high = n-1;
while(low<high){
mid = low+(high-low)/2;
if(ary[mid] == value){
return mid;
}
if(ary[mid] > value){
high = mid-1;
}
if(ary[mid] < value){
low = mid+1;
}
}
//版本2
int BinarySearch2(int ary[] ,int value, int low ,int high){
int mid = low+(high-low)/2;
if(a[mid] == value)
return mid;
if(a[mid]>value)
return BinarySearch2(ary,value,low,mid-1);
if(a[mid]<value)
return BinarySearch2(ary,value,mid+1,high);
}
语法:grep 字符串 文件名|wc -l ,grep输出,wc -l按行统计
例子:
grep NullPointerException task-hbase-transform.log|wc -l
。grep 'objStr1\|objStr2' filename|wc -l
#直接用 | 链接起来即可。“|”: 管道符“|”将两个命令隔开,管道符左边命令的输出就会作为管道符右边命令的输入。连续使用管道意味着第一个命令的输出会作为第二个命令的输入,第二个命令的输出又会作为第三个命令的输入,依此类推。
df:(disk free)显示磁盘分区上可以使用的磁盘空间。
VI 显示所有行的行号:vi set number
找到共用80端口的线程
linux基本指令 awk、find、grep
shell脚本:统计一个文件中重复的行和重复次数
linux 如何将文件从一台服务器转移到另一台服务器
如何查找出现频率最高的100个ip地址
查看进程:
1、ps 命令用于查看当前正在运行的进程。
grep 是搜索
例如: ps -ef | grep java
2、查看自己的进程
ps -l
3、查看系统所有进程
ps aux
4、进程树
查看所有进程树
# pstree -A
查看占用端口的进程
示例:查看特定端口的进程
# netstat -anp | grep port
linux常用指令;
进程
进程是资源分配的基本单位。
线程
线程是独立调度的基本单位。
一个进程中可以有多个线程,它们共享进程资源
https://mp.weixin.qq.com/s/5CbYGrylSKx1JwtOiW3aOQ
管道:利用管道(“|”)的输入输出
消息队列(类似于缓存)
共享内存
分配给进程的内存不是实际物理内存,而是虚拟内存空间
信号量,相当于一个计数器。
socket
死锁是指两个或两个以上的线程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
鸵鸟策略
死锁检测与死锁恢复
一个资源的死锁检测:通过检测有向图是否存在环来实现 ( 深度优先搜索 )
恢复:抢占恢复、回滚恢复、杀死进程
死锁检测
死锁预防:
死锁避免
单表查询、多表查询、count、distinct、limit
数据库事务是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。
数据库事务拥有以下四个特性,被称之为ACID特性:
原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。
隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中
来源: https://baijiahao.baidu.com/s?id=1611918898724887602&wfr=spider&for=pc
读未提交(read uncommitted): 就是可以读到未提交的内容
在这种隔离级别下,查询是不会加锁的,也由于查询的不加锁,所以这种隔离级别的一致性是最差的,可能会产生“脏读”、“不可重复读”、“幻读”。
读已提交(read committed): 就是只能读到已经提交了的内容。
可重复读(repeated read): 就是专门针对“不可重复读”这种情况而制定的隔离级别
普通的查询同样是使用的“快照读”,但是,和“读提交”不同的是,当事务启动时,就不允许进行“修改操作(Update)”了
序列化(serializable)
这种级别下,事务“串行化顺序执行”,也就是一个一个排队执行。由于他大量加上锁,导致大量的请求超时,因此性能会比较底下,再特别需要数据一致性且并发量不需要那么大的时候才可能考虑这个隔离级别。
**“读未提(Read Uncommitted)”能预防啥?**啥都预防不了。
**“读提交(Read Committed)”能预防啥?**使用“快照读(Snapshot Read)”,避免“脏读”,但是可能出现“不可重复读”和“幻读”。
**“可重复读(Repeated Red)”能预防啥?**使用“快照读(Snapshot Read)”,锁住被读取记录,避免出现“脏读”、“不可重复读”,但是可能出现“幻读”。
**“串行化(Serializable)”能预防啥?**排排坐,吃果果,有效避免“脏读”、“不可重复读”、“幻读”,不过效果谁用谁知道。
数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。
一、按操作划分,可分为DML锁
(数据锁:data locks)、DDL锁
(dictionary locks,数据字典锁)
二、按锁的粒度划分,可分为表级锁
、行级锁
、页级锁
(mysql)
三、按锁级别划分,可分为共享锁
、排他锁
四、按加锁方式划分,可分为自动锁
、显示锁
五、按使用方式划分,可分为乐观锁
、悲观锁
顾名思义,很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人拿这个数据就会block(阻塞),直到它拿锁。
共享锁(S锁)
排他锁(X锁)
更新锁
因为当使用共享锁时,修改数据的操作分为两步:
- 首先获得一个共享锁,读取数据,
- 然后将共享锁升级为排他锁,再执行修改操作。
这样如果有两个或多个事务同时对一个事务申请了共享锁,在修改数据时,这些事务都要将共享锁升级为排他锁。这时,这些事务都不会释放共享锁,而是一直等待对方释放,这样就造成了死锁。
如果一个数据在修改前直接申请更新锁,在数据修改时再升级为排他锁,就可以避免死锁。
原文链接:https://blog.csdn.net/weixin_39651041/article/details/79985715
顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以,不会上锁。但是在更新的时候会判断一下在此期间别人有没有更新这个数据,可以使用版本号等机制。
版本号
时间戳
使用数据库服务器的时间戳
待更新字段
所有字段
并发控制会造成两种锁
活锁
定义:指的是T1封锁了数据R,T2同时也请求封锁数据R,T3也请求封锁数据R,当T1释放了锁之后,T3会锁住R,T4也请求封锁R,则T2就会一直等待下去。
解决方法:采用“先来先服务”策略可以避免。
死锁
定义:就是我等你,你又等我,双方就会一直等待下去。比如:T1封锁了数据R1,正请求对R2封锁,而T2封住了R2,正请求封锁R1,这样就会导致死锁,死锁这种没有完全解决的方法,只能尽量预防。
预防方法:
系统判定死锁的方法:
超时法:如果某个事物的等待时间超过指定时限,则判定为出现死锁;
等待图法:如果事务等待图中出现了回路,则判断出现了死锁。
1.脏读:
指一个事务A正在访问数据,并且对该数据进行了修改,但是这种修改还没有提交到数据库中(也可能因为某些原因Rollback了)。这时候另外一个事务B也访问这个数据,然后使用了这个被A修改的数据,那么这个数据就是脏的,并不是数据库中真实的数据。这就被称作脏读。
解决办法:把数据库事务隔离级别调整到READ_COMMITTED
即让用户在更新时锁定数据库,阻止其他用户读取,直到更新全部完成才让你读取。
2.幻读:
指一个事务A对一个表中的数据进行了修改,而且该修改涉及到表中所有的数据行;同时另一个事务B也在修改表中的数据,该修改是向表中插入一行新数据。那么经过这一番操作之后,操作事务A的用户就会发现表中还有没修改的数据行,就像发生了幻觉一样。这就被称作幻读。
解决办法:把数据库事务隔离级别调整到SERIALIZABLE_READ
3.不可重复读:
指在一个事务A内,多次读同一个数据,但是事务A没有结束时,另外一个事务B也访问该同一数据。那么在事务A的两次读数据之间,由于事务B的修改导致事务A两次读到的数据可能是不一样的。这就发生了在一个事务内两次读到的数据不一样,这就被称作不可重复读。
解决办法:把数据库事务隔离级别调整到REPEATABLE_READ
注:
级别高低:脏读 < 不可重复读 < 幻读
第一范式:保证列的原子性,保证列不可再分。
第二范式:唯一性 ;一个表只说明一个事物;有主键且非主键依赖主键;(限制多对多的关系,建立一个关联表,通过外键和联合主键来关联两张表)
第三范式:每列都与主键有直接关系,不存在传递依赖;(限制一对多的关系,在从表中建立一个外键,通过外键来引用主表的信息)
https://www.jianshu.com/p/be44d846929d
自连接
如果在一个连接查询中涉及的两个表其实是同一个表,这种查询称为自连接查询 。
//要查询王红所在的部门的所有员工
SELECT p1.* FROM employee AS p1 JOIN employee AS p2 ON p1.did=p2.did WHERE p2.name='王红';
外连接
左连接(left join):返回左表中的所有记录和右表中符合条件的记录
SELECT department.did,department.dname,employee.name
FROM department
LEFT JOIN employee ON department.did=employee.did
右连接(right join):返回右表中的所有记录和左表中符合条件的记录
select department.did,department.dname,employee.name
from department
right join employee on department.did=employee.did
内连接(inner join)
又称为自然连接,内连接使用比较运算符对两个表中的数据进行比较,并列出与连接条件匹配的数据行,组成新纪录。
SELECT employee.name,department.dname FROM department JOIN employee ON department.did=employee.did;
如果小的循环在外层,对于数据库连接来说就只连接5次,进行5000次操作,如果1000在外,则需要进行1000次数据库连接,从而浪费资源,增加消耗。这就是为什么要小表驱动大表。
GROUP BY子句必须出现在WHERE子句之后,ORDER BY子句之前.
HAVING语句必须在ORDER BY子句之后。
(where先执行,再group by分组;having,order by。)
SELECT
`user`.roleId,
COUNT(`user`.userId) as total
FROM `user`
where ustatus = 1
GROUP BY roleId
HAVING total >1
ORDER BY sex DESC
where和having区别:
1.having只能用在group by之后,对分组后的结果进行筛选(即使用having的前提条件是分组)。
2.where肯定在group by 之前,即也在having之前。
3.where后的条件表达式里不允许使用聚合函数,而having可以。
COUNT(*),COUNT(1),COUNT(column), COUNT(DISTINCT column)和COUNT(expression)
COUNT(*)
函数返回由SELECT语句返回的结果集中的行数。COUNT(*)
函数计算包含NULL
和非NULL
值的行,即:所有行。
count(1)这个用法和count(*)的结果是一样的
COUNT(DISTINCT column)
返回不包含NULL
值且不包含重复的记录算一条的唯一行数。
COUNT(column)
返回不包含NULL
值的所有行数
https://www.cnblogs.com/wwxzdl/p/11116446.html
数据库索引其实就是为了使查询数据效率快。
索引就是通过事先排好序,从而在查找时可以应用二分查找等高效率的算法。
索引的优点:
① 建立索引的列可以保证行的唯一性,生成唯一的rowId
② 建立索引可以有效缩短数据的检索时间
③ 建立索引可以加快表与表之间的连接
④ 为用来排序或者是分组的字段添加索引可以加快分组和排序顺序
索引的缺点:
① 创建索引和维护索引需要时间成本,这个成本随着数据量的增加而加大
② 创建索引和维护索引需要空间成本,每一条索引都要占据数据库的物理存储空间,数据量越大,占用空间也越大(数据表占据的是数据库的数据空间)
③ 会降低表的增删改的效率,因为每次增删改索引需要进行动态维护,导致时间变长
什么情况下需要建立索引
① 数据量大的,经常进行查询操作的表要建立索引。
② 用于排序的字段可以添加索引,用于分组的字段应当视情况看是否需要添加索引。
③表与表连接用于多表联合查询的约束条件的字段应当建立索引。
原文链接:https://blog.csdn.net/m0_37925202/article/details/82939530
int count=0;
for(int i=1;i<5;i++){
for(int j=1;j<5;j++){
for(int k=1;k<5;k++){
if(i!=j&&i!=k&&j!=k){
System.out.println(i+j+k);
count++;
}
}
}
}
Hash索引的底层实现是由Hash表来实现的,非常适合以 key-value 的形式查询,也就是单个key 查询,或者说是等值查询。其结构如下所示:
从上面结构可以看出,Hash 索引可以比较方便的提供等值查询的场景,由于是一次定位数据,不像BTree索引需 要从根节点到枝节点,最后才能访问到页节点这样多次IO访问,所以检索效率远高于BTree索引。但是对于范围查询的话,就需要进行全表扫描了。
但为什么我们使用BTree比使用Hash多呢?主要Hash本身由于其特殊性,也带来了很多限制和弊端:
B树和B+树 B树和B+树算是数据结构中出现频率十分高的模型了,在笔者之前的几篇博客,有对二叉查找树和二叉平衡树进行过讲解和代码分析,但是那些都是在程序中使用比较多的树,在数据库中,数据量相对较大,多路查找树显然更加适合数据库的应用场景,接下来我们就介绍这两类多路查找树,毕竟作为程序员,心里没点B树怎么能行呢?
B树:B树就是B-树,他有着如下的特性:
1、B树不同于二叉树,他们的一个节点可以存储多个关键字和多个子树指针,这也是B+树的特点;
2、一个m阶的B树要求除了根节点以外,所有的非叶子子节点必须要有[m/2,m]个子树;
3、根节点必须只能有两个子树,当然,如果只有根节点一个节点的情况存在;
4、B树是一个查找二叉树,这点和二叉查找树很像,他都是越靠前的子树越小,并且,同一个节点内,关键字按照大小排序;
5、B树的一个节点要求子树的个数等于关键字的个数+1;
由于B树将所有的查找关键字都放在节点中,所以查找方式和二叉查找十分相像,比如说查找E:
先通过根节点找到了左子树,再顺序地遍历左子树,发现E在F和J的中间,于是查找叶子节点,顺序遍历关键字以后就可以返回E了,如果未能查到E,则表示没有找到。
B+树
1、B+树将所有的查找结果放在叶子节点中,这也就意味着查找B+树,就必须到叶子节点才能返回结果;
2、B+树每一个节点的关键字个数和子树指针个数相同;
3、B+树的非叶子节点的每一个关键字对应一个指针,而关键字则是子树的最大,或者最小值;
MyBatis优点:
1.易于上手和掌握
sql写在xml里,便于统一管理和优化。
提供xml标签,支持编写动态sql。
提供映射标签,支持对象与数据库的orm字段关系映射
提供对象关系映射标签,支持对象关系组建维护
6. 解除sql与程序代码的耦合。
Mybatis管理事务是分为两种方式:
(1)使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交
(2)使用MANAGED的事务管理机制,这种机制mybatis自身不会去实现事务管理,而是让程序的容器(JBOSS,WebLogic)来实现对事务的管理
Redis 是 C 语言开发的一个开源的(遵从 BSD 协议)高性能键值对(key-value)的内存数据库,可以用作数据库、缓存、消息中间件等。 它是一种 NoSQL(not-only sql,泛指非关系型数据库)的数据库。
优点:
了解下 Redis 内部内存管理是如何描述这 5 种数据类型的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kpfrvIIN-1585126522542)(https://pics6.baidu.com/feed/023b5bb5c9ea15ce598be46bdbb071f53b87b2a5.jpeg?token=3f5ccd21917fb33a2472bbb06b480a56&s=5AA834629B8961495EFDB0C70000E0B1)]
①String 是 Redis 最基本的类型,可以理解成与 Memcached一模一样的类型,一个 Key 对应一个 Value。Value 不仅是 String,也可以是数字。
String 类型是二进制安全的,意思是 Redis 的 String 类型可以包含任何数据,比如 jpg 图片或者序列化的对象。String 类型的值最大能存储 512M。
②Hash是一个键值(key-value)的集合。Redis 的 Hash 是一个 String 的 Key 和 Value 的映射表,Hash 特别适合存储对象。常用命令:hget,hset,hgetall 等。
③List 列表是简单的字符串列表,按照插入顺序排序。可以添加一个元素到列表的头部(左边)或者尾部(右边) 常用命令:lpush、rpush、lpop、rpop、lrange(获取列表片段)等。
④Set 是 String 类型的无序集合。集合是通过 hashtable 实现的。Set 中的元素是没有顺序的,而且是没有重复的。常用命令:sdd、spop、smembers、sunion 等。
⑤Zset 和 Set 一样是 String 类型元素的集合,且不允许重复的元素。常用命令:zadd、zrange、zrem、zcard 等。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jW7ryrPT-1585126522547)(https://pics1.baidu.com/feed/7a899e510fb30f24c7a97030a6259a45ad4b030c.png?token=45944d39516c10989237aecc64801ed9&s=19A07D32159BD5CE12D591CA0000F0B3)]
Redis****可以实现缓存机制, Redis是一个key-value存储系统。
Redis支持丰富的数据类型,最为常用的数据类型主要由五种:String、Hash、List、Set和Sorted Set。
Redis通常将数据存储于内存中,或被配置为使用虚拟内存。
Redis有一个很重要的特点就是它可以实现持久化数据,通过两种方式可以实现数据持久化:使用RDB快照的方式,将内存中的数据不断写入磁盘;或使用类似MySQL的AOF日志方式,记录每次更新的日志。前者性能较高,但是可能会引起一定程度的数据丢失;后者相反。
Redis支持将数据同步到多台从数据库上,这种特性对提高读取性能非常有益。
2.5.1 Java
new Integer(123) 与 Integer.valueOf(123) 的区别在于:
String 被声明为 final,因此它不可被继承。(Integer 等包装类也不能被继承)
1. 可以缓存 hash 值
因为 String 的 hash 值经常被使用,例如 String 用做 HashMap 的 key。不可变的特性可以使得 hash 值也不可变,因此只需要进行一次计算。
2. String Pool 的需要
如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。
3. 安全性
String 经常作为参数,String 不可变性可以保证参数不可变。
4. 线程安全
String 不可变性天生具备线程安全,可以在多个线程中安全地使用。
1、可变性
2、线程安全
1、Array类型的变量在声明的同时必须进行实例化(至少得初始化数组的大小),而ArrayList可以只是先声明;
2、Array对象的初始化必须指定大小,且创建后的数组大小是固定的;而ArrayList的大小可以动态指定,空间大小可以任意增加;
3、Array始终是连续存放的;而ArrayList的存放不一定连续;
4、Array不能随意添加、删除;而ArrayList可以在任意位置插入和删除
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2.对于查询和修改操做get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据 。
线程安全: HashMap 是非线程安全的,而 Hashtable 是线程安全的,因为 Hashtable 内部的方法,基本都经过 synchronized 修饰(如果要确保线程安全,建议使用 ConcurrentHashMap);
执行效率: 因为线程安全的原因,HashMap 要比 Hashtable 效率高;此外,由于 Hashtable 基本被淘汰,最好不要在项目中使用它;
对 Null key 和 Null value 的支持: HashMap 中,null 可以作为键,这样的键最多可以有一个,但可以有一个或多个键所对应的值为 null;在 Hashtable 中,键和值都不能为 null,否则会直接抛出 NullPointerException;
初始容量大小和扩容的机制不同 :
① 创建时,如果未指定容量初始值,Hashtable 默认的初始大小为11,之后每次扩充,容量变为原来的 2n+1;HashMap 默认的初始大小为16,之后每次扩充,容量变为原来的2倍;
② 创建时,如果给定了容量初始值,Hashtable 将直接使用给定大小作为初始容量;而 HashMap 会将其扩充为2的幂次方大小,也就是说, HashMap 总是使用2的幂作为哈希表的大小;
底层数据结构: JDK1.8 以后,HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,会自动将链表转化为红黑树,以减少搜索时间,而 Hashtable 没有这样的机制。
自动转换按从低到高的顺序转换。不同类型数据间的优先关系如下:
低--------------------------------------------->高
byte,short,char-> int -> long -> float -> double
多态:允许不同类的对象对同一消息做出相应反应。同一消息可以根据发送对象的不同而采用不同的行为方式。举例按F1键获取不同的帮助。
Java实现多态有三个必要条件:
1)继承
2)重写
3)向上转型:多态中需要将子类的引用赋给父类对象,只有这样该引用才能够调用父类的方法和子类的方法(父类引用指向子类对象。)
方法的重载和重写都是实现多态的方式 。
区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。
重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的参数列表,有兼容的返回类型。
重载发生在一个类中,同名的方法有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)。
1、接口类似于类,但接口的成员都没有执行方法
2、不能实例化一个接口,而类可以实例化(abstract类除外)
3、接口没有构造函数,类有构造函数
4、接口的成员没有任何修饰符,其成员总是公共的,而类的成员则可以有修饰符(如:虚拟或者静态)
参数 | 抽象类 | 接口 |
---|---|---|
默认的方法实现 | 它可以有默认的方法实现 | 接口完全是抽象的,不存在方法的实现 |
实现 | 子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。 | 子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现 |
构造器 | 抽象类可以有构造器 | 接口不能有构造器 |
与正常Java类的区别 | 除了你不能实例化抽象类之外,它和普通Java类没有任何区别 | 接口是完全不同的类型 |
访问修饰符 | 抽象方法可以有public、protected和default这些修饰符 | 接口方法默认修饰符是public static final,不可以使用其它修饰符。 |
多继承 | 抽象方法可以继承一个类和实现多个接口 | 接口只可以继承一个或多个其它接口 |
速度 | 它比接口速度要快 | 接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。 |
添加新方法 | 如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。 | 如果你往接口中添加方法,那么你必须改变实现该接口的类。 |
变量 | 构造方法 | 方法 | |
---|---|---|---|
抽象类 | 无限制 | 子类通过构造方法链调用构造方法,抽象类不能用new操作符实例化 | 无限制 |
接口 | 所有变量必须是public static final | 没有构造方法,接口不能用new操作符实例化 | 所有方法必须是公共类的抽象实例 |
实例方法可以直接访问实例变量,调用实例方法;
实例方法可以直接访问类变量,调用类方法。但不推荐这么做,原因是不清晰,容易把类变量误认为是实例变量,把类方法误认为是实例方法(借助IDE,它会给出警告信息);
类方法可以直接调用类变量和类方法;
类方法不能直接调用实例变量和实例方法;
类方法里面不能使用“this”关键字,因为没有实例存在,“this”不知道引用哪个实例。
原文链接:https://blog.csdn.net/qq_33704186/article/details/90311296
1、integer是int的包装类,int是Java的一种基本数据类型
2、integer变量必须实例化后才能使用,int变量不需要
3、integer实际是对对象的引用,int是直接存储数据值
4、integer的默认值是null,int的默认值是0
Equals通常用来比较两个对象的内容是否相等,==用来比较两个对象的地址是否相等
Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。Java可以用四种方式来创建线程,如下所示:
1)继承Thread类创建线程
定义Thread类的子类,并重写Thread类的run()方法,创建子类对象(即线程对象),调用线程对象的start()方法来启动该线程。
2)实现Runnable接口创建线程
3)使用Callable和Future创建线程
4)使用线程池例如用Executor框架
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IYsMSNCq-1585126522549)(C:\Users\zhangboyi\AppData\Roaming\Typora\typora-user-images\1584198984106.png)]
1、新生状态
在程序中用构造方法(new操作符)创建一个新线程时,如new Thread®,该线程就是创建状态,此时它已经有了相应的内存空间和其它资源,但是还没有开始执行。
2、就绪状态
新建线程对象后,调用该线程的**start()**方法就可以启动线程。当线程启动时,线程进入就绪状态(runnable)。由于还没有分配CPU,线程将进入线程队列排队,等待 CPU 服务,这表明它已经具备了运行条件。当系统挑选一个等待执行的Thread对象后,它就会从等待执行状态进入执行状态。系统挑选的动作称之为“CPU调度"。一旦获得CPU线程就进入运行状态并自动调用自己的run方法。
3、运行状态
当就绪状态的线程被调用并获得处理器资源时,线程就进入了运行状态。此时,自动调用该线程对象的run()方法。run()方法定义了该线程的操作和功能。运行状态中的线程执行自己的run方法中代码。直到调用其他方法或者发生阻塞而终止。
4、阻塞状态
一个正在执行的线程在某些特殊情况下,如被人为挂起或需要执行耗时的输入输出操作时,suspend()、 wait()等方法,线程都将进入堵塞状态。堵塞时,线程不能进入排队队列,只有当引起堵塞的原因被消除后,线程转入就绪状态。重将让出 CPU 并暂时中止自己的执行,进入堵塞状态。在可执行状态下,如果调用 sleep()、 新到就绪队列中排队等待,这时被CPU调度选中后会从原来停止的位置开始继续执行。
5、死亡状态
线程调用stop()方法、destory()方法或 run()方法执行结束后,线程即处于死亡状态。处于死亡状态的线程不具有继续运行的能力。
Java虚拟机(JVM)是运行Java字节码的虚拟机,它是java编程语言的核心。
JVM被称为虚拟,因为它提供的接口不依赖于底层操作系统和机器硬件。这种与硬件和操作系统的独立性使得java程序可以在任何地方进行一次写入。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-46CDxShJ-1585126522552)(C:\Users\zhangboyi\AppData\Roaming\Typora\typora-user-images\1584201825931.png)]
https://blog.csdn.net/sun337939896/article/details/79092356
程序计数器和虚拟机栈都是线程私有的内存。
1.程序计数器:
可以看做是当前线程所执行的字节码的行号指示器。每条线程都有一个独立的程序计数器,所以程序计数器是线程私有的内存区域。
主要存放代码执行的位置。分支、循环、跳转、异常处理、线程恢复等基础功能都需要计数器来完成。
2.Java虚拟机栈:
3.本地方法栈
本地方法栈与虚拟机栈的区别:虚拟机栈为虚拟机执行Java方法服务(也就是字节码),而本地方法栈为虚拟机使用到的Native方法服务。
堆和方法区是各个线程共享的内存区域
4.Java堆:
5.方法区:
类的加载过程是指将java编译之后的class文件读入到内存中,然后在堆区创建一个java.lang.Class对象,用于封装类在方法区内的数据结构。类加载的最终目的是封装类在方法区的数据结构,并向java程序员提供访问方法区数据的接口。
https://www.jianshu.com/p/23f8249886c6
垃圾回收(Garbage Collection)是Java虚拟机(JVM)垃圾回收器提供的一种用于在空闲时间不定时回收无任何对象引用的对象占据的内存空间的一种机制。
垃圾判断算法
引用计数法
给每个对象添加一个计数器,当有地方引用该对象时计数器加1,当引用失效时计数器减1。用对象计数器是否为0来判断对象是否可被回收。缺点:无法解决循环引用的问题。
可达性分析算法
通过一系列的
GC Roots
的对象作为起始点,从这些节点出发所走过的路径称为引用链
。当一个对象到 GC Roots 没有任何引用链相连的时候说明对象不可用。
可作为 GC Roots 的对象:
垃圾回收算法
在确定了哪些垃圾可以被回收后,垃圾收集器要做的事情就是开始进行垃圾回收,但是这里面涉及到一个问题是:如何高效地进行垃圾回收。这里我们讨论几种常见的垃圾收集算法的核心思想。
标记-清除算法
- 效率不高
- 空间会产生大量碎片
复制算法
会造成空间利用率低下。
标记-整理算法
解决内存碎片化问题,把存活的对象移到内存一端。
分代收集算法
根据存活对象划分几块内存区,一般是分为新生代和老年代。然后根据各个年代的特点制定相应的回收算法。
新生代
每次垃圾回收都有大量对象死去,只有少量存活,选用复制算法比较合理。
老年代
老年代中对象存活率较高、没有额外的空间分配对它进行担保。所以必须使用
标记 —— 清除
或者标记 —— 整理
算法回收。
内存泄漏:当一个对象已经不需要再使用本该被回收时,另外一个正在使用的对象持有它的引用从而导致它不能被回收,这导致本该被回收的对象不能被回收而停留在堆内存中,这就产生了内存泄漏。
**内存溢出:**为每个应用程序分配的内存是有限的,而当一个应用中产生的内存泄漏比较多时,这就难免会导致应用所需要的内存超过系统分配的内存限额,这就造成了内存溢出。
1、内存泄漏memory leak :是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出。
2、内存溢出 out of memory :指程序申请内存时,没有足够的内存供申请者使用,或者说,给了你一块存储int类型数据的存储空间,但是你却存储long类型的数据,那么结果就是内存不够用,此时就会报错OOM,即所谓的内存溢出。
内存溢出常见原因:
1.内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
2.集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
3.代码中存在死循环或循环产生过多重复的对象实体;
4.使用的第三方软件中的BUG;
5.启动参数内存值设定的过小
解决方案:
1、修改JVM参数,直接增加内存
2、检查错误日志,查看内存溢出错误前是否有其他异常错误
3、对代码进行走查分析,找出可能发生内存溢出的位置
Java**类加载器(**Java Classloader)是Java运行时环境(Java Runtime Environment)的一部分,负责动态加载Java类到Java虚拟机的内存空间中。
类加载器的分类:
启动类加载器、扩展类加载器、应用类加载器(系统类加载器)、用户自定义类加载器。
启动类加载器:这个类负责将存放在JAVA_HOME/lib目录或者被-Xbootclasspath参数所指定的路径中的并且是虚拟机内存中。
扩展类加载器:负责加载JAVA_HOME/lib/ext目录中或者被java.ext.dirs系统变量指定路径中的所有类库,开发者可以直接使用扩展类加载器。
应用程序类加载器:负责加载用户类路径上指定的类加载器,一般情况下就是程序中默认的类加载器。
1、队列先进先出,栈先进后出。
2、对插入和删除操作的"限定"不同。
栈是限定只能在表的一端进行插入和删除操作的线性表。
队列是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。
3、遍历数据速度不同。
1.都是线性结构。
2.插入操作都是限定在表尾进行。
3.都可以通过顺序结构和链式结构实现。、
4.插入与删除的时间复杂度都是O(1),在空间复杂度上两者也一样。
5.多链栈和多链队列的管理模式可以相同。
栈内存里面存放基本类型的变量和对象的引用变量
堆内存里面存放new创建的对象和数组
1、栈(操作系统):由操作系统自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈;
2、堆(操作系统):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。
堆(数据结构):堆可以被看成是一棵树,如:堆排序;
栈(数据结构):一种先进后出的数据结构。
栈:由系统自动分配,速度较快。但程序员是无法控制的。
堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。
其最突出的优点是查找和插入删除具有常数时间的复杂度
其实现原理是:把Key通过一个固定的算法函数即所谓的哈希函数转换成一个整型数字,然后就将该数字对数组长度进行取余,取余结果就当作数组的。
数组:
1、在内存中,数组是一块连续的区域。
2、数组需要预留空间,空间利用率较低
3、插入和删除数据都要大量移动元素的位置,效率比较低下,但查询效率比较高
4、数组的空间是从栈分配的。
链表
1、在内存中,空间是分散的,不是连续性的
2、链表的查询效率低,但插入或删除的效率高
3、空间不需要提前指定大小,是动态申请的,空间利用率较高。
4、链表的空间从堆中分配
1、 有25匹马,5个跑道。没有秒表。为了选出跑得最快的三匹马,请问最少进行多少轮比赛?
7场。思路如下:
25匹马分5组,分别选出每组的第一,+5场
各组第一再比一场,+1场,(确定第一名,以及记录本场赛跑前三名所在的小组)
排除掉已确定的第一名和不可能排名前三名的马,剩余5匹,再比一场,取得前两名,+1场。(即第6场比赛排名第一的小组的第二、三名,排名第二所在的小组,取第一第二名,排名第三所在的小组,取第一名,总共5匹)
2、有一个5L和一个3l 的无刻度水杯,还有一个水池。如何量出4L水
4、有1001个珍爱币,每次只能取1,2,4个。现有A,B两个人。A先手,谁拿到最后一个珍爱币,谁输。请问A是否可以必胜?
A第一次先取1个,剩下1000个
之后从B第一次取开始计数,保证每轮B+A所取的珍爱币的数目为奇数
//复杂度为O(n)
public static boolean findColumn2(int[] a,int size_a,int[] b,int size_b){
int i,j=0;
while(i<size_a&&j<size_b){
if(a[i]==b[j])
return true;
if(a[i]>b[j])
j++;
if(a[i]<b[j])
i++;
}
return false;
}
//复杂度为O(nlogn),使用了二分法
public static boolean findConlumn(int[] a,int size_a,int[] b,int size_b){
for(int i=0;i<size_a;i++){
int low=0,high = size_b-1,mid;
while(low<high){
mid = low+(high-low)/2;
if(a[i]==b[mid])
return true;
if(a[i]>b[mid])
low = mid +1;
if(a[i]<b[mid])
high = mid -1;
}
}
}
//中心拓展法
public static ArrayList<String> findAllHuiWen2(String s){
ArrayList<String> list = new ArrayList<String>();
if(s==null || s.length()==0) return list;
if(s.length()==1) {
list.add(s);
return list;
}
for(int i=0; i<s.length(); i++){
getSubList(s,i,i,list);
getSubList(s,i,i+1,list);
}
return list;
}
public static void getSubList(String s, int left, int right, ArrayList<String> list){
while (left>=0 && right<s.length() && s.charAt(left)==s.charAt(right)){
String subString = s.substring(left, right+1);
if(!list.contains(subString))
list.add(subString);
left--;
right++;
}
}
//中心拓展法
public static String longestPalindrom(String s){
if(s == null||s.length() == 0) return "";
int start =0,end=0;
for(int i = 0;i<s.length();i++){
int len1 = expandAroundCenter(s,i,i);
int len2 = expandAroundCenter(s,i,i+1);
int len = Math.max(len1, len2);
if(len>end-start){
start = i-(len-1)/2;
end = i+len/2;
}
}
return s.substring(start,end+1);
}
public static int expandAroundCenter(String s,int left,int right){
int L = left,R=right;
while (L>0&&R<s.length()&&s.charAt(L) == s.charAt(R)){
L--;
R++;
}
//返回回文串长度
System.out.println(R-L-1);
return R-L-1;
}
//二分法
public class firstBadVersion {
public static void main(String[] args){
//查找有序数组是否存在val,并输出第一次出现的位置
int[] arr ={1,2,3,3,3,4,4,6,7,8};
int val = 3;
System.out.println(firstPresent(arr,val));
}
public static int firstPresent(int[] arr,int val){
int low=0;
int high = arr.length -1;
while (low<high){
int mid = low+(high - low)/2;//写法说明:反之整数溢出
if(arr[mid]>=val){
high = mid-1;
}
else{
low = mid +1;
}
}
return low;
}
}
class Solution{
public ListNode mergeTwoLists(ListNode l1,ListNode l2){
if(l1 == null)
return l2;
else if(l2 == null){
return l1;
}
else if(l1.val < l2.val){
l1.next = mergeTwoLists(l1.next,l2);
return l1;
}else{
l2.next = mergeTwoLists(l1,l2.next);
return l2;
}
}
}
本质是一个web代理服务器,默认工作端口为8888。
工作原理
代理模式
流模式
流模式可以理解为是一种实时通信的模式,有请求就有返回,也就是实时返回!
缓存模式
等所有请求都到了再 一起返回,也就是等所有数据都准备好之后才返回给客户端!
5种常见的测试用例设计方法
https://blog.csdn.net/hongfuqiang/article/details/78840763
单元测试、集成测试、系统测试、验收测试、回归测试
1、单元测试:完成最小的软件设计单元(模块)的验证工作,目标是确保模块被正确的编码,使用过程设计描述作为指南,对重要的控制路径进行测试以发现模块内的错误,通常情况下是白盒的,对代码风格和规则、程序设计和结构、业务逻辑等进行静态测试,及早的发现和解决不易显现的错误。
2、集成测试:通过测试发现与模块接口有关的问题。目标是把通过了单元测试的模块拿来,构造一个在设计中所描述的程序结构,应当避免一次性的集成(除非软件规模很小),而采用增量集成。
自顶向下集成:模块集成的顺序是首先集成主模块,然后按照控制层次结构向下进行集成,隶属于主模块的模块按照深度优先或广度优先的方式集成到整个结构中去。
自底向上集成:从原子模块开始来进行构造和测试,因为模块是自底向上集成的,进行时要求所有隶属于某个给顶层次的模块总是存在的,也不再有使用稳定测试桩的必要。
3、系统测试:是基于系统整体需求说明书的黑盒类测试,应覆盖系统所有联合的部件。系统测试是针对整个产品系统进行的测试,目的是验证系统是否满足了需求规格的定义,找出与需求规格不相符合或与之矛盾的地方。系统测试的对象不仅仅包括需要测试的产品系统的软件,还要包含软件所依赖的硬件、外设甚至包括某些数据、某些支持软件及其接口等。因此,必须将系统中的软件与各种依赖的资源结合起来,在系统实际运行环境下来进行测试。
4、回归测试:回归测试是指在发生修改之后重新测试先前的测试用例以保证修改的正确性。理论上,软件产生新版本,都需要进行回归测试,验证以前发现和修复的错误是否在新软件版本上再次出现。根据修复好了的缺陷再重新进行测试。回归测试的目的在于验证以前出现过但已经修复好的缺陷不再重新出现。一般指对某已知修正的缺陷再次围绕它原来出现时的步骤重新测试。
5、验收测试:验收测试是指系统开发生命周期方法论的一个阶段,这时相关的用户或独立测试人员根据测试计划和结果对系统进行测试和接收。它让系统用户决定是否接收系统。它是一项确定产品是否能够满足合同或用户所规定需求的测试。验收测试包括Alpha测试和Beta测试。
Alpha测试:是由用户在开发者的场所来进行的,在一个受控的环境中进行。
Beta测试:由软件的最终用户在一个或多个用户场所来进行的,开发者通常不在现场,用户记录测试中遇到的问题并报告给开发者,开发者对系统进行最后的修改,并开始准备发布最终的软件。
首先,需要已经完成了功能测试,此时测试版本稳定,属性、功能稳定。
根据项目的特点、选择合适的自动化测试工具,并搭建测试环境
提取手工测试的测试用例 转化为自动化测试用例
通过工具、代码实现自动化的构造输入、自动检测输出结果是否满足预期
生成自动测试报告
持续改进、脚本优化
性能测试常用指标:
从外部看,主要有
1、吞吐量:每秒钟系统能够处理的请求数,任务数
2、响应时间:服务处理一个请求或一个任务的耗时
3、错误率:一批请求中结果出错的请求所占比例
从服务器的角度看,性能测试关注CPU,内存,服务器负载,网络,磁盘IO
负载均衡,英文名称为Load Balance,其含义就是指将负载(工作任务)进行平衡、分摊到多个操作单元上进行运行,例如FTP服务器、Web服务器、企业核心应用服务器和其它主要任务服务器等,从而协同完成工作任务。
负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。
分类
部署方式
https://blog.csdn.net/qq_42270373/article/details/95230866
测试用例的设计需要参考需求文档。
删除前确认
文件删除成功/失败,应该有相应的提示信息
不选择文件,点击删除按钮,出现相应的提示信息
删除过程中,点击取消按钮,验证取消是否成功
成功删除之后,是否可以撤销删除
删除文件,一定要对删除权限和身份验证
文件删除之后,是放入回收站还是彻底删除
若存在批量删除,测试文件是否能够被成功删除
测试批量删除的性能
模拟大量用户进行批量删除,检查系统的稳定性
对不允许存在的文件进行删除,提示相应的信息
文件删除的过程中,网络中断,看是否能够成功删除
是否有删除日志
文件打开/文件正在复制,给出相应的提示信息
微信发红包
https://blog.csdn.net/qq_40891477/article/details/94395634
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5JZfwV3R-1585126522560)(C:\Users\zhangboyi\AppData\Roaming\Typora\typora-user-images\1585067861661.png)]
微信支付