** 0.深拷贝和浅拷贝的区别?**
- copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象。好处:只拷贝引用,不增加内存
- copy.deepcopy 深拷贝 拷贝对象及其子对象 好处:可用于备份,源数据被修改它不会被影响
可变类型(list,dict):浅拷贝只拷贝第一层,深拷贝会拷贝所有层
不可变类型(int,string,float,tuple):深浅拷贝都一样,只拷贝引用
注意:
可变类型里嵌套不可变类型或不可变里面嵌套可变类型:浅拷贝只拷贝引用,而深拷贝为保证数据的独立性,它会从最外层到不可变类型都复制一遍
作用:浅拷贝可以节省内存空间,pytho中大多数都是浅拷贝。可以根据需求进行浅拷贝还是深拷贝。例如是备份重要数据,不想被修改就采用深拷贝。(因为浅拷贝指向同一个地址,不会增加内存,相当于桌面快捷方式一样.)
1.*args, ** kwargs是什么意思?
*args: 可变位置参数。
*kwargs: 可变关键字参数。
2.谈一谈Python中的装饰器
Python中的装饰器其实也是一种函数, 它可以在不修改原函数代码情况下扩展原函数功能。装饰器函数与普通函数不同之处就在于装饰器函数返回了一个函数对象,装饰器利用了闭包的原理来实现。主要用于日志插入,权限管理等等。
3.Python的垃圾回收机制以及内存管理
垃圾回收机制:
Python的垃圾回收机制以引用计数为主, 标记清除、分代回收为辅。引用计数指:Python在内部维护了针对每一个对象的引用计数, 当一个对象创建或者被引用时,其引用计数将加1,当一个对象被销毁或作用域失效时, 其引用计数将减1。只有对象的引用计数为0时,这个对象将会被回收。引用计数的优点:简单、具有实时性。缺点:对象循环引用时将永远不会被销毁。对于对象循环引用的状况Python使用标记清除来解决,Python在内部实现了一个循环检测器, 不停的检测对象是否存在循环引用,如果两个对象互相循环引用并且不包含其他第三者对象时, 其将会被收回。在Python参考手册中有写道:
当一个对象无法获取时, 那么这个对象有可能被当成垃圾销毁了。Python将所有对象分成了三代, 对象存活时间越长就越晚被回收, 反之则越早被回收。
内存管理:
Python使用了内存池机制来管理内存,其内存以金字塔的形式对内存功能进行划分,-1、-2层主要用于对操作系统进行操作, 0层中是C的malloc,、free等等内存分配和释放函数。1、2层是一个内存池, 当对象小于265K时将直接由这片内存池进行分配内存,否则将调用第0层中的C函数来分配内存,当小于265K的对象被销毁时, 其内存也不会被销毁, 只是返回给了内存池以便二次利用。2层是对Python对象进行操作。
4.Python多线程
Python中多线程由于有GIL的影响, 导致在任意时间内只有一个线程在运行,所以Python的多线程在处理计算密集型任务上效果反而不如单线程, 只有在处理IO密集型任务上多线程才能发挥实力,在等待IO过程中Python C源码会释放GIL, 最终会导致线程在等待IO过程中会被暂停去执行其他的线程。python中GIL主要是由于历史原因导致Cpython虚拟机中的GIL难以移除,同时GIL的存在保证了多线程之间数据完整性以及状态同步。
5.说明os、sys模块不同,并列举常用的模块方法
os: 提供了对使用操作系统函数的高度封装
sys: 提供由解释器访问或者维护的变量以及与解释器交互的一些函数os模块只负责程序与操作系统交互, 提供了访问操作系统底层的接口封装。
sys模块负责程序与解释器交互, 提供了一系列的函数用于操控Python运行的环境设置。
os模块常用方法:
os.getcwd() # 获取当前运行路径
os.remove() # 删除指定的文件
os.walk() # 生成指定目录下的文件夹以及文件
os.makedirs() # 生成多成目录
os.mkdir() # 生成目录
os.rmdir() # 删除指定目录
os.removedir() # 删除多层目录
os.listdir() # 列出指定目录下所有的文件夹以及文件
os.path.join() # 将分离的各部分组合成一个路径名
os.path.getsize() # 获取指定文件大小
os.path.exists() # 查看指定目录或者文件是否存在
os.path.isabs() # 查看指定目录是否为绝对路径
…
sys模块常用方法:
sys.argv# 命令行参数列表
sys.exit() # 退出程序并返回指定的整数
sys.maxunicode # 最大的Unicode值
sys.modules # 系统导入的模块名称
sys.path # python搜索模块时的路径
sys.stdout # 标准输出
sys.stdin # 标准输入
sys.stderr # 错误输出
…
6.什么是lambda表达式?它有什么好处?
lambda也是函数的一种, 在处理一些简单的操作时可以使用该表达式, 其好处是不用为一些实现简单功能的函数命名,毕竟编程只有两个难点: 缓存失效, 命名。
7.Python里面如何拷贝一个对象?
Python中拷贝分为深拷贝、浅拷贝。浅拷贝只拷贝父级对象, 不会拷贝对象内部的子对象,使用copy模块中的copy。深拷贝则会完全拷贝父对象以及子对象, 使用copy模块中的deepcopy。
8.__new__和__init__的区别。
__new__负责构建一个类对象并将其返回,init则负责初始化一些变量,不返回任何对象。在实例化一个类时, __new__方法将会先被运行, 其次才运行__init__方法。
9.python中协程?协程的作用?
Python中协程最初使用yield来实现, 当程序运行到yield语句时就会将控制权交出来去执行其他的函数, 在Python3之前只能通过原生yield、greenlet以及Gevent第三方库来实现协程, 在Python3 之后引入了yield from, yield from 用于重构生成器。在Python3.5之后引用了async和await, 其作为yield from, yield的完美替身来实现协程。
协程的作用:当遇到阻塞就去执行其他的程序,例如遇到yield语句就跳出去执行其他函数
10.Python的异常机制?
Python中异常也是一个对象, 所有的异常的基类都是Exception。捕获异常使用try…except…语法,如果要try与except之间的代码出现了错误并且我们将其异常类型捕获了那么代码将会跳转代except中去执行。还可以使用raise 去手动的触发一个错误,也可以使用assert来触发异常, 只不过assert经常用来在测试中, 并且assert对程序的性能有着极大影响,只有内置的__debug__为True时assert才会执行。
11.python旧式类(经典类)和新式类的区别
经典类与新式类的区别是:继承搜索的顺序发生了改变,经典类多继承搜索顺序是深度优先, 按照从左至右的查找,并且将每一个父类的基类都查找一遍。新式类则是, 先从左至右的查找, 然后再向每一个父类的基类进行查找。(都是从左至右的顺序查找, 经典类查找一个父类时同时向上查找,新式类则是先查找所有的父类然后再向上查找)
12.classmethod,staticmethod,property是什么?有什么作用?
classmethod,staticmethod,property都是装饰器, 他们都作用在类的方法上。
classmethod:使得被装饰的方法成为一个类方法既不需要实例化类就可以直接调用的方法,第一个参数为cls。
staticmethod: 使得被装饰的方法成为一个静态函数既与普通的函数无区别。
property: 将一个方法变成一个属性来使用。
13.python中的绑定方法和未绑定方法是什么
绑定方法:绑定了实例化的方法既第一个参数是self
未绑定方法:没有绑定实例化的方法既类方法、静态方法
14.python上下文管理器是什么?
Python中上下文管理器使用with来调用主要用于数据库连接,文件操作, 网络操作。
其作用是: 如果在进行一些打开资源操作时出现了异常,上下文管理器将会自动的执行一些资源清理操作。在进入上下文管理器时, Python会先调用对象的__enter__方法, 该方法返回一个对象用于进行一些操作,如果在进行一些操作时发生了异常Python则调用__exit__该对象接受三个参数第一个参数异常类,第二个参数异常提示字符串, 第三个参数traceback对象。
15.functools的wraps是做什么的?
wraps是一个装饰器功能是: 由于被装饰的函数传入到装饰器中时已经不是原函数了, 而是一个新的函数, 并且丢失一些原函数的属性, 为了不影响函数的使用, 可以使用wraps来抵消这种副作用。
16.请说一说ORM实现原理
ORM使用了Python的属性描述符协议实现,通过另外一个类来描述类变量的属性类型, 再给这个属性进行赋值时(对应数据库中的字段名称)会调用__set__方法,访问属性则会调用__get__方法删除则调用__delete__方法。
17.请说一说迭代器和生成器区别?
生成器时一种特殊的迭代器, 生成器自动实现了迭代器协议, 不需要手动的实现__iter__以及next方法,生成器在迭代的过程中可以改变当前的迭代值, 而普通的迭代器改变当前值时往往会发生错。迭代器必须实现__iter__以及next方法。
18.描述一下type()的作用
当type只传入一个参数时将返回该参数的类型,如果传入了三个参数则返回一个类对象,同时Python中的所有类的基类都是type
19.Python中列表与元组的异同?
相同: 列表和元组都是容器并且是可迭代对象,二者可以包含任意类型的对象。
不同:列表是可变的, 元组是不可变。
20.Python中的列表是如何实现的?
Python中的列表使用了分离式技术实现的动态顺序表。
21.Python中列表的索引查询的时间复杂度是多少?
O(1)
22.Python字典的实现原理?
Python的字典使用了哈希表来储存key、value,当添加一个数据时首先会把key通过哈希函数转换成一个数字, 然后将该数字对存放value的数组长度取余并将取余结果当做数组的下标, 将value存放在该取余结果为下标的数组中。数据查询时将key转换为对应的数组下标,并定位到数组的位置获取value。
23.什么是pickling和unpickling?
Pickle模块读入任何Python对象,将它们转换成字符串,然后使用dump函数将其转储到一个文件中——这个过程叫做pickling,反之从存储的字符串文件中提取原始Python对象的过程,叫做unpickling。
24.有哪些工具可以帮助debug或做静态分析?
PyChecker是一个静态分析工具,它不仅能报告源代码中的错误,并且会报告错误类型和复杂度。
Pylint是检验模块是否达到代码标准的另一个工具。
dis用来查看Python对象的字节码。
25.Python中的作用域?
在Python中,一个对象的作用于总是由代码被赋值的地方所决定的。当遇见一个变量时Python会按照: 本地作用域→ 当前作用域被嵌入的本地作用域→ 全局/模块作用域→ 内置作用域顺序搜索。
26.Python的参数传递是值传递还是引用传递?
可变对象使用引用传递, 不可变对象使用值传递
27.写一个函数, 输入一个字符串, 返回倒序排列的结果
def reverse(text):
return text[::-1]
28.python中is和==的区别
is比较的是对象在内存的地址, ==比较的对象中的值
29.什么是Python的闭包?
内层函数引用了其外部作用域的变量,然后返回内层函数的情况,称为闭包,创建一个闭包必须满足以下几点:
\1. 必须有一个内嵌函数
\2. 内嵌函数必须引用外部函数中的变量,外层空间中被引用的变量叫做层函数的环境变量
\3. 外部函数的返回值必须是内嵌函数
\4. 环境变量和内层非全局函数一起构成了闭包
30. Python的自省?
type(),dir(),getattr(),hasattr(),isinstance()
31.Python并发的解决方案
Twisted是一个事件驱动型的网络引擎,不同于单线程和多线程模式,这种模式不需要过多去关心线程锁的问题,当遇到高并发问题时候,采用twisted会很好解决数据共享的问题。
Tornado既是一个web server,也是web framework。就是说这个web框架有自己内置的web server,在写web时候可以用到它的高性能网络库,甚至有公司拿这个来做游戏的服务器,可以用它处理高并发问题。
Gevent是基于协程的Python网络库,基于libev的快速事件循环,基于greenlet的轻量级执行单元,API的概念和Python标准库一致。
sanic基于uvloop和httptools实现高并发异步网络框架
1.进程的有哪几种状态以及导致转换的事件。
进程有5种状态:
运行态:该进程正在执行。
就绪态:进程已经做好了准备,只要有机会就开始执行。
阻塞态(等待态):进程在某些事情发生前不能执行,等待阻塞进程的事件完成。
新建态:刚刚创建的进程,操作系统还没有把它加入到可执行进程组中,通常是进程控制块已经创建但是还没有加载到内存中的进程。
退出态:操作系统从可执行进程组中释放出的进程,由于自身或某种原因停止运行。
导致转换的事件:
\1. 空->新建:创建执行一个程序的新进程,可能的事件有:新的批处理作业、交互登录(终端用户登录到系统)、操作系统因为提供一项服务而创建、由现有的进程派生等。
\2. 新建->就绪:操作系统准备好再接纳一个进程时,把一个进程从新建态转换为就绪态。
\3. 就绪->运行:需要选择一个新进程运行时,操作系统的调度器或分配器根据某种调度算法选择一个处于就绪态的进程。
\4. 运行->退出:导致进程终止的原因有:正常完成、超过时限、系统无法满足进程需要的内存空间、进程试图访问不允许访问的内存单元(越界)、算术错误(如除以0或存储大于硬件可以接纳的数字)、父进程终止(操作系统可能会自动终止该进程所有的后代进程)、父进程请求终止后代进程等。
\5. 运行->就绪:最常见的原因是,正在运行的进程到达了“允许不中断执行”的最大时间段,该把处理器的资源释放给其他在就绪态的进程使用了;还有一中原因可能是由于具有更改优先级的就绪态进程抢占了该进程的资源,使其被中断转换到就绪态。
6.运行->阻塞:如果进程请求它必须等待的某些事件,例如一个无法立即得到的资源(如I/O操作),只有在获得等待的资源后才能继续进程的执行,则进入等待态(阻塞态)。
7.阻塞->就绪:当等待的事件发生时,处于阻塞态的进程转换到就绪态。
8.就绪->退出:在上图中没有标出这种转换,在某些进程中,父进程可以在任何时刻终止一个子进程,如果一个父进程终止,所有相关的子进程都被终止。
9.阻塞->退出:跟上一项原因类似。
2.进程与线程的区别。
进程是资源分配的最小单位,线程是程序执行的最小单位。
进程有自己的独立的地址空间, 线程共享进程中的数据,使用相同的地址空间。
进程自己通信方式主要使用特别的方式来进行通信。线程之间的通信非常的方便, 同一进程下的线程共享全局变量、静态变量等数据。
多进程程序更加的健壮,其中一个进程死掉了并不影响其他的进程,多线程中只要有一个线程死掉,那么整个进程也死掉了。
3.进程通信的几种方式。
进程之间进行通信常用的有几种方式:管道,消息队列, 信号量, 共享内存
管道通常指无名管道, 他的特点包括:
1.半双工:数据只能在一个方向流动,一端为读端,一端为写端
2.有关系进程通信: 管道只能在具有亲缘关系的进程之间进行通信,如父子进程、兄弟进程
3.文件: 管道是一种特殊的文件它有着像普通文件读写一样的API, 它只存在于内存中。
Python实现:
import os
from time import sleep
def child(wpipe):
while 1:
msg = "hello world!".encode()
os.write(wpipe, msg)
sleep(2)
def parent():
rpipe, wpipe = os.pipe()
pid = os.fork()
if pid == 0:
child(wpipe)
else:
os.close(wpipe)
fb = os.fdopen(rpipe, 'r')
while 1:
recv = os.read(rpipe, 1024)
print(recv.decode())
parent()
# 输出
"""
>>> python3.6 ./pipe.py
hello world!
hello world!
hello world!
hello world!
hello world!
hello world!
hello world!
hello world!
hello world!
hello world!
"""
消息队列存放在内核中, 一个消息队列有一个标识符来标识, 它的特点:
1.消息队列是面向记录的, 其中消息具有特定的格式和特点的优先级
2.消息队列独立于发送方和接受方,即使进程终止,消息队列中的消息并不会被删除。所以它可以用于无关进程之间通信
3.消息队列可以对消息实现随机读取, 不需要按在特定的顺序来读取。信号量属于系统层面, linux系统也是通过信号量来管理进程,进程一旦接收到信号就会打断原来的程序执行流程来处理信号。
import os
import signal
def handler(signalnum, frame):
global receive_times
print("收到信号", signalnum, frame)
def main():
print(os.getpid())
signal.signal(signal.SIGTERM, handler)
while True:
pass
if __name__ == '__main__':
main()
运行上面程序, 在另一个终端输入 kill pid,程序将会打印
…收到信号 15
共享内存是最简单的通信方式, 他允许多个进程(无关进程, 有关进程)访问同一片内存, 一个进程改变其中的数据后, 其他的进程也能看见数据的变化。共享内存特点:
1.进程共享同一块内存
\2. 访问共享内存和访问私有内存一样快
3.不需要系统调用和内核入口
4.不造成不必要的内存复制
Python可以使用multiprocessing中Value、Array、Manager等等实现
4.线程同步几种方式
线程同步通常有4中方式: 临界区、事件、互斥量、信号量。
临界区:拥有临界区的线程可以访问被保护起来的资源或者代码段, 其他线程如果想访问则被挂起, 直到拥有临界区对象放弃临界区为止。Python中使用:
threading.Lock()
实现。事件:可以自定义一个事件, 如果这个事件一直不发生, 则这些线程将会阻塞, 直到事件发生。 Python中使用
threading.Event()
实现 。互斥量:互斥量为资源引入了状态:锁定/非锁定, 某个线程要更改共享数据时, 先将其锁定, 此时其他线程不能对该资源进行操作, 直到资源被释放。Python中使用
threading.Lock()
实现 。
5.用户线程与内核线程的区别
用户线程的优点:
1.线程切换不需要内核态特权, 进程不需要为了线程管理而切换到内核态。
\2. 可以为应用程序量身定做调度算法而不影响系统调度程序。
3.用户级线程可以再多个平台上运行, 不需要对内核进行修改以支持用户级线程。
用户线程的缺点:
1.当一个用户级线程执行一个系统调用时, 不仅这个线程会被阻塞, 进程中的所有线程都会被阻塞。
2.在用户级线程策略中, 一个多线程应用程序不能利用多处理技术。
内核级线程优点:
1.线程切换由内核控制,可以很好的利用多核CPU。
2.由操作系统内核创建和撤销, 一个内核级线程阻塞并不影响其他的线程运行。
内核级线程缺点:
1.由内核进行调度。不能跨平台。
用户级线程和内核级线程的区别:
1.内核线程是内核可感知的, 用户级线程是内核不可感知的。
2.用户级线程创建,撤销等等不需要内核的支持, 内核级线程创建,撤销等等都需要内核的支持。
3.用户级线程在调用系统指令是会导致其所属的进程被中断, 内核级线程在调用系统指令时, 只会导致该线程被中断, 与其他线程无关。
4.用户级线程CPU调度以进程为单位, 用户程序进行线程的控制, 内核级线程CPU以线程为调度单位, 由系统的线程调度程序负责线程的调度工作。
5.用户级线程的程序实体运行在用户态下程序, 而内核级线程的程序则可以运行在任何状态上。
6.进程池、线程池的原理?
线程池: 开启一定数量的线程并让其睡眠, 当需要一个线程去执行某种任务时, 唤醒某个线程让它执行任务, 任务执行完毕又让其睡眠。
进程池同理
7.进程为什么会产生死锁?
导致死锁的原因:
1.因为系统资源不足
2.进程运行推进顺序不合适
3.资源分配不当
导致死锁的四个必要条件:
1.一次一个进程只能访问一个资源, 其他进程不能访问已分配的资源。
2.当一个进程等待其他进程时, 继续占有已分配的资源时
3.不能强行抢占进程已有的资源
4.存在一个封闭的进程链, 导致每一个进程都占有下一个进程所需的资源
8.操作系统的四个特性?
1.并行: 并行是指两个事件以上(包含)在同一时刻发生既物理上这些事件是同时发生的。
2.共享: 系统中的资源可供内存中的多个进程共同使用, 由于资源的属性不同, 多个进程对资源共享方式也不同。
3.虚拟:操作系统中的虚拟通过分时技术将多个物理设备转换成若干个逻辑上的对应物。
4.异步:在多道程序设计环境下允许多个进程并发执行。
9.什么是缓冲区溢出?有什么危害?其原因是什么?
缓存区溢出指计算机在向缓存区填充数据时超过了缓存区的最大值, 溢出的数据覆盖在了合法数据上。
其危害: 程序崩溃, 导致拒绝服务。跳转并执行恶意代码。
造成缓存区溢出的原因主要是没有对用户的输入进行检查。
10.操作系统中进程调度策略有哪几种?
优先级服务,时间片轮换, 多级反馈
1.TCP为什么需要3次握手
三次握手的目的是:防止已失效的连接请求报文又传入到服务端,导致错误。
2.TCP和UDP有什么区别?
tcp是传输控制协议,其提供面向连接、可靠的字节流服务,通信双方必须依照三次握手协议连接之后才能传输数据, tcp提供了超时重传、 丢弃重复数据、检验数据流量控制等功能。
UDP是用户数据包协议, 它提供了一个简单的不可靠的面向无连接的服务,在双方未连接时也能传输数据因而速度特别快。
3.TCP/IP的流量控制?
利用滑动窗口实现流量控制
4.HTTP的长连接和短连接?
短连接: 客户端与服务端每进行一次HTTP操作就建立一次连接,请求结束就断开连接。
长连接:客户端与服务器进行第一次HTTP操作后, TCP连接并不会断开连接, 下次请求将复用这条TCP通道
http://5.IO中同步与异步,阻塞与非阻塞区别
同步和异步关注的是消息通信机制。
同步:发出一个调用时, 在没有得到结果之前这个调用不会返回结果, 如果调用返回那么说明得到结果了。
异步:发出一个调用后立刻返回, 但是返回时没有结果的。
阻塞与非阻塞关注的是程序在等待调用的结果
阻塞:调用结果被返回前该线程被挂起, 直到得到结果后,该线程继续运行。
非阻塞:不能立刻得到结果之前, 该函数不会阻塞当前线程, 会立刻返回。
6.Cookies 和 Session的区别
cookies是一种保存在客户端上的字符串用于用户与服务端会话持久的保持数据
Session是一种保存在服务器的字符串, 其功能与cookies相同, 但是session是在cookies基础上实现的。
7.什么是TCP粘包、TCP粘包发生了怎么处理?
TCP粘包是指发送方发送了若干个包到接收方接受时都粘成了一个包, 从缓存区来看后一个包的头部数据紧紧的接着前一个包的尾部。
对于TCP粘包的情况有两种处理方式:
\1. 接收方: 可以选择关闭tcp默认的nagle算法来避免粘包
2.应用层处理: 格式化数据, 对于每一条数据都采用相同的格式必须有开始符以及结束符, 这样即使发生粘包也可以通过开始符和结束符判断数据边界, 也可以在数据开头就将该条数据的长度填充进数据中, 如果发生粘包则可以使用数据长度来区分每一条数据。
UDP不会发生粘包, 因为UDP没有使用块的合并优化算法,导致接收端的缓存区内按照链式的结构来储存每一个UDP包, 并且每一个UDP包都有消息头,这样接收方就很好的进行拆包。
8.TCP中的time_wait是什么情况?出现过多的close_wait可能是什么原因?
timewait值tcp中主动断开连接一方的一个状态, 当主动断开连接的一方发送给对方FIN包,且对方回复了ACK+FIN时, 主动断开连接的一方将进入time_wait状态, 并持续到2msl后进入CLOSE状态。
出现过多的close_wait的原因:被动关闭方未关闭socket造成。
解决办法:
1.为socket设置超时
2.调整系统参数, 包括句柄参数和TCP/IP参数
9.epoll,select的区别?边缘触发,水平触发区别?
epoll将每一个监听事件都储存在了红黑树中并且只返回被触发的事件。epoll在睡眠结束后只需要检测就绪链表是否为空。
select则将时间都放入一个列表中, 当其中某个事件被触发时,select将所有的事件返回给用户。select睡眠结束后需要遍所有的监听事件。
10. tcp三次握手, 四次挥手
三次握手:
客户端 服务端
->SYN=1, seq=x
<-ACK=1, ack=x+1, seq=y, SYN=1
-> ACK=1, ack=y+1, seq=x+1
<-> data
四次挥手:
主动关闭方 被动关闭方
<-> data
->FIN=1, seq=x
<- ACK=1, seq=y, ack=x+1
<- FIN=1, ACK=1, seq=z, ack=x+1
-> ACK=1, ack=z+1, seq=x+1
1.数据库事务的四个特性及含义
数据库事务的4个特性:原子性、持久性、一致性、隔离性
原子性:整个事务中的所有操作要么全部完成, 要么全部都不完成, 如果在事务中操作出现异常,那么事务将会进行回滚, 就像这个事务从来没有执行过一样。
持久性:在事务完成后,该事务所有的操作都将持久化在数据库中, 不会被回滚。
一致性:在事务开始之前和事务结束之后, 数据库的完整性约束并没有被破坏。
隔离性:确保在同一时间类只有一个事务处理某个数据。
2.数据库索引使用了什么数据结构?
数据库索引对于非主键索引使用B树, 对于主键索引使用B+树
3.数据库优化的思路
SQL语句优化:
\1. 尽量避免在where语句后面使用 !=、<>操作符以及对NULL值得判断, 否则引擎将放弃索引而使用全表扫描。
\2. 使用exists替换in。
\3. 尽量放弃使用select *, 需要什么数据就取出什么数据。
\4. 使用join代替子查询。
\5. 设置合适的字段属性:例如尽量把字段设置为NOT NULL, 这样引擎就不要对比NULL值
4.MySQL中myisam与innodb的区别
\1. innodb支持事物, myisam不支持事物
\2. innodb支持行级锁, myisam支持表级锁
\3. innodb支持MVC, myisam不支持
\4. innodb支持外键, myisam不支持
\5. innodb不支持全文索引,myisam支持
5.Redis支持的数据类型
字符串,集合, 有序集合,哈希, 列表
6.redis持久化的几种方式
1. 快照: 默认使用这种方式,将数据快照存放在特定的二进制文件中。
2. AOF: 将每一条命令都储存, 恢复时再将每一天命令进行运行。
7. redis如何实现热数据缓存?
当redis的内存数据大小上升到一定大小时, 就会实施数据淘汰策略, redis提供了6中数据淘汰策略
volatile-LRU:从已经设置过期时间的数据中挑选最近最少使用的数据淘汰
volatile-TTL: 从已经设置过期时间的数据中挑选即将要过期的数据淘汰
volatile-RANDOM: 从已经设置过期时间的数据中随机选择数据进行淘汰
allkeys-LRU:从数据集中挑选最近最少使用的数据淘汰
allkeys-random:从数据集中任意选择数据淘汰
no-enviction:禁止驱逐数据
8.Redis 常见的性能问题都有哪些?
\1. master写内存快照, save命令调度rdbSave函数会阻塞主线程的工作, 可能会导致间断性的暂停服务。
\2. master AOF持久化, 最好不要使用AOF来进行持久化, 这个持久化方式对性能有着极大的影响。
\3. redis主从复制的性能问题,为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内。
9.mysql字符集和排序规则?
mysql中一个字符集至少有一个或者多个排序方式, 比如utf8就有:utf8_general_ci , utf8_general_cs等等。
排序规则命名规则:字符集名字_语言_后缀, 其中
\1. _ci:不区分大小写的排序方式
\2. _cs:区分大小写的排序方式
\3. _bin:二进制排序方式,大小比较将根据字符编码,不涉及人类语言,因此_bin的排序方式不包含人类语言
字符集最常用的包括utf8, utf8md4。
10.varchar与char的区别是什么?大小限制?utf8字符集下varchar最多能存多少个字符?
char和varchar最大的不同就是一个是固定长度,一个是可变长度。由于是可变长度,因此存储的是实际字符串再加上一个记录字符串长度的字节。如果分配给char或varchar列的值超过 列的最大长度,则对值进行裁剪。
varchar(M)和char(M),M都表示字符数.varchar的最大长度为65535个字节,不同的编码所对应的最大可存储的字符数不同。char最多可以存放255个字符,不同的编码最大可用字节数不同。
字符类型若为utf8,每个字符最多占3个字节,varchar最大长度不能超过21845。
11.primary key和unique的区别?
一个表只能有一个primary key, 一个表可以有多个unique key。
unique key约束只针对非主键列, 可以为空值, primary key约束针对主键列, 不允许有空值。
12.外键有什么用,是否该用外键?外键一定需要索引吗?
外键是为了一张表记录的数据不会太过冗余,也是为了数据的一致性和完整性。
如果业务逻辑相当的复杂那么建议使用外键来保证数据的一致性和完整性, 如果业务逻辑不复杂则可以不使用外键, 仅靠程序中来保证数据的一致性和完整性, 或者业务对数据的一致性完整性要求相当的高, 那么一定要用外键。同时如果为了不让mysql在性能有任何的形象应该避免使用外键。 所有应该视当前业务,数据等情况决定是否使用外键。
外键需要索引, 因为外键在查询,更新,删除数据时会对数据进行查找, 所以需要对外键建立索引。
13.索引有什么用?
对于建立索引的列, mysql的查询效率会提高很多。
14.谈谈redis的事务?用事务模拟原子+1操作?原子操作还有其它解决方案吗?
redis的事务使用关键字multi开启事务, 使用exec执行事务中的语句,它可以执行多条语句, 所有的命令按照先进先运行的的运行, 不会被其他的命令加塞。
用事务模拟原子+1操作:
multi
incr xx
exec
原子操作 可以使用 incr操作实现