测试面试准备知识点

1. 面经

Shopee

作者:呜呜祖卡

https://www.nowcoder.com/discuss/369302?type=2&order=0&pos=1&page=1来源:牛客网

为什么想做测试

以前实习是怎么测试的 没有实习过 所以没谈了

如果打不开百度网页,怎么排查错误

  • 先确定网络是否连接

测试删除文件功能

http状态码都说一下 单独问了404

https了解吗http+ssl

数据库内连接外连接左连接右连接 用得不多 所以没继续问了

想怎么建立索引?学生学号姓名年级成绩老师入学时间 可以根据什么来建立索引

linux常用命令 管道有常用吗

作者:九月努力签高薪好offer

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来源:牛客网

  1. 判断两个数组中是否存在相同的数字,两个已经排好序的数组,写代码判断这两个数组中是否存在相同的数字?要求时间复杂度越低越好。

  2. 讲输入 url 到页面呈现的过程(下面几个很细节的问)

  3. 拿到 http 响应后,怎么渲染页面,html 的组成,js、css 这些静态文件是存在哪里?(不清楚前端,瞎讲,我说到 http 缓存,面试官一脸疑惑,我也搞不懂)

  4. 服务端有很多服务,关于 http、ftp 等等,怎么知道你发的是 http 请求,我要响应的是 http 请求(端口)

  5. 客户端向服务器发一个 1kb 数据,怎么保证是无损传输(答 tcp 保证可靠传输,超时重传和 seq/ack 机制

  6. 一个 tcp 链接最多能同时发多少个 http 请求(可能是这个问题,记不清,又引申到高并发)

  7. 有没有了解高并发,我说不了解,问不了解的话,那但你从学过的计算机基础知识,来看怎么实现这个过程(凉凉,完全不了解,一顿瞎扯)

  8. 老板给一个需求,不具体,输入一个生日,实现生日前一天给人发邮件祝福,从产品、开发、测试角度来怎么设计、怎么实现、怎么测试(说产品的时候,告诉我要多问,去细化需求)

  9. 如果要实现生日可以修改,一直往后面推,怎么做(我说直接覆盖数据库的数据,他最后说需要设置一个用户登录之类的)

  10. 这个数据库要有哪些字段

  11. 实现方面,还问你怎么能每天去执行,谁去扫库吗,我说可以用 linux crontab 去设置定时任务,每天去扫库(瞎扯,不懂后台)

  12. 测试方面,说还要考虑一年的最后一天的跳转,闰年之类的

  13. 问对深圳,对未来有什么规划

  14. 问想做前端方面还是后台服务器方面

另外附上一面面经

\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连接?

服务器返回响应结果后,客户端要做什么?

作者:☞Nothing☜

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三次握手。

测试一个登录界面。

进程和线程的区别。

线程同步。

黑盒白盒的方法。

作者:古月dawn

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个人,互相交换礼物,每个人不能拿到自己的礼物。设计一种算法

2. 准备

2.1 计算机网络

2.1.1 http

超文本传输协议

2.1.2 http和https的区别

  • https协议需要到CA(Certificate Authority,证书颁发机构)申请证书,一般免费证书较少,因而需要一定费用。
  • http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
  • http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
  • http的连接很简单,是无状态的。Https协议是由SSL+Http协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。(无状态的意思是其数据包的发送、传输和接收都是相互独立的。无连接的意思是指通信双方都不长久的维持对方的任何信息。)

https请求过程

WX20191127-133805@2x.png

2.1.3 session与cookies实现机制

https://harttle.land/2015/08/10/cookie-session.html

session与cookie的区别

  • session存储在服务器,cookid存储在客户端
  • session比cookie安全,所以一般用来存储一些敏感信息
  • 性能方面:
  • 数据存储大小不同:单个cookie保存的数据不超过4k,session没有限制

2.1.4 http缓存

  • 强缓存
  • 协商缓存
  • 浏览器启用缓存的优点:减少页面加载时间,减少服务器负载
  • 浏览器是否使用缓存,缓存多久,是由服务器控制的
    • 即服务器响应的 响应头 中,某些字段指明了缓存的关键信息

强缓存和协商缓存的区别

  • 协商缓存跟强缓存不一样,强缓存不发请求到服务器,所以有时候资源更新了浏览器还不知道,但是协商缓存会发请求到服务器,所以资源是否更新,服务器肯定知道。
  • 大部分web服务器都默认开启协商缓存,而且是同时启用Last-Modified,If-Modified-Since和ETag、If-None-Match
  • Last-Modified,If-Modified-Since和ETag、If-None-Match一般都是同时启用,这是为了处理Last-Modified不可靠的情况
  • // 分布式系统里多台机器间文件的Last-Modified必须保持一致,以免负载均衡到不同机器导致比对失败
  • // 分布式系统尽量关闭掉ETag(每台机器生成的ETag都会不一样)

作者:woow_wu7链接:https://juejin.im/post/5e2aaa406fb9a02fb75d68df来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2.1.5 http状态码

分类描述
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来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2.1.6 http请求以及响应

https://juejin.im/post/5e5152be6fb9a07ce31ee4bd#heading-25

1. DNS域名解析 // 将域名解析成IP地址
2. 建立TCP链接 // 三次握手
3. 客户端发起HTTP请求
4. 服务器处理请求,并返回HTTP报文
5. 浏览器解析渲染页面
6. 断开TCP链接 // 四次挥手

url到页面显示的过程

  1. DNS域名解析
  • DNS是 ( domain name system ) 域名系统的缩写
  • 将域名解析成ip地址
  • 一个域名对应一个以上的ip地址
  • 为什么要将域名解析成ip地址?
    • 因 ( 为TCP/IP网络 ) 是通过 ( ip地址 ) 来确定 ( 通信对象 ),不知道ip就无法将消息发送给对方
  • DNS域名解析的过程:// 递归查询和迭代查询
  1. ( 浏览器 ) 中查询 DNS 缓存,有则进入建立tcp链接阶段,下面同理

  2. ( 本机的系统 )中查询 DNS 缓存

  3. ( 路由器 ) 中查询 DNS 缓存

  4. ( 运营商服务器 ) 中查询 DNS 缓存

  5. 递归查询 // 根域名/一级域名/二级域名 …blog.baidu.com

    • .com
    • .baidu
    • blog
    • 还未找到就报错
  6. 建立tcp链接 // 三次握手

  • 第一次握手

    • 客服端发送一个 标志位SYN=1,序号Seq=x的链接包给服务端
      • SYN:表示发起一个新链接,( Synchronize Sequence Numbers )
      • Seq:序号是随机的
  • 第二次握手

    • 服务端发送一个 标志位SYN=1,ACK=1,确认号Ack=x+1,序号Seq=y的确认包给客户端
    • 标志位 ACK 表示响应
  • 第三次握手

    • 客户端发送一个 SYN=0,ACK=1,确认号Ack=y+1,序号Seq=x+1的确认包给服务器

    • 为什么需要三次握手

      • 之所以要第三次握手,主要是因为避免无效的连接包延时后又发送到服务器,造成服务器以为又要建立链接的假象,造成错误
  1. 客户端发送http请求

  2. 服务端处理请求,并返回http响应报文

  3. 浏览器解析渲染

  • 遇见HTML标记,浏览器调用HTML解析器,解析成Token并构建DOM树
  • 遇见style/link标记,浏览器调用css解析器,解析成CSSOM树
  • 遇见script标记,浏览器调用js解析器,处理js代码(绑定事件,可能会修改DOM tree 和 CSSOM tree)
  • 将DOM 和 CSSOM 合并成 render tree
  • 根据render tree计算布局(布局)
  • 将各个节点的颜色绘制到屏幕上(渲染)
  1. 断开TCP链接 // 四次挥手,( FIN : 表示释放链接 )
  • 第一次挥手:浏览器发起,告诉服务器我请求报文发送完了,你准备关闭吧
  • 第二次挥手:服务器发起,告诉浏览器我请求报文接收完了,我准备关闭了,你也准备吧
  • 第三次挥手:服务器发起,告诉浏览器,我响应报文发送完了,你准备关闭吧
  • 第四次挥手:浏览器发起,告诉服务器,我响应报文接收完了,我准备关闭了,你也准备吧
  • 先是服务器先关闭,再是浏览器关闭

2.1.7 GET 和 POST 的区别

  • GET在浏览器回退时是无害的,而POST会再次提交请求。
  • GET产生的URL地址可以被Bookmark,而POST不可以。
  • GET请求会被浏览器主动cache,而POST不会,除非手动设置。
  • GET请求只能进行url编码,而POST支持多种编码方式。
  • GET请求参数会被完整保留在浏览器的历史记录里,而POST中的参数不会被保留。
  • GET请求在URL中传送的参数是有长度限制的,而POST无限制。
  • 参数的数据类型,GET只接受ASCII字符,而POST没有限制。
  • GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
  • GET参数通过URL传递,POST放在Request body中。

IP 是无连接的

IP 用于计算机之间的通信。

IP 是无连接的通信协议。它不会占用两个正在通信的计算机之间的通信线路。这样,IP 就降低了对网络线路的需求。每条线可以同时满足许多不同的计算机之间的通信需要。

通过 IP,消息(或者其他数据)被分割为小的独立的包,并通过因特网在计算机之间传送。

IP 负责将每个包路由至它的目的地。

TCP/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]。

2.1.8 TCP和UDP的区别、特点

  • TCP的主要特点是:

    • 面向连接。
    • 每一条TCP连接只能是点对点的(一对一)。
    • 提供可靠交付的服务(无差错,不丢失,不重复,且按序到达)(校验和、重传控制、序号标识、滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。)。
    • 提供全双工通信。
    • 面向字节流。
  • UDP的主要特点是:

    • 无连接。
    • 支持一对一、一对多、多对一和多对多的交互通信。
    • 尽最大努力交付(不保证可靠交付)。
    • 面向报文。
    • 无拥塞控制。
    • 首部开销小(只有四个字段:源端口、目的端口、长度、检验和)。

采用TCP,一旦发生丢包,TCP会将后续的包缓存起来,等前面的包重传并接收到后再继续发送,延时会越来越大。

UDP对实时性要求较为严格的情况下,采用自定义重传机制,能够把丢包产生的延迟降到最低,尽量减少网络问题对游戏性造成影响。

TCP与UDP的应用场景

TCP: 文件传输、发送接收邮件,远程登录。

UDP:( 对数据准确性和丢包要求比较低,但速度必须快 )在线视频,语音电话、游戏等

2.1.9 TCP为什么可靠?

[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同步序列编号

三次握手:

三次握手.png

四次挥手

image.png

ARP协议

  • 第一步:首先,每个主机都会有自己的ARP缓存区中建立一个ARP列表,以表示IP地址和MAC地址之间的对应关系
  • 第二步:当源主机要发送数据时,首先检测ARP列表中是否对应IP地址的目的主机的MAC地址如果有,则直接发送数据。如果没有,就向本网段的所有主机发送ARP数据包,内容:我是IP地址,mac地址,谁是IP地址,mac?
  • 第三步:当本网络的所有主机收到该ARP数据包时,首先检查数据包中的IP地址是否是自己的IP地址,如果不是,则忽略该数据包。如果是,则首先从数据包中取出源主机的IP和mac地址写入到ARP列表中,如果以存在,则覆盖。然后将自己的mac地址写入arp响应包中,告诉源主机自己是它想要找的mac地址
  • 第四步:源主机收到ARP响应包后,将目的主机的IP和mac地址写入arp列表,并利用此信息发送数据如果源主机一直没有收到arp响应数据包,表示arp查询失败。

为什么要使用ARP协议
OSI模型把网络工作分为七层,彼此不直接打交道,只通过接口(layer interface)。IP地址工作在第三层,MAC地址工作在第二层。当协议在发送数据包时,需要先封装第三层IP地址,第二层MAC地址的报头,但协议只知道目的节点的IP地址,不知道目的节点的MAC地址,又不能跨第二、三层,所以得用ARP协议服务,来帮助获取到目的节点的MAC地址。

ARP协议是第几层协议
工作在二层,是三层协议。

ARP在生成环境产生的问题及解决办法:

  • ARP病毒,ARP欺骗。
  • 高可用服务器对之间切换时要考虑ARP缓存的问题。
  • 路由器等设备无缝迁移时要考虑ARP缓存的问题,例如:更换办公室的路由器。

OSI的七层模型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HY9mCqsr-1585126522514)(C:\Users\zhangboyi\AppData\Roaming\Typora\typora-user-images\1584096807131.png)]

img

DNS解析过程

  • 浏览器搜索自己的DNS缓存,缓存中维护一张域名与IP地址的对应表;
    • 若没有,则搜索操作系统缓存中有没有对应的解析结果;
    • 若没有,则操作系统将域名发送至本地域名服务器(递归查询方式),本地域名服务器查询自己的DNS缓存,查找成功则返回结果,否则,通过以下方式迭代查找:
      • 本地域名服务器向根域名服务器发起请求,根域名服务器返回com域的顶级域名服务器的地址;
      • 本地域名服务器向com域的顶级域名服务器发起请求,返回权限域名服务器地址;
      • 本地域名服务器向权限域名服务器发起请求,得到IP地址;
      • 本地域名服务器将得到的IP地址返回给操作系统,同时自己将IP地址缓存起来;
      • 操作系统将IP地址返回给浏览器,同时自己也将IP地址缓存起来;
        至此,浏览器已经得到了域名对应的IP地址。

2.1.4浏览器中输入一个URL后,按下回车后发生了什么

  1. 浏览器查找域名的IP地址

img

  1. 浏览器与目标服务器建立TCP连接
  • http协议建立在tcp协议之上,http请求前,需先进行tcp连接,形成客户端到服务器的稳定的通道。俗称TCP的三次握手。
  • tcp连接完成后,http请求开始,请求有多种方式,常见的有get,post等。
  • http请求包含请求头,也可能包含请求体两部分,请求头中包含我们希望对请求文件的操作的信息,请求体中包含传递给后台的参数。
  • 服务器收到http请求后,后台开始工作,如负载平衡,跨域等,这里就是后端的工作了。
  • 文件处理完毕,生成响应数据包,响应也包含两部分,响应头和相应体,响应体就是我们所请求的文件。
  • 经过网络传输,文件被下载到本地客户端,客户端开始加载。

1、查询DNS,获取域名对应的ip

2、得到目标服务器的IP地址以及其端口号,调用系统库socket函数,请求一个TCP流套接字,客户端向服务器发送http请求报文:

3、服务器端经过物理层、数据链路层、网络层、传输层、应用层,解析请求报文,发送http响应报文

html页面的解析与渲染

  • 客户端浏览器加载了html文件后,由上到下解析html为DOM树(DOM Tree)。
  • 遇到css文件,css中的url发起http请求。
  • 这是第二次http请求,由于http1.1协议增加了Connection: keep-alive声明,故tcp连接不会关闭,可以复用。
  • http连接是无状态连接,客户端与服务器端需要重新发起请求–响应。在请求css的过程中,解析器继续解析html,然后到了script标签。
  • 由于script可能会改变DOM结构,故解析器停止生成DOM树,解析器被js阻塞,等待js文件发起http请求,然后加载。这是第三次http请求。js执行完成后解析器继续解析。
  • 由于css文件可能会影响js文件的执行结果,因此需等css文件加载完成后再执行。
  • 浏览器收到css文件后,开始解析css文件为CSSOM树(CSS Rule Tree)。
  • CSSOM树生成后,DOM Tree与CSS Rule Tree结合生成渲染树(Render Tree)。
  • Render Tree会被css文件阻塞,渲染树生成后,先布局,绘制渲染树中节点的属性(位置,宽度,大小等),然后渲染,页面就会呈现信息。
  • 继续边解析边渲染,遇到了另一个js文件,js文件执行后改变了DOM树,渲染树从被改变的dom开始再次渲染。
  • 继续向下渲染,碰到一个img标签,浏览器发起http请求,不会等待img加载完成,继续向下渲染,之后再重新渲染此部分。
  • DOM树遇到html结束标签,停止解析,进而渲染结束。

输入一个URL,但是没有访问到预期的网站,是什么原因?

1.PC网络故障

2.400客户端出错

3.401服务器拒绝提供服务

  1. 403请求的资源不存在

5.500服务器内部错误

6.请求或者响应在网络传输中途被劫走了

7.可能是DNS出错了。

PC网络故障

  1. 首先排除接触故障,确保你的网线是可以正常使用
  2. 排除偶然故障,禁用网卡后再启用。
  3. 使用ipconfig查看计算机的上网参数 ,输入ipconfig/all,可以看到IP地址和网卡物理地址等相关网络详细信息。
  4. 使用ping命令测试网络的连通性,定位故障范围。Ping本地地址“127.0.0.1”,若丢包率为0,则可以判断本机网络协议工作正常。否则表明本机网卡的安装或TCP/IP协议有问题,接下来检查网卡TCP/IP协议。
  5. 第四步正常的情况下,Ping本机IP地址,若不能ping通,则说明本机网卡驱动程序不正确,或者网卡与网线之间连接有故障
  6. Ping网关,若能被ping通,则本机网络连接正常。否则可能是网关设备存在问题或者上网参数设置有误,检查网络参数。

Socket

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,

img

2.2 数据结构与算法

常见的数据结构

img

图片中的数组的优缺点写错,参考下方

  1. 数组

    • 数组是可以在内存中连续存储多个元素的结构,在内存中的分配也是连续的 。

    • 其查询效率,修改的效率相对链表来说比较高。

    • 插入、删除数据的时候

  2. 链表

    • 链表是物理存储单元上非连续的、非顺序的存储结构
    • 查询、修改效率低
    • 插入、删除效率高,不用移动元素
  3. 队列

  4. 散列表

    散列表,也叫哈希表,是根据关键码和值 (key和value) 直接进行访问的数据结构,通过key和value来映射到集合中的一个位置,这样就可以很快找到集合中的对应元素。

    • 红黑树

      红黑树的特点:

      速度特别快,趋近平衡树,查找叶子元素最少和最多次数不多于二倍。

      节点可以是红色的或者黑色的
      根节点是黑色的
      叶子节点(特指空节点)是黑色的
      每个红色节点的子节点都是黑色的
      任何一个节点到其每一个叶子节点的所有路径上黑色节点数相同
      

2.2.1 排序算法

https://blog.csdn.net/racheil/article/details/90763011

冒泡排序
img
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;
            }
        }
    }
}
选择排序

基本思想:

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。

img
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;
            }
        }
     	   
    }
        
}
快速排序
  • 从数列中挑出一个元素,称为"基准"(pivot)。
  • 重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
  • 递归地(recursively)把小于基准值元素的子数列和大于基准值元素的子数列排序。
    ————————————————
    版权声明:本文为CSDN博主「Racheil」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/racheil/article/details/90763011
img
 //找基准,返回第一趟排序后的基准(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)稳定

2.2.2 查找算法

二分法查找
//版本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);
}

2.3 操作系统

2.3.1 Linux

linux命令,找出关键字出现的次数

  • 语法:grep 字符串 文件名|wc -l ,grep输出,wc -l按行统计

  • 例子:

    • 统计task-hbase-transform.log中NullPointerException出现的次数:grep NullPointerException task-hbase-transform.log|wc -l
    • 如果是多个字符串出现次数,可使用: grep 'objStr1\|objStr2' filename|wc -l#直接用 | 链接起来即可。
  • “|”: 管道符“|”将两个命令隔开,管道符左边命令的输出就会作为管道符右边命令的输入。连续使用管道意味着第一个命令的输出会作为第二个命令的输入,第二个命令的输出又会作为第三个命令的输入,依此类推。

    • grep:-v 不显示匹配上的内容;-n 显示匹配上的内容
    • grep -v down,显示不包含down的内容。
      • grep -n down,显示包含down的内容。
    • du:(disk use)显示每个文件和目录的磁盘使用空间。
  • 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
  1. netstat

查看占用端口的进程

示例:查看特定端口的进程

# netstat -anp | grep port

linux常用指令;

2.3.2 计算机操作系统

  1. 进程

    进程是资源分配的基本单位。

  2. 线程

    线程是独立调度的基本单位。

    一个进程中可以有多个线程,它们共享进程资源

    进程与线程的区别
    • 拥有资源:进程是资源分配的基本单位。但是线程不拥有资源,线程可以访问隶属进程的资源
    • 调度:线程是独立调度的基本单位,在同一进程中,线程的切换不会引起进程切换。 从一个进程中的线程切换到另一个进程中的线程时,会引起进程切换。
    • 系统开销:创建和撤销进程时,系统都要分配或者回收进程,其所付出的开销远大于创建或撤销线程的开销。
    • 通信方面:线程间可以通过读写同一进程中的数据进行通信,但是进程通信需要借助IPC
    进程通信(IPC)

    https://mp.weixin.qq.com/s/5CbYGrylSKx1JwtOiW3aOQ

    • 管道:利用管道(“|”)的输入输出

      • 匿名管道
        • 只支持半双工通信(单向交替传输);
        • 只能在父子进程或者兄弟进程中使用。
      • 命名管道FIFO
        • 只支持半双工通信(单向交替传输);
        • 常用于客户-服务器应用程序中
    • 消息队列(类似于缓存)

    • 共享内存

      分配给进程的内存不是实际物理内存,而是虚拟内存空间

    • 信号量,相当于一个计数器。

    • socket

    死锁

    死锁是指两个或两个以上的线程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

    • 必要条件
      • 互斥:每个资源要么已经分配给了一个进程,要么就是可用的。
      • 占有和等待:已经得到了某个资源的进程可以再请求新的资源。
      • 不可抢占:已经分配给一个进程的资源不能强制性地被抢占,它只能被占有它的进程显式地释放。
      • 环路等待:有两个或者两个以上的进程组成一条环路,该环路中的每个进程都在等待下一个进程所占有的资源。
    • 处理方法
      • 鸵鸟策略

      • 死锁检测与死锁恢复

        • 一个资源的死锁检测:通过检测有向图是否存在环来实现 ( 深度优先搜索 )

        • 恢复:抢占恢复、回滚恢复、杀死进程

        • 死锁检测

          • Jstack命令
          • JConsole工具
      • 死锁预防:

        • 破坏必要条件
        • 超时放弃
      • 死锁避免

        • 银行家算法

2.4 数据库

单表查询、多表查询、count、distinct、limit

数据库事务

数据库事务是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。

数据库事务拥有以下四个特性,被称之为ACID特性:

原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。

一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。

隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。

持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中

数据库的四种隔离级别

来源: https://baijiahao.baidu.com/s?id=1611918898724887602&wfr=spider&for=pc

  1. 读未提交(read uncommitted): 就是可以读到未提交的内容

    在这种隔离级别下,查询是不会加锁的,也由于查询的不加锁,所以这种隔离级别的一致性是最差的,可能会产生“脏读”、“不可重复读”、“幻读”。

    img
  2. 读已提交(read committed): 就是只能读到已经提交了的内容。

    img
  3. 可重复读(repeated read): 就是专门针对“不可重复读”这种情况而制定的隔离级别

    普通的查询同样是使用的“快照读”,但是,和“读提交”不同的是,当事务启动时,就不允许进行“修改操作(Update)”了

    img
  4. 序列化(serializable)

    这种级别下,事务“串行化顺序执行”,也就是一个一个排队执行。由于他大量加上锁,导致大量的请求超时,因此性能会比较底下,再特别需要数据一致性且并发量不需要那么大的时候才可能考虑这个隔离级别。

    img

**“读未提(Read Uncommitted)”能预防啥?**啥都预防不了。

**“读提交(Read Committed)”能预防啥?**使用“快照读(Snapshot Read)”,避免“脏读”,但是可能出现“不可重复读”和“幻读”。

**“可重复读(Repeated Red)”能预防啥?**使用“快照读(Snapshot Read)”,锁住被读取记录,避免出现“脏读”、“不可重复读”,但是可能出现“幻读”。

**“串行化(Serializable)”能预防啥?**排排坐,吃果果,有效避免“脏读”、“不可重复读”、“幻读”,不过效果谁用谁知道。

数据库锁机制

数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。

一、按操作划分,可分为DML锁(数据锁:data locks)、DDL锁 (dictionary locks,数据字典锁)

二、按锁的粒度划分,可分为表级锁行级锁页级锁(mysql)

三、按锁级别划分,可分为共享锁排他锁

四、按加锁方式划分,可分为自动锁显示锁

五、按使用方式划分,可分为乐观锁悲观锁

悲观锁( 具有强烈的独占和排他特性 )

顾名思义,很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人拿这个数据就会block(阻塞),直到它拿锁。

  1. 共享锁(S锁)

    • 也叫读锁,用于所有的只读数据操作。共享锁是非独占的,允许多个并发事务读取其锁定的资源。
    • 性质
      • 多个事务可封锁同一个共享页
      • 任何事务都不能修改该页
      • 通常是该页被读取完毕,S锁立即被释放。
  2. 排他锁(X锁)

    • 也叫写锁,表示对数据进行写操作。如果一个事务对对象加了排他锁,其他事务就不能再给他任何锁。
    • 性质
      • 仅允许一个事务封锁此页。
      • 其他事务必须等到X锁释放才能对该页就行访问
      • X锁一直到事务结束才释放。
  3. 更新锁

    • U锁,在修改操作的初始化阶段永安里锁定可能要被修改的资源,这样可以避免共享锁造成的死锁现象。
    • 性质
      • 用来预定要对此页施加X锁,它允许其他事务读,但不允许再施加U锁或X锁;
      • 当被读取的页要被更新时,则升级为X锁
      • U锁一直到事务结束时才能被释放。

    因为当使用共享锁时,修改数据的操作分为两步:

    1. 首先获得一个共享锁,读取数据,
    2. 然后将共享锁升级为排他锁,再执行修改操作。
      这样如果有两个或多个事务同时对一个事务申请了共享锁,在修改数据时,这些事务都要将共享锁升级为排他锁。这时,这些事务都不会释放共享锁,而是一直等待对方释放,这样就造成了死锁。
      如果一个数据在修改前直接申请更新锁,在数据修改时再升级为排他锁,就可以避免死锁。
      原文链接:https://blog.csdn.net/weixin_39651041/article/details/79985715
乐观锁

顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以,不会上锁。但是在更新的时候会判断一下在此期间别人有没有更新这个数据,可以使用版本号等机制。

  1. 版本号

  2. 时间戳

    使用数据库服务器的时间戳

  3. 待更新字段

  4. 所有字段

并发控制会造成两种锁

  1. 活锁

    定义:指的是T1封锁了数据R,T2同时也请求封锁数据R,T3也请求封锁数据R,当T1释放了锁之后,T3会锁住R,T4也请求封锁R,则T2就会一直等待下去。
    解决方法:采用“先来先服务”策略可以避免。

  2. 死锁

    定义:就是我等你,你又等我,双方就会一直等待下去。比如:T1封锁了数据R1,正请求对R2封锁,而T2封住了R2,正请求封锁R1,这样就会导致死锁,死锁这种没有完全解决的方法,只能尽量预防。
    预防方法:

    1. 一次封锁法,指的是一次性把所需要的数据全部封锁住,但是这样会扩大了封锁的范围,降低系统的并发度;
    2. 顺序封锁法,指的是事先对数据对象指定一个封锁顺序,要对数据进行封锁,只能按照规定的顺序来封锁,但是这个一般不大可能的。

    系统判定死锁的方法:

    超时法:如果某个事物的等待时间超过指定时限,则判定为出现死锁;
    等待图法:如果事务等待图中出现了回路,则判断出现了死锁。

脏读、幻读、可重复度

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

  1. 选取最适用的字段属性
  2. 使用连接(Join)来代替子查询
  3. 使用联合来代替手动创建临时表
  4. 事务
  5. 锁定表
  6. 使用外键
  7. 使用索引
  8. 优化的查询语句

mysql查询

  1. 自连接

    如果在一个连接查询中涉及的两个表其实是同一个表,这种查询称为自连接查询 。

    //要查询王红所在的部门的所有员工
    SELECT p1.*  FROM employee AS p1 JOIN employee AS p2 ON p1.did=p2.did WHERE p2.name='王红';
    
  2. 外连接

    • 左连接(left join):返回左表中的所有记录和右表中符合条件的记录

      SELECT department.did,department.dname,employee.name 
      FROM department 
      LEFT JOIN employee ON department.did=employee.did
      

      img

    • 右连接(right join):返回右表中的所有记录和左表中符合条件的记录

      select department.did,department.dname,employee.name
      from department
      right join employee on department.did=employee.did
      

      img

  3. 内连接(inner join)

    又称为自然连接,内连接使用比较运算符对两个表中的数据进行比较,并列出与连接条件匹配的数据行,组成新纪录。

    SELECT employee.name,department.dname FROM department JOIN employee ON department.did=employee.did;
    
小表驱动大表

如果小的循环在外层,对于数据库连接来说就只连接5次,进行5000次操作,如果1000在外,则需要进行1000次数据库连接,从而浪费资源,增加消耗。这就是为什么要小表驱动大表。

MySql 中Char与VarChar的区别

  1. char
    • char类型是定长的类型,当输入的字符长度超过指定的长度时,char会截取超出的字符;
    • 当存储char值时,MySQL是自动删除输入字符串末尾的空格;
    • char是适合存储很短的、一般固定长度的字符串。
  2. varchar
    • varchar(n)类型用于存储可变长的。
    • 取数据的时候,不需要去掉多余的空格
    • 另外它还需要使用1或2个额外字节记录字符串的长度

group by 与 where, having以及顺序

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

img

where和having区别:
1.having只能用在group by之后,对分组后的结果进行筛选(即使用having的前提条件是分组)。
2.where肯定在group by 之前,即也在having之前。
3.where后的条件表达式里不允许使用聚合函数,而having可以。

count函数用法

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

数据库索引其实就是为了使查询数据效率快。

原理

索引就是通过事先排好序,从而在查找时可以应用二分查找等高效率的算法。

索引有哪些?
  1. 聚集索引(主键索引):在数据库里面,所有行数都会按照主键索引进行排序。
  2. 非聚集索引:就是给普通字段加上索引。
  3. 联合索引:就是好几个字段组成的索引,称为联合索引。 联合索引遵从最左前缀原则
索引的优缺点

索引的优点:
① 建立索引的列可以保证行的唯一性,生成唯一的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++;
    }
}
}
}

存储过程

1.Hash

Hash索引的底层实现是由Hash表来实现的,非常适合以 key-value 的形式查询,也就是单个key 查询,或者说是等值查询。其结构如下所示:

从上面结构可以看出,Hash 索引可以比较方便的提供等值查询的场景,由于是一次定位数据,不像BTree索引需 要从根节点到枝节点,最后才能访问到页节点这样多次IO访问,所以检索效率远高于BTree索引。但是对于范围查询的话,就需要进行全表扫描了。

但为什么我们使用BTree比使用Hash多呢?主要Hash本身由于其特殊性,也带来了很多限制和弊端:

  1. Hash索引仅仅能满足“=”,“IN”,“<=>”查询,不能使用范围查询。
  2. 联合索引中,Hash索引不能利用部分索引键查询。 对于联合索引中的多个列,Hash是要么全部使用,要么全部不使用,并不支持BTree支持的联合索引的最优前缀,也就是联合索引的前面一个或几个索引键进行查询时,Hash索引无法被利用。
  3. Hash索引无法避免数据的排序操作 由于Hash索引中存放的是经过Hash计算之后的Hash值,而且Hash值的大小关系并不一定和Hash运算前的键值完全一样,所以数据库无法利用索引的数据来避免任何排序运算。
  4. Hash索引任何时候都不能避免表扫描 Hash索引是将索引键通过Hash运算之后,将Hash运算结果的Hash值和所对应的行指针信息存放于一个Hash表中,由于不同索引键存在相同Hash值,所以即使满足某个Hash键值的数据的记录条数,也无法从Hash索引中直接完成查询,还是要通过访问表中的实际数据进行比较,并得到相应的结果。
  5. Hash索引遇到大量Hash值相等的情况后性能并不一定会比BTree高 对于选择性比较低的索引键,如果创建Hash索引,那么将会存在大量记录指针信息存于同一个Hash值相关联。这样要定位某一条记录时就会非常麻烦,会浪费多次表数据访问,而造成整体性能底下。

3. 扩展:B+/-Tree原理

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

MyBatis有什么优势,他如何做事务管理

MyBatis优点:

1.易于上手和掌握

  1. sql写在xml里,便于统一管理和优化

  2. 提供xml标签,支持编写动态sql。

  3. 提供映射标签,支持对象与数据库的orm字段关系映射

  4. 提供对象关系映射标签,支持对象关系组建维护

6. 解除sql与程序代码的耦合。

Mybatis管理事务是分为两种方式:

(1)使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交

(2)使用MANAGED的事务管理机制,这种机制mybatis自身不会去实现事务管理,而是让程序的容器(JBOSS,WebLogic)来实现对事务的管理

redis

Redis 是什么 ?

Redis 是 C 语言开发的一个开源的(遵从 BSD 协议)高性能键值对(key-value)的内存数据库,可以用作数据库、缓存、消息中间件等。 它是一种 NoSQL(not-only sql,泛指非关系型数据库)的数据库。

优点:

  • Redis 作为一个内存数据库: 性能优秀,数据在内存中,读写速度非常快,支持并发 10W QPS。
  • 单进程单线程,是线程安全的,采用 IO 多路复用机制。
  • 丰富的数据类型,支持字符串(strings)、散列(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)等。
  • 支持数据持久化。可以将内存中数据保存在磁盘中,重启时加载。主从复制,哨兵,高可用。
  • 可以用作分布式锁。
  • 可以作为消息中间件使用,支持发布订阅。

了解下 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 编程语言

2.5.1 Java

new Integer(123) 与 Integer.valueOf(123) 的区别在于:

  • new Integer(123) 每次都会新建一个对象;
  • Integer.valueOf(123) 会使用缓存池中的对象,多次调用会取得同一个对象的引用。

[String](https://cyc2018.github.io/CS-Notes/#/notes/Java 基础?id=二、string)

String 被声明为 final,因此它不可被继承。(Integer 等包装类也不能被继承)

String初始化之后就不可变

1. 可以缓存 hash 值

因为 String 的 hash 值经常被使用,例如 String 用做 HashMap 的 key。不可变的特性可以使得 hash 值也不可变,因此只需要进行一次计算。

2. String Pool 的需要

如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。

img

3. 安全性

String 经常作为参数,String 不可变性可以保证参数不可变。

4. 线程安全

String 不可变性天生具备线程安全,可以在多个线程中安全地使用。

[String, StringBuffer and StringBuilder](https://cyc2018.github.io/CS-Notes/#/notes/Java 基础?id=string-stringbuffer-and-stringbuilder)

1、可变性

  • String不可变
  • StringBuffer和StringBuuilder可变

2、线程安全

  • String不可变,因此线程是安全的
  • StringBuffer是线程安全的,内部使用synchronized进行同步
  • StringBuilder不是线程安全的

Array和ArrayList的区别:

1、Array类型的变量在声明的同时必须进行实例化(至少得初始化数组的大小),而ArrayList可以只是先声明;

2、Array对象的初始化必须指定大小,且创建后的数组大小是固定的;而ArrayList的大小可以动态指定,空间大小可以任意增加;

3、Array始终是连续存放的;而ArrayList的存放不一定连续;

4、Array不能随意添加、删除;而ArrayList可以在任意位置插入和删除

ArrayList和LinkedList的区别

1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2.对于查询和修改操做get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据 。

HashMap 和 Hashtable 的区别

  1. 线程安全: HashMap 是非线程安全的,而 Hashtable 是线程安全的,因为 Hashtable 内部的方法,基本都经过 synchronized 修饰(如果要确保线程安全,建议使用 ConcurrentHashMap);

  2. 执行效率: 因为线程安全的原因,HashMap 要比 Hashtable 效率高;此外,由于 Hashtable 基本被淘汰,最好不要在项目中使用它;

  3. 对 Null key 和 Null value 的支持: HashMap 中,null 可以作为键,这样的键最多可以有一个,但可以有一个或多个键所对应的值为 null;在 Hashtable 中,键和值都不能为 null,否则会直接抛出 NullPointerException;

  4. 初始容量大小和扩容的机制不同
    ① 创建时,如果未指定容量初始值,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)向上转型:多态中需要将子类的引用赋给父类对象,只有这样该引用才能够调用父类的方法和子类的方法(父类引用指向子类对象。)

重写和重载的区别;

方法的重载和重写都是实现多态的方式 。

区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。

重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的参数列表,有兼容的返回类型。

重载发生在一个类中,同名的方法有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)。

class和interface的区别

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

Integer与int的区别

1、integer是int的包装类,int是Java的一种基本数据类型

2、integer变量必须实例化后才能使用,int变量不需要

3、integer实际是对对象的引用,int是直接存储数据值

4、integer的默认值是null,int的默认值是0

Equals通常用来比较两个对象的内容是否相等,==用来比较两个对象的地址是否相等

java中创建线程的四种方法以及区别

Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。Java可以用四种方式来创建线程,如下所示:

1)继承Thread类创建线程

定义Thread类的子类,并重写Thread类的run()方法,创建子类对象(即线程对象),调用线程对象的start()方法来启动该线程。

2)实现Runnable接口创建线程

  • 定义Runnable接口的实现类
  • 重写该接口的run()方法
  • 通过Thread类建立线程对象
  • 将Runable接口的子类对象作为实际参数传递给Thread类的构造函数
  • 调用Thread类的start方法开启线程并调用Runable接口子类的Run方法

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虚拟机(JVM)是运行Java字节码的虚拟机,它是java编程语言的核心。

  • 当我们运行程序时,JVM负责将字节代码转换为特定于机器的代码
  • JVM还依赖于平台,并提供核心Java函数,如内存管理,垃圾收集,安全性等。

JVM被称为虚拟,因为它提供的接口不依赖于底层操作系统和机器硬件。这种与硬件和操作系统的独立性使得java程序可以在任何地方进行一次写入。

java jvm的内存机制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-46CDxShJ-1585126522552)(C:\Users\zhangboyi\AppData\Roaming\Typora\typora-user-images\1584201825931.png)]

img

https://blog.csdn.net/sun337939896/article/details/79092356

程序计数器和虚拟机栈都是线程私有的内存。


1.程序计数器:

  • 可以看做是当前线程所执行的字节码的行号指示器。每条线程都有一个独立的程序计数器,所以程序计数器是线程私有的内存区域

  • 主要存放代码执行的位置。分支、循环、跳转、异常处理、线程恢复等基础功能都需要计数器来完成。

2.Java虚拟机栈:

  • 存放各种基本数据类型和对象引用。
  • Java虚拟机栈是线程私有的,它的生命周期与线程相同。

3.本地方法栈

本地方法栈与虚拟机栈的区别:虚拟机栈为虚拟机执行Java方法服务(也就是字节码),而本地方法栈为虚拟机使用到的Native方法服务。

堆和方法区是各个线程共享的内存区域

4.Java堆:

  • 存放的是new创建的对象实例。几乎所有对象都在此分配内存。
  • 所有的线程共享的一块内存区域,在虚拟机启动时创建。
  • 垃圾回收器管理的主要区域。
  • 可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可

5.方法区:

  • 它用于存储已被虚拟机加载的类信息常量静态变量即时编译器编译后的代码等数据
  • 所有的线程共享的一块内存区域。
类的加载机制

类的加载过程是指将java编译之后的class文件读入到内存中,然后在堆区创建一个java.lang.Class对象,用于封装类在方法区内的数据结构。类加载的最终目的是封装类在方法区的数据结构,并向java程序员提供访问方法区数据的接口

垃圾回收机制GC

https://www.jianshu.com/p/23f8249886c6

垃圾回收(Garbage Collection)是Java虚拟机(JVM)垃圾回收器提供的一种用于在空闲时间不定时回收无任何对象引用的对象占据的内存空间的一种机制。

垃圾判断算法

  • 引用计数法

    给每个对象添加一个计数器,当有地方引用该对象时计数器加1,当引用失效时计数器减1。用对象计数器是否为0来判断对象是否可被回收。缺点:无法解决循环引用的问题

  • 可达性分析算法

通过一系列的 GC Roots的对象作为起始点,从这些节点出发所走过的路径称为引用链。当一个对象到 GC Roots 没有任何引用链相连的时候说明对象不可用。

可作为 GC Roots 的对象:

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中 JNI(即一般说的 Native 方法) 引用的对象

垃圾回收算法

在确定了哪些垃圾可以被回收后,垃圾收集器要做的事情就是开始进行垃圾回收,但是这里面涉及到一个问题是:如何高效地进行垃圾回收。这里我们讨论几种常见的垃圾收集算法的核心思想。

  • 标记-清除算法

    • 效率不高
    • 空间会产生大量碎片
  • 复制算法

    会造成空间利用率低下。

  • 标记-整理算法

    解决内存碎片化问题,把存活的对象移到内存一端。

  • 分代收集算法

    根据存活对象划分几块内存区,一般是分为新生代和老年代。然后根据各个年代的特点制定相应的回收算法。

    新生代

    每次垃圾回收都有大量对象死去,只有少量存活,选用复制算法比较合理。

    老年代

    老年代中对象存活率较高、没有额外的空间分配对它进行担保。所以必须使用 标记 —— 清除 或者 标记 —— 整理 算法回收。

内存泄露与内存溢出

内存泄漏:当一个对象已经不需要再使用本该被回收时,另外一个正在使用的对象持有它的引用从而导致它不能被回收,这导致本该被回收的对象不能被回收而停留在堆内存中,这就产生了内存泄漏。

**内存溢出:**为每个应用程序分配的内存是有限的,而当一个应用中产生的内存泄漏比较多时,这就难免会导致应用所需要的内存超过系统分配的内存限额,这就造成了内存溢出。

java里内存泄漏和溢出的区别

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分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。

****Hash****表即散列表

其最突出的优点是查找和插入删除具有常数时间的复杂度

其实现原理是:把Key通过一个固定的算法函数即所谓的哈希函数转换成一个整型数字,然后就将该数字对数组长度进行取余,取余结果就当作数组的。

数组与链表的区别

数组:

1、在内存中,数组是一块连续的区域。

2、数组需要预留空间,空间利用率较低

3、插入和删除数据都要大量移动元素的位置,效率比较低下,但查询效率比较高

4、数组的空间是从栈分配的。

链表

1、在内存中,空间是分散的,不是连续性的

2、链表的查询效率低,但插入或删除的效率高

3、空间不需要提前指定大小,是动态申请的,空间利用率较高。

4、链表的空间从堆中分配

2.6 智力题

1、 有25匹马,5个跑道。没有秒表。为了选出跑得最快的三匹马,请问最少进行多少轮比赛?

​ 7场。思路如下:

  • 25匹马分5组,分别选出每组的第一,+5场

  • 各组第一再比一场,+1场,(确定第一名,以及记录本场赛跑前三名所在的小组)

  • 排除掉已确定的第一名和不可能排名前三名的马,剩余5匹,再比一场,取得前两名,+1场。(即第6场比赛排名第一的小组的第二、三名,排名第二所在的小组,取第一第二名,排名第三所在的小组,取第一名,总共5匹)

2、有一个5L和一个3l 的无刻度水杯,还有一个水池。如何量出4L水

  • 5L杯装满水,用5L杯的水装满3L杯(此时5L杯还有2L水)
  • 将3L杯的水倒进水池,在将5L杯剩下的2L水倒入3L杯中
  • 又取水池的水装满5L杯,用5L杯的水装满3L杯(倒进1L水)
  • 5L杯还剩4L
    3、老王进货一双鞋30,标价40,但是一直卖不出去,后面决定以标价50%卖出。这时候来买的人,拿了张五十元的,老王没零钱,去隔壁老李找了五张十块的。交易完成顾客离开后,老李发现那张50的是假钞,老王出于诚信赔老李50元,请问老王亏了多少钱?
  • 110元=假若不是假钱,亏了10块钱
  • 现为假钱,顾客那赔了50+10,老李那赔了50

4、有1001个珍爱币,每次只能取1,2,4个。现有A,B两个人。A先手,谁拿到最后一个珍爱币,谁输。请问A是否可以必胜?

  • A第一次先取1个,剩下1000个

  • 之后从B第一次取开始计数,保证每轮B+A所取的珍爱币的数目为奇数

编程题

1、 输入一个数n,求比这个数大的最小的一个回文数 。


2、判断两个数组中是否存在相同的数字,两个已经排好序的数组,写代码判断这两个数组中是否存在相同的数字?要求时间复杂度越低越好。

//复杂度为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;
        }
    }
}

3、找出一个字符串中所有回文子串(长度 >=3,长度为奇数的),并记录他的起始位置(暴力)

//中心拓展法
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++;
    }
}

4、寻找最长回文串

//中心拓展法    

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;

    }

4、给一个有序数组和它的大小,给定一个val,求这个数组里有没有这个val,有或者有不止一个的话,求第一次出现这个 val 的位置;

//二分法
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;
        }
       
    }
}

测试工具

fiddler抓包工具

  • 本质是一个web代理服务器,默认工作端口为8888。

    • 代理服务器的优势
      • 共享网络
      • 提高访问速度
      • 突破访问限制
      • 隐藏身份
  • 工作原理

    • 浏览器与服务器之间通过建立TCP连接以HTTP协议进行通信,浏览器默认通过自己发送HTTP请求到服务器。
    • 而Fiddler是http代理服务器,fiddler工作于七层中的应用层,能够捕获到通过的http(s)请求。
    • fiddler启动后会自动将代理服务器设置为本机,端口是fiddler监听端口。监听的端口号在fiddler 菜单 Tools- TeleriK Fiddler options-connections中可以修改。
  • 代理模式

    • 流模式

      流模式可以理解为是一种实时通信的模式,有请求就有返回,也就是实时返回!

    • 缓存模式

      等所有请求都到了再 一起返回,也就是等所有数据都准备好之后才返回给客户端!

测试理论基础

5种常见的测试用例设计方法

  1. 等价类划分法
  2. 边界值分析法
  3. 因果图法
  4. 场景法
  5. 正交实验设计法;
  6. 判定表驱动分析法;
  7. 错误推测法
  8. 功能图分析法

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

测试用例的设计需要参考需求文档。

  1. 界面测试
    • 界面布局是否合理
    • 按钮的大小是否易于点击
    • 登录界面是否美观,无乱码,无错字
  2. 功能测试
    • 用户名、密码、验证码采用等价类划分法
    • 用户名和密码是否大小写敏感
    • 输入密码是时,大写开启是否有提示信息
    • 假如需要发送手机验证码,发送验证码功能是否正常
    • 多种登录方式,各种登录方式是否相互影响
    • 手机验证码的时效性是否在规定的时间内
    • 验证码刷新功能是否正常
  3. 兼容性测试
    • 主流的浏览器下是否显示正常以及功能正常使用。
  4. 性能测试
    • 打开登录页面,需要的时间
    • 单用户下,服务器处理的时间,登录成功后跳转页面所需的时间。
    • 模拟大量用户进行操作,服务器的吞吐量,错误率等是否正常。
    • 网络延迟。弱网环境下,丢包率的问题。
    • App类的需要增加,耗电问题、流量问题、消耗内存问题。
  5. 安全性测试
    • 输入的密码是否可以隐藏,隐藏按钮的切换是否正常。
    • 用户名、密码是否支持复制粘贴。
    • 用户名和密码是否通过加密的方式,发送给web服务器。
    • 错误登录次数限制
    • 单用户在多台机器登录
    • 多用户在单台机器登录
    • 防止sql注入攻击
    • 防止xss跨站脚本攻击。
    • 根据不同的产品需求,验证其安全性
  6. 易用性测试
  7. 本地化测试
测试删除文件功能
  • 删除前确认

  • 文件删除成功/失败,应该有相应的提示信息

  • 不选择文件,点击删除按钮,出现相应的提示信息

  • 删除过程中,点击取消按钮,验证取消是否成功

  • 成功删除之后,是否可以撤销删除

  • 删除文件,一定要对删除权限和身份验证

  • 文件删除之后,是放入回收站还是彻底删除

  • 若存在批量删除,测试文件是否能够被成功删除

  • 测试批量删除的性能

  • 模拟大量用户进行批量删除,检查系统的稳定性

  • 对不允许存在的文件进行删除,提示相应的信息

  • 文件删除的过程中,网络中断,看是否能够成功删除

  • 是否有删除日志

  • 文件打开/文件正在复制,给出相应的提示信息

一瓶水怎么进行测试
给你一个杯子,要测试哪些属性
  1. 界面测试
    • 外观整齐美观,没有瑕疵
    • 图案是否合法
    • 图案是否容易掉落
  2. 功能测试
    • 有没有漏水
    • 烫手验证
    • 杯子的容量刻度是否正确
    • 盖子拧紧,倒过来,没有水漏出
    • 装有色饮料时,杯子是否会被染色,放置多久会被染色,染色之后是否能够清洗干净。
  3. 性能测试
    • 可使用最大的次数
    • 掉在地上不容易损坏
    • 杯子的耐热性、耐寒性测试
    • 长时间放置不会漏水
    • 杯子刻度,以及图案、文字不会受到温度,湿度的影响。
  4. 安全测试
    • 杯子材质是否安全
    • 高温或低温材质释放毒性
    • 防滑测试
  5. 兼容性测试
    • 杯子能够容纳果汁、白水、酒精等。

微信发红包

https://blog.csdn.net/qq_40891477/article/details/94395634

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5JZfwV3R-1585126522560)(C:\Users\zhangboyi\AppData\Roaming\Typora\typora-user-images\1585067861661.png)]

微信支付

img

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

波小艺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值