面试题

发布时间 2023-04-02 21:48:56作者: Super小赵

基础问题

可变类型和不可变类型

  可变类型:列表 字典 集合
  不可变类型:整型 浮点型 字符串 数组  

常用的魔法方法

 魔法方法就是在某种情况下会自动触发
  __init__  类()---->对象进行实例化
  __new__   类()---->产生一个空对象---->触发__init__完成对象实例化 并且有返回值 返回实例化好的对象
*** 两者的区别是:当实例化一个类的时候最先被调用的方法是__new__方法,__init__是在类实例被创建出来之后调用的,它完成的是类实例的初始化操作,而__new__方法是创建这个类实例的方法


  __call__  对象加括号调用时则会触发
  __str__   对象执行打印操作会触发 这个方法返回什么打印结果就是什么 并且这个方法必须返回一个字符串类型的数据  
    
  __getattr__  对象.属性 属性不存在 则会触发
  __setattr__  对象.属性=值 则会触发
    
  __getitem__  对象['属性'],属性不存在 则会触发
  __setitem__  对象['属性']=值  则会触发
    
    
# 双下enter(enter) 和 双下exit(exit)必须一起使用 要不会报错
  __enter__  当对象被当作with上下文管理操作的开始自动触发,并且这个方法返回什么,as后面的变量就会收到什么
  __exit__   当对象参与的with上下文管理语法执行完之后自动触发(子代码结束)

-上下文管理器:只要重写了__enter__和__exit__方法,就具备这个能力
  with 对象 as xx:
        1 写了一行代码,触发__enter__的执行
  2 写了一行代码,触发__exit__,做一些资源清理工作

类中的装饰器用过哪些

 如果类中不加任何装饰器,是绑定给对象的方法,对象来调用,对象 点 直接调用,会自动把对象传进去
    classmethod  绑定给类的方法,类来调,会自动把类传进去,对象也可以调
    staticmethod 不绑定给任何东西,也叫静态方法,类可以调 对象也可以调,它们不会自动传值
   
# 如何把方法包装成数据属性
    property装饰器 
加property装饰器的功能就是将函数的返回值作为类的属性,方法伪装成属性
 意思就是我们调用这个被装饰的函数不需要加括号去运行,而是直接像变量或者属性一样获取这个值

类中如何隐藏属性

  __属性,方法

高匿代理和透明代理

# 高匿代理和透明代理
-高匿:服务端拿不到真实客户端的ip地址
-透明:服务端能拿到真实客户端的ip地址

后端如何拿到真实客户端ip地址

X-Forwarded-For(XFF):获取HTTP请求真实的IP(作用)
    
通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段

什么是http

超文本传输协议
设计目的是保证客户端与服务器之间的通信

http和https的区别

-ssl认证
   https = http+ssl/tsl(加密方式)

http版本区别
0.9:底层基于tcp,每次http请求,都是建立一个tcp连接,三次握手,请求结束需要四次挥手
1.1:请求头中有个参数Keep-alive,可以保证多个http请求公用一个TCP连接
2.x:多路复用,多个请求使用同一个数据包

http请求头

x-forword-for,user-agent(用户代理),cookie,referer(告诉服务器该网页是从哪个页面链接过来的),content-Type(编码)

http协议

HTTP协议:是W3C制定的一种超文本传输协议
         底层是TCP/IP

-请求协议:
    请求首行:请求头地址,请求方式,http的版本
    请求头:key-value
    请求体
   
-响应协议:
    响应首行:响应状态码,响应字符串描述
    响应头:key-value,响应状态码,cookie
    响应体

http协议特性

1 基于TCP/IP协议之上的应用层协议

2 基于请求/响应模式

3 无状态保存

4 无连接

http的get请求和post请求的区别

POST 和GET本质都是一样的

最直观的区别就是get把参数包含在url中
post通过request body传递参数
你要给get加上request body,给post带上url参数,技术上是完全行的通的

1 get产生一个TCP数据包,post产生两个TCP数据包
  对于get方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据)
  而对于post,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200(返回数据)

2 get请求在浏览器刷新或者退出的时候是无害的,post的话数据会被重新提交

3 get可以存在缓存中,而post不行

4 get请求无法发送大量数据,而post可以

5 get请求只能进行url编码,而post支持多种编码方式

6 对参数的数据类型,get只接受ASCII字符,而post没有限制

7 get比post更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息

8 get可以被书签收藏,post不行

面试官要看项目

看的是你的编码水平

公司的看不了,给他看的都是个人项目
公司项目看不了,签了保密协议

数据库如何处理的?

-云数据库:阿里云数据库,花钱买的服务--->给账号密码--->公司不需要自己搭建mysql
    -MySQL
    -Reids
    -MogoDB
    
-自己的数据库,部署在云服务器上的数据库,是你自己的

你用过什么云产品?

阿里云的ecs,服务器
阿里云的oss,对象存储
云短信
七牛云 文件存储

看看你的数据库

-配置文件 dev.py  连的是本地的127.0.0.1

因为是自己的项目写一些小项目想用来开源 连的都是本地 自己做测试用的

上线怎么弄

不知道,公司就是给我一个地址和端口号,账名和密码不知道
账号和密码是在环境变量里去取的 这是他们上线的人才知道的 我们是不知道的

上线的数据库服务和项目服务是在同一台机器上吗?

不是的
django+uwsgi服务 一台
MySQL服务 单独一台 我们使用地址和端口号去链接 账号和密码是在环境变量里去取的 这是他们上线的人才知道的 我们是不知道的
redis 一台
前端服务 一台


是的
我们用户量不大 所有服务都在一台机器上 虽然这样不好 但公司就是这么用的 因为公司可能没有吧

celery用过吗?

用过
异步任务
延迟任务
定时任务

是可以用来做来定时任务,但是我们一般不采纳,因为celery太过庞大,就像用django写小脚本一样  

深浅拷贝

浅拷贝:
    会在内存中新开辟一个空间,存放这个拷贝的列表,但是列表里面的内容还是沿用之前对象的内存地址
    
深拷贝:
    会在内存中开辟新空间,将原列表以及列表里面的可变数据类型重新创建一份,不可变数据类型则沿用之前的
    
总结:
   1 浅拷贝花费时间少,占用的内存少,只拷贝顶层数据,拷贝效率高
   2 对不可变对象拷贝时,浅拷贝和深拷贝的作用是一致的,不开辟新空间,相当于赋值操作
   3 可变对象浅拷贝时,只拷贝第一层中的引用,如果元素是可变对象,并且被修改,那么拷贝的对象也会发生变化
   4 可变对象深拷贝时,会逐层进行拷贝,遇到可变类型,就开辟一块内存复制下来

什么是生成器,有什么应用场景?

生成器是一个特殊的程序,可以被用作控制循环的迭代行为,是一边循环一边计算的机制,称为generator
生成器是迭代器的一种,使用yield返回值函数,每次调用yield会暂停,而可以使用next()函数和send()函数恢复生成器

生成器的特点:
    1 节约内存
    2 迭代到下一次的调用时,所使用的参数都是第一次所保留下的,就是说,在整个所有函数调用参数都是第一次所调用时保留的,而不是新创建的
    3 send能穿值,能改变值
    4 yield会阻塞,下次调用会接着上面的未执行的接着执行
    
应用场景:
    由于可以使用生成器很方便地实现一个迭代器,因此迭代器适用的场景生成器几乎都适用
    进行大文件的读取时,多任务,python的协程

拔高问题

双写一致性

 1 修改数据库 更新缓存
 2 修改数据库 删除缓存
 3 定时更新

断点续传

# 概念
  客户端的断点续传指的是在下载或者上传文件的时候,将下载或者上传的文件人为的划成几个部分,每一个部分采用一个线程进行上传或者下载,如果碰到网络故障,可以从已经上传或下载的部分开始继续上传下载未完成的部分,而没不要从头再下载,可以节省时间提高速度
    
  -迅雷多线程下载


# 详细
大文件切片上传:
想要上传大文件,那么就需要将大文件进行切片,分为一块一块的小文件,将小文件分别发送给后台,后台接收到小文件后,将小文件存储起来,当所有小文件上传成功后,再将小文件合并到一个文件中,这样就完成了大文件切片上传
    
断点续传:
想要实现断点续传,那么首先实现大文件上传。当我们将文件切片,除了需要给文件对应的值(使用md5)外,还需要给每个小文件对应的编号,将md5和编号同时传送给后端,后端根据md5和编号进行小文件存储,当发生文件上传一半终止上传后,获取后端已经上传的小文件编号发送到前端,前端检测到后端发送的小文件编号,从对应编号的切片进行上传

内网穿透

内网穿透就是使用一台有公网 IP 的电脑(frp服务器,下文称为节点)作为 “中间人” 来与没有公网IP的电脑建立连接并转发数据


https://zhuanlan.zhihu.com/p/370483324

缓存穿透,击穿,雪崩

# 缓存穿透
  是指查询一个缓存中和数据库中都不存在的数据,导致每次查询这条数据都会透过缓存,直接查库,最后返回空。当用户使用这条不存在的数据疯狂发起查询请求的时候,对数据库就造成的压力就非常大,甚至可能直接挂掉

# 解决缓存穿透的方法一般有两种:
 第一种:缓存空对象
    就是当数据库中查不到数据的时候,缓存一个空对象,然后给这个空对象的缓存设置一个过期时间,这样下次再查询该数据的时候就可以直接从缓存中拿到,从而达到减少数据库压力的目的
  缺点:
    1 需要缓存层提供更多的内存空间来缓存这些空对象,当空对象很多的时候就会浪费很多内存
    2 会导致缓存层和存储层数据不一致

 第二种:使用布隆过滤器(推荐方法)
    就是一种数据结构,它是由一个长度为m bit的位数组与n个hash函数组成的数据结构,位数组中每个元素初始值都为0,在初始化布隆过滤器时,会先将所有key进行n次hash运算,这样就可以得到n个位置,然后将这n个位置上的元素改为1,这样,就相当于把所有的key保存到了布隆过滤器中了
    
布隆过滤器:
   bloomfilter:是一个通过多哈希函数映射到一张表的数据结构,能够快速的判断一个元素在一个集合内是否存在,具有很好的空间和时间效率。(典型例子,爬虫url去重)
    

    
# 缓存击穿
  是指当缓存中某个热点数据过期了,在该热点数据重新载入缓存之前,有大量的查询请求穿过缓存,直接查询数据库。这种情况会导致数据库压力瞬间骤增,造成大量请求阻塞,甚至直接挂掉
    
# 解决缓存击穿的方法也有两种:
 第一种:设置key值永不过期
    在设置热点key的时候,不给key设置过期时间即可,还有另外一种方式也可以达到key不过期的目的,就是正常给key设置过期时间,在后台同时启一个定时任务去定时更新这个缓存
    
 第二种:使用分布式锁
     使用了加锁的方式,锁的对象就是key,这样,当大量查询同一个key的请求并发进来时,只能有一个请求获取到锁,然后获取到锁的线程查询数据库,然后将结果放入到缓存中,然后释放锁,此时,其他处于锁等待的请求即可继续执行,由于此时缓存中已经有了数据,所以直接从缓存中获取到数据返回,并不会查询数据库

    

# 缓存雪崩
  是指当缓存中有大量的key值在同一时间过期,或者Redis直接宕机了,导致大量的查询请求全部到达数据库,造成的数据库查询压力骤增,甚至直接挂掉

# 缓存雪崩解决方案
 第一种:key值过期时间打散
    将每个key值的过期时间打散那,使它们失效点尽可能均匀分布
    
 第二种:redis发生故障的情况
    署redis时可以使用redis的几种高可用方案部署
     -redis主从架构
     -redis哨兵机制
     -redis集群

http/2多路复用

HTTP/1下的请求,并不能很好的利用宽带,一个TCP连接同时只能有一个HTTP请求和响应,如果正在发送一个HTTP请求,那其他的HTTP请求就得排队
这种排队会产生一个请求队列,当队头的请求发生意外(比如丢包、服务器响应缓慢),导致比平时要慢得多,就会导致后面的请求被延迟。这种情况我们称为 队头阻塞


为了解决这个问题HTTP/2采用了多路复用

在HTTP/2中,有两个非常重要的概念,分别是帧(frame)和流(stream)
帧代表着最小数据单位,每个帧会标识出该帧属于哪个流,流也就是多个帧组成的数据流
HTTP/2采用二进制数据帧传输,取代了HTTP1.x的文本格式,二进制格式解析更高效

# 多路复用
多路复用代替了HTTP1.x的序列和阻塞机制,所有相同的域名请求都通过同一个TCP连接并发完成
同一TCP中可以发送多个请求,对端通过帧中的标识知道属于哪个请求,通过 这个技术,可以避免HTTP旧版本中的队头阻塞问题,极大的提高传输性能

IO多路复用


数据库三大范式

1 . 每一个字段的值必须具有原子性,字段是最小的单元不可再分

​ 表中不能嵌套表,要保证数据不可再分

​ 例如:姓名,可以分为 姓 和 名 这是不允许的

  1. 表中字段必须完全依赖于全部主键而非部分主键

    任意 一个字段都只能依赖表中的同一个字段

    例如:一个表中有学生ID和学生姓名,班级ID和班级名称 这个就不符合第二范式

  2. 非主键外所有字段都必须互不依赖

    一张表最多存在在2层同类型信息

    例如:一张表中有学生编号和学生名称,有班级ID和院系名称,那么学生可以确定班级,班级可以确定院系,那么院系和学生有传递依赖,所以不符合第三范式

MySQL有哪些索引类型,分别有什么作用

索引:索引是提高检索速度的

MySQL有哪些类型

目前MySQL主要有FULLTEXT,HASH,BTREE,RTREE

FULLTEXT

FULLTEXT全文检索,目前只有MySAM引擎支持

这类针对于文本的模糊查询效率较低问题

HASH

由于HASH的唯一及类似键值对的形式

可以一次定位,不需要像树形索引那样逐层查找,因此具有较高的效率。但是这种高效是有条件的,即只在'='和'in'条件下高效,对于范围查找、排序及组合索引仍然效率不高

BTREE

BTREE索引就是一种将索引值按一定的算法,存入一个树形结构中,每次查询都是从树的入口开始遍历。这是mysql里默认和最常用的索引类型

RTREE

RTREE在MySQL很少使用,仅支持geometry数据类型,支持该类型的存储只有MySAM、BDb、innoDb,NDb、Archive几种。相对于BTREE,RTREE的优势在于范围查找

索引种类

普通索引:仅加速查询

唯一索引:加速查询+列值唯一

主键索引:加速查询 + 列值唯一(不可以有null) + 表中只有一个组合索引,其效率大于索引合并

全文索引:对文本的内容进行分词,进行搜索

ps:索引合并,使用多个单列索引组合搜索

覆盖索引:查询列要被所建的索引覆盖

事务的特性和隔离级别

事务的特性

  1. 原子性

    就是事务所包含的所有操作,要么全部成功,要么全部失败

  2. 一致性

    事务执行前和执行后,必须保持一致

  3. 隔离性

    一个事务执行的过程中,并不能被别的事务干扰

  4. 持久性

    事务被提交后,它会被永久存储到数据库中了

事务的隔离级别

  1. Serialzable(可串行读):可避免脏读、不可重复读、幻读的发生
  2. Repeatable(可重复读):可以避免脏读、不可重复读的发生
  3. Read committed(读已提交):可避免脏读的发生
  4. Read uncommited(读未提交):最低级别,任何情况都无法保证

MySQL默认的是 Repeatable,oracle默认的是Read commited

MySQL支持四种隔离级别,而oracle支持Serialzable和Read committed这两种级别

脏读

一个事务读取到一个未提交的数据的数据

不可重复读

在读某条数据的时候返回了不同的值,造成这个结果的原因是因为我们在查询了一次之后准备第二次查询的这个间隔,对我们进行查询的这条数据进行了修改

幻读

出现幻读不是对一条数据的操作产生的问题,而是操作多条数据产生的问题

幻读并不是说两次读取获取的结果集是不同的,幻读侧重的方面是某一次的 select 操作得到的结果所表征的数据状态无法支撑后续的业务操作

更为具体一些:select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读

幻读和不可重复读都在读取一个已经提交的事务,而脏读是读取一个未提交的事务

不可重复读是读取同一条数据

幻读是查询的是批量数据