嘿嘿
数据库三大范式是什么
-
第一范式(1NF)是指数据库表的每一列都是不可分割
表中不能嵌套表,要保证数据不可再分
例如:姓名,可以分为 姓 和 名
-
第二范式:如果表是单主键,那么主键以外的列必须完全依赖于主键;如果表是复合主键,那么主键以外的列必须完全依赖于主键,不能仅依赖主键的一部分任意 一个字段都只能依赖表中的同一个字段
例如:一个表中有学生ID和学生姓名,班级ID和班级名称 这个就不符合第二范式
-
第三范式(3NF)要求:表中的非主键列必须和主键直接相关而不能间接相关;也就是说:非主键列之间不能相关依赖
不存在传递依赖
一张表最多存在在2层同类型信息
比如一张表中有学生编号有学生名称,有班级id有院系名称,那么学生可以确定班级,班级可以确定院系,那么院系与学生有传递依赖,所以不符合第三范式
mysql有哪些索引类型,分别有什么作用
索引的种类
- 聚簇索引,聚集索引,主键索引,主键,如果不存在 主键,隐藏一个主键,构建聚簇索引
- 辅助索引,普通索引 index
- 唯一索引 unique
- 联合索引,组合索引,多列索引:unique index (user_id,user_name)
事务的特性和隔离级别
事务的特性
-
原子性
数据库把“要么全做,要么全部做”的这种规则称为原子性
-
一致性
一致性:事务执行前后的状态要一致,可理解为数据一致性
-
隔离性
隔离性:事务之间相互隔离,不受影响,这与事务的隔离级别密切相关
-
持久性
持久性:事务完成之后,她对数据的修改是永恒的,即时出现故障也能够正常保持
事务的隔离级别
- Serialzable(可串行读):可以避免脏读,不可重复读的、幻读的发生。
- Repeatable(可重复读):可以避免脏读、不可重复读的发生
- Read committed(读已提交):可避免脏读的发生
- Read uncommited(读未提交):最低级别,任何情况都无法保证
mysql默认是的 Repeatable, oracle默认是 Read commited
mysql支持四种隔离级别,而oracle支持Serialzable和Read committed这两种级别
-
脏读
指的是读到了其他事务未提交的数据,未提交意味着这些数据可能会回滚,也就是可能最终不会存到数据库中,也就是不存在的数据。读到了并一定最终存在的数据,这就是脏读
-
脏写
如果一个事务修改了另一个事务提交修改过的数据,就意味着发生了脏写现象。
-
不可重复读
指的是在一个事务内,最开始读到的数据和事务结束前的任意时刻读到的同一批数据出现不一致的情况
-
幻读
- 幻读错误的理解
幻读是 事务A 执行两次 select 操作得到不同的数据集,即 select 1 得到 10 条记录,select 2 得到 15 条记录。 这其实并不是幻读,既然第一次和第二次读取的不一致,那不还是不可重复读吗,所以这是不可重复读的一种。 - 正确的理解
并不是说两次读取获取的结果集不同,幻读侧重的方面是某一次的 select 操作得到的结果所表征的数据状态无法支撑后续的业务操作。更为具体一些:select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读
- 幻读错误的理解
幻读和不可重复读都是在读取一个已经提交的事务,而脏读是读取一个未提交的事务。
不可重复读是读取同一条数据
幻读是查询的是批量数据
什么是qps,tps,并发量,pv,uv
-
QPS
Queries Per Second,每秒查询率,一台服务器每秒能够响应的查询次数 -
TPS
Transactions Per Second,是每秒处理的事务数,包括一条消息入和一条消息出,加上一次用户数据库访问 -
并发量
系统同时处理的请求数量 -
PV
页面访问量,即页面浏览量或点击量,用户每次刷新即被计算一次。可以统计服务一天的访问日志得到 -
UV
独立访客,统计1天内访问某站点的用户数。可以统计服务一天的访问日志并根据用户的唯一标识去重得到。 -
DAU(日活)DAU(Daily Active User)
日活跃用户数量。常用于反映网站、app、网游的运营情况。DAU通常统计一日(统计日)之内,登录或使用了某个产品的用户数(去除重复登录的用户),与UV概念相似
-
MAU(Month Active User)
月活跃用户数量,指网站、app等去重后的月活跃用户数量
什么是接口幂等性问题,如何解决?
-
幂等
幂等(idempotent、idempotence)是一个数学与计算机学概念
一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同
-
接口幂等性
无论调用多少次,产生的效果是一样的
例如
-
get
每次获取的值都一样天然幂等
-
put
修改数据,每次修改的数据不一样,但是大的说就是这一条数据。不会对资源产生副作用
-
delete
删除,天然幂等
-
post
新增数据,不出现不幂等的情况,要把它做成幂等,会对资源产生副作用
-
解决
- 唯一主键,unique 新增用户 用户唯一,但是订单问题解决不了
- token机制,随机字符串,当你请求我这个接口的时候给你一个随机字符串,然后自己页存一份,接口做处理的时候,先判断拿你的字符串,跟我存的做对比如果一样则执行,这个串校验完就直接删除。
- 前端按钮只能点一次,但是后端页需要,因为有的人可能会把接口抠出来然会发请求,这个就涉及到反爬了
什么是gil锁,有什么作用
1、全局解释器锁,它的本质就是一个大的互斥锁,它是cpython的一个机制,gil只存在于cpython解释器
解释器不仅仅只有cpython,pypy,jpython
2、每个线程在执行的过程都需要先获取GIL,为了保证同一时刻只 有一个线程可以执行代码。
GIL只能够确保同进程内多线程数据不会被垃圾回收机制弄乱 并不能确保进程里面的数据是否安全
-为什么要有gil锁?
-保证数据安全? 用互斥锁就可以了,gil锁不能保证数据安全
-python的垃圾回收机制,需要垃圾回收线程来做,如果同一时刻,有多个线程在同时执行,垃圾回收就可能会把正在其他线程使用的变量给回收掉,因为当时只有单核电脑,本来统一时刻就不能有多个线程同时执行,于是作者就干脆做了一个gil锁,让线程必须获得到gil锁,才能执行,但后来随着多核的出现,导致python的多线程并不能利用多核
python的垃圾回收机制是什么样的
-高级一点的语言,为了保证内存的使用效率,都会有垃圾回收的机制,而咱们python使用以下三种方式来做垃圾回收。
-
引用计数:当一个值与一个变量名绑定,那这个值的引用计数是1,当这个值又与另一个变量名绑定那么这个值引用计数就为2了。
当一个值的引用计数为0,那么就视为垃圾,就会被回收。
-
标记清除:当没办法调用但值的引用计数不为零,python内部会把这些全部都打上标记然后一次性全部清理掉。
-
分代回收:垃圾回收器会更频繁的处理新对象。一个新的对象即是你的程序刚刚创建的,而一个老的对象则是经过了 几个时间周期之后仍然存在的对象。Python会在当一个对象从零代移动到一代,或是从一代移动到二代的过程中提升 (promote)这个对象。
解释为什么计算密集型用多进程,io密集型用多线程
-由于GIL锁的存在,即便是多核机器,同一时刻,也只能有一个线程在执行
-线程需要cpu去调度执行
-如果开了多线程,是计算密集型,计算是消耗cpu,假设是四核电脑,不能充分利用这四个核,只能有一个核在执行,开多线程没有用
-而如果计算密集型,开了多进程,gil是在cpython解释器进程中的,再进程中开启线程执行计算,可以充分利用多核优势
-开了一个进程,就开了一个cpython解释器的进程,就会有一个gil锁
-由于GIL锁的存在,如果是计算密集型,开启多线程,不能利用多核优势,
-开启多进程,可以利用多核优势
-io不耗费cpu,开启多线程,在一个时间段内是有并发效果的
-即便是io密集型,用多进程是不是会显著提高效率?
本身开启进程是非常消耗资源的,如果是io密集型,没有必要开多进程,并不会有显著的效率提升
为什么有了gil锁还要互斥锁
gil:全局解释器锁,线程要执行,必须获得gil锁,才能执行
互斥锁:为了保证多线程并发操作数据(变量)而设置的锁,保证在加锁和释放锁之间,其他线程不能操作
gil本质也是大的互斥锁
因为gil不能锁住临界区,而互斥锁可以锁住临界区所以只是用gil在多线程操作的时候会出现数据安全问题。
什么是临界区?
出现并发安全问题的这段代码称之为临界区,临界区会出现并发安全问题,所以要加锁
a=0
线程1要计算:a+=1
1 线程1 拿到gil
2 读取 a=0
3 假设时间片到了,释放gil,释放cpu
4 等待下次被调度执行
线程2要计算:a += 1
5 线程2 获得了gil锁
6 读取a=0
7 计算a+1
8 把结果赋值 a, a=1
9 释放gil锁
进程,线程和协程
进程:是资源分配的最单位,一个应用程序运行起来,至少有一个进程,进程管理器中就可以看到一个个的进程
线程:是cpu调度的最小单位,一个进程下至少有一个线程
协程:单线程下的并发,程序层面控制的任务切换
代码如何实现
开启多进程的两种方式
1 写一个类,继承Process,重写类的run方法--》实例化得到对象,对象.start 开启进程
2 通过Process类实例化得到一个对象,传入任务,调用对象.start开启进程
1 开启一个线程 先继承Thread,重写类的run方法--》实例化得到对象,对象.start 开启进程
2 通过Thread类实例化得到一个对象,传入任务,调用对象.start 开启进程
开启协程
早期之前:借助于第三方gevent,基于greelet写的
async和await关键字,不借助于第三方,开启协程 asyncio包
必须写在一个函数前
async def task()--->这个函数执行的结果是协程函数
await 只要是io操作的代码,前面必须加 await
在那用过
我一般遇到计算密集型的操作,我会开多进程,io密集型的操作,我一般开多线程
闲来无事,爬取别人数据,喜欢开多线程,爬虫io居多我开多线程
比如一个视图函数,异步的爬取数据写的文件中
异步的发送钉钉通知
异步的发送邮件
但实际上,在项目中,不需要我们开启进程线程,可以借助于第三方的框架比如celery就可以做异步的操作
而celery的worker,就是进程线程架构
django框架,是支持并发,我们没有开启多进程和多线程,但是符合uwsgi的web服务器在进入django框架之前,开启了进程和线程来执行视图函数
什么是鸭子类型
走路像鸭子,说话像鸭子,我们就可以叫他鸭子
解释:鸭子类型是python面向对象中描述接口的一个概念,区分于其他编程语言,
比如java:实现接口,必须显示的继承一个接口
而python:实现接口,遵循鸭子类型,不需要显示的继承一个接口(类),只要类中有对应的属性跟方法,我们就称这几个类的对象为同一种类型
什么是猴子补丁,有什么用途
-
什么是猴子补丁,有什么用途
猴子补丁:在程序运行过程中,动态替换的一种技术
-
比如咱们json模块,用内置的json,效率低,有一个第三方ujson模块
不改变程序的源代码,把程序中所有json都替换成ujson
在程序运行的入口处:
import ujson as json -
django中 pymysql的替换
import pymsql pymysql.install_as_MySQLdb() -
gevent--->猴子补丁--monkey.pach_all()--->动态的替换内部会阻塞的代码
-time
-socket
-把所有内置的会释放gil锁的模块,动态替换成gevent自己写的,不会释放gil锁的模块
同步代码:io操作,会阻塞,会释放gil锁,这条线程会释放cpu 异步代码:遇到io,不释放gil锁 动态的把所有同步会阻塞的代码的代码,都替换成异步代码。
什么是反射,python中如何使用反射
反射:是程序在运行过程中通过字符串来操作对象的属性和方法。
hasattr 检测是否含有某属性
getattr 获取某属性
setattr 设置某属性
delattr 删除某属性
http和https的区别
https=http+ssl/tls
监听的端口不一样,http 80 https 443
保证http传输的安全
什么是http 数据传输是明文
超文本传输协议
是一个基于请求响应,无状态,无连接,作用于应用层之上的协议,他规定了浏览器于服务端之间数据交互的格式。
什么是https 数据传输是密文
安全超文本传输协议
https使用的主要目的是提供对网站服务器的身份认证,同时保护交换数据的隐私于完整性。
https是基于http协议,通过SSL或TLS提供加密处理数据、验证对方身份以及数据完整性保护。
http的默认端口80,https的默认端口443
HTTP 的连接很简单,是无状态的。HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 协议安全。
HTTP 是超文本传输协议,信息是明文传输,HTTPS 则是具有安全性的 SSL 加密传输协议。
HTTPS 协议需要到 CA (Certificate Authority,证书颁发机构)申请证书,一般免费证书较少,因而需要一定费用。(以前的网易官网是http,而网易邮箱是 https 。)
https是http+ssl或tls构成的
从浏览器输入一个地址,到看到页面信息,经历的过程
- 在浏览器输入的是:域名---》要做域名解析--》把域名解析成ip地址+端口的形式---》dns解析(浏览器缓存,本地缓存,host文件,本地DNS服务器, 根dns)---》如果解析不到则会报404
- 解析完后,向解析出的域名和端口,建立TCP连接,进行3次握手
- 向某个地址发送http的get请求
- 如果后端服务是使用nginx转发,nginx把http请求转发给web框架(django, flask)-->django请求生命周期
- 后端服务器以http响应的形式返回给客户端浏览器
- 客户端浏览器把http响应体的内容展示在浏览器上,但是http响应还有:状态码,响应头
- 四次挥手断开tcp连接--》http协议版本
https://blog.csdn.net/m0_52165864/article/details/126313277
左连接,右连接,内连接,全连接:MySQL不能直接支持
数据通常不在同一张表中,这就涉及到连表操作,而连接的方式有很多
内连接:把两张表共有的数据,连接到一起
右连接:以右表为基准,把右表所有的数据都展示,有可能左表没有,用空补齐
左连接:以左表为基准,把左表所有的数据都展示,有可能右表没有,用空补齐
全连接:以左右两表数据作为基准,左右两表数据都展示,有可能左或表没有,用空补齐
union和union all的区别
select 出来结果,union, union all 都是对结果进行合并,求并集
union 会去重
union all 不会去重
tcp三次握手和四次握手
tcp是面向连接的可靠协议,使用三次握手,四次挥手保证可靠,数据不丢失
-SYN: SYN=1 表示要建立连接
-FIN: 表示断开连接
-ACK: ACK=1 表示我要收到了,允许
-seq: 随机数,建立连接无论客户端还是服务端要建立连接就要携带
-ack:回应请求就要加1返回
三次握手:
第一次:客户端向服务端发送简历连接请求,【携带一个随机数】(SYN=1,seq=随机数)
第二次:服务端回应客户端的简历连接请求(ACK=1,ack=随机数+1),服务端发送建立连接请求(SYN=1,seq=另一个随机数)
第三次:客户端回应服务端的建立连接请求(ACK=1,ack=另一个随机数+1)
四次挥手:
第一次:客户端向服务端发起断开连接的请求(FIN=随机数)
第二次:服务端收到后,回复这个请求(ACK=1,ack=随机数+1)
第三次:服务端向客户端发起断开连接的请求(FIN=另一个随机数)
第四次:客户端收到后,回复这个请求(ACK=1,ack=另一个随机数+1)
-三次握手:
-第一次:喂(SYN=1),我是lqz(seq=随机数)
客户端:SYN_SEND状态
服务端:没收到:listen 状态,收到了是:SYN_RCVD状态
-第二次:收到(ACK=1),lqz啊(ack=随机数+1),喂(SYN=1),我是刘亦菲(seq=随机数1)
服务端:SYN_RCVD状态
客户端:没收到服务端返回的第二次:SYN_SEND状态,一旦收到就established
-第三次:收到(ACK=1),刘亦菲你好(ack=随机数1+1)
客户端:连接建好的状态 established
服务端:收到后,处于established
OSI七层协议,那七层,每层有那些,TCP/IP五层结构
- osi七层: 应用层 表示层 会话层 传输层 网络层 数据链路层 物理层
- 五层结构: 应用层 传输层 网络层 数据链路层 物理层
应用层协议:http,ftp,https,dns
表示层:加密解密,压缩解压缩
会话层:负责建立、管理和终止表示层实体之间的会话连接
传输层:tcp协议,udp协议,端口协议
网络层:ip地址协议
数据链路层:mac地址,以太网协议
物理层:物理介质,网线
tcp和udp的区别
tcp是面向连接的可靠协议
udp无连接的不可靠协议
都是处于传输层
udp: dns协议用的udp协议
tcp:http,mysql,redis客户端服务端通信
WSGI uwsgi uWSGI,cgi,fastcgi分别是什么
-
CGI:通用网关接口(Common Gateway Interface/CGI), CGI描述了服务器(nginx, apache)和web框架之间传输数据的一种标准
所有的bs架构软件都是遵循CGI协议的
一句话总结:一个标准,定义客户端服务器之间如何传输数据
-
FastCGI:快速通用网关接口(Fast Common Gateway Interface/FastCGI)是一种让交互程序与Web服务器通信的协议。FastCGI是早期通用网关接口(CGI)的增强版本
- FastCGI致力于减少网页服务器与CGI程序之间互动开销,从而使服务器可以同时处理更多的网页请求
- 常见的FastCGI服务器:Apache,Nginx
通俗说 FastCGI是CGI的升级版
-
WSGI:Python Web Server Gateway Interface的缩写为WSGI,Python定义的Web服务器和Web应用程序或框架之间的一种通用的接口
- 一句话总结:一个Web Server,即一个实现了WSGI协议的服务器,处理发来的请求及返回响应
-
uwsgi:uWSGI服务器实现的独有协议,用于定义传输信息的类型,是用于前端服务器与uWSGI服务器的通信规范
uwsgi是uWSGI自有的协议
uWSGI:web服务器等同于wsgiref
符合WSGI协议的web服务器
符合WSGI协议的web服务器
wsgiref,werkzeug(一个符合wsgi协议的web服务器+工具包(封装了一些东西))
uWSGI 用c语言写的,性能比较高
gunicorn:python写的
tornado: 也可以部署django项目
web服务器到底是什么?服务器中间件
客户端(浏览器,app) 跟服务端(web框架)之间的东西,服务器中间件
nginx apche 是一类东西,就是做请求转发
uWSGI 只针对与python的web框架
tomcat,jboss,weblogic 只针对java的web框架
如何定制上下文管理器
一个对象如果实现了__enter__和__exit__方法,那么这个对象就支持上下文管理协议,即with语句
上下文管理协议适用于那些进入和退出之后需要执行一些代码的场景,比如文件、网络连接、数据库连接或使用锁,使用事务的编码场景。
Python是值传递还是引用传递
什么是值,什么是引用
值就是一个具体的值(一块内存空间放着这个变量的值)
引用是一个值得内存地址(内存地址指向了值)
什么是值传递,什么是引用传递
如果是值传递,函数中修改了传递得值,不会影响原来的
如果是引用传递,函数中修改了传递的引用,就会影响原来的
严格意义上来说,python既不是值传递,也不是引用传递,python是 自己的传递方式,规则是:
如果传递的是不可变类型,再函数中修改,就不会影响原来的变量。
如果传递的是可变数据类型,再函数中修改,不会影响原来的变量,修改,而不是重新赋值
什么是迭代器,生成器,装饰器
- 迭代:一种不依赖于索引取值的方式,我们不需要关注它的位置,只要能够一个个取值,他就称之为迭代
for 循化 next()
-
可迭代对象:可以迭代的(for,next取值的)python中的对象称之为可迭代对象,
有字典,列表,字符串,元组,集合,文件对象
-
迭代器:可迭代对象调用
__iter__,就得到了迭代器,迭代器__iter__和__next__方法 -
自定义迭代器:写个类,类中重写
__iter__和__next__方法,这个类的对象就是迭代器 -
生成器:生成器本质就是迭代器,函数中有
yield关键字,这个函数被调用,会返回一个生成器生成器表达式,也可以做出生成器
-
装饰器:本身就是一个闭包函数,作用是不在改变被装饰对象源代码和调用方式的基础上,为它加入新功能
比如:flask的路由就是基于装饰器
django的信号也可以用装饰器
django中局部去除csrf
django的信号用过吗?如何用,干过什么
-
django提供的一种通知机制,他是设计模式观察者模式(发布订阅),在发生魔咒变化的时候,通知某个函数执行
-
内置信号:如果内置信号用起来简单,只需要写个函数,跟内置信号绑定,当信号被触发,函数就会执行
django中绑定信号有两种方式
@receiver
connect连接
自定义信号:就比内置信号多了两步,
-
触发信号 信号. send
Dockerfile用过吗?常用命令有哪些
-
Dockerfile 是用于构建 Docker 镜像的文本文件。它包含一系列指令和参数,用于描述如何构建镜像,并定义了镜像的内容和配置。
FROM 基于那个镜像 RUN 执行那条命令 ENV 环境变量 WORKDIR 工作目录设置完工作目录然后在下载就会默认下载到这个目录下
并行,并发,同步,异步,阻塞,非阻塞
-
并行,并发
并发:同一时间段内,执行多个任务的能力
并行:同一时刻,执行多个任务的能力,执行多少个任务就需要多少个cpu
-
同步,异步
同步:同步是一件事一件事的做,只有执行完前一个任务,才会执行下一件任务。同步意味着有序
异步:当一个任务已经执行了,你无需等待该任务执行完成。就可以切换到另外一个任务上,异步意味着无序。
-
阻塞,非阻塞
阻塞:程序在等待某个操作完成期间,自身无法继续干别的事情,则称该程序在该操作上是阻塞的
非阻塞:程序在等待某擦欧总过程中,自身不被阻塞,可以继续运行干别的事情,则称该程序在该操作上是非阻塞的。
阻塞一般说的执行状态,一共有三种执行状态,一个是执行态,阻塞态,就绪态。
如果一个线程遇到io行在哪则称称之为该线程现在处于阻塞态,释放cpu
非阻塞态
当cpu在调度的线程,则该线程称之为运行态,没有在调度,在等待cpu调度的称之为是就绪态
什么时IPC,如何进行进程间通信
IPC:Inter-Process Comunication,进程间通信,
两种情况:
- 同一台机器上的两个进程通信
- 不同机器上的两个进程进行通信
如何通信:
python queue可以做进程间通信
消息队列:redis就可以做消息队列,rabbitmq,kafka
socket套接字
- 服务于服务之间,通过接口调用
- RPC调用:远程过程调用
正反向代理
正向代理,代理的时客户端,隐藏客户端的真实信息,爬虫的代理池
反向代理,代理的是服务端,隐藏服务端的真实信息,nginx
比如 10086,你只需要给10086打电话就行了,他就可以给你解决相对应的问题,但是你不知道这个客服的真实信息是什么。
什么是粘包
因为TCP是流式协议,tcp客户端发送的多个数据包就会像水流一样流向TCP服务端,多个数据包就会粘在一起,区分不开几个数据包,造成了粘包现象
- 每个包设置结束标志 http协议采用这种
/r/n/r/n - 每个包设置固定大小的头,头中包含包的大小
only,defer
User.object.only(name)相当于是select name from user
那么取name则不走sql,别的字段则走sql
defer相反。

浙公网安备 33010602011771号