2020年10月笔记
1.请说明目前PHP最新版本的版本号和新特性
2.简要说明PHP的垃圾回收机制
垃圾回收机制是一种动态存储分配方案.它会自动释放程序已分配的不在需要的内存块.自动回收内存的过程叫垃圾收集.
在PHP中没有任何变量指向这个对象时,这个对象就变为垃圾.PHP会将其在内存中销毁,这是PHP的垃圾回收机制,防止内存溢出.
3.列举熟悉的PHP框架,并说出该框架的特点
4.常见的状态码,说明其含义
5.解释:脏读,幻读,不可重复读
脏读:脏读是指一个事务中访问到了另一个事务未提交的数据.
幻读:一个事务读取2次,得到的记录条数不一致,由于2次读取之间另外一个事务对数据进行了增删.
不可重复读:一个事务读取同一条记录2次,得到的结果不一致,由于2次读取之间另外一个事务对此行数据进行了修改.
补充:
数据库事务的特点:ACID
原子性(A Atomicity):事务是一个原子性的操作单元,事务里面对数据库的操作,要么都执行,要么都不执行.
一致性(C Consistent):在事务开始之前和结束之后,数据都必须保持一致状态,必须保证数据库的完整性.也就是说,数据必须符合数据库的规则.
隔离性(I ioslation):数据库允许多个并发事务同时对数据进行操作,事务之间是相互独立的,事务处理的中间状态对其他事务是不可见的,以此防止出现数据不一致状态.
MySQL中4个事务隔离级别,隔离级别由低到高:隔离级别越高,越能保证数据的完整性和一致性,但对并发性能影响也越大.
读未提交(Read uncommitted),读已提交(Read committed),可重复读(Repeatable read),可串行化(serializable)
使用
select @@tx_isolation;
可以查看 MySQL 默认的事务隔离级别。不同的事务隔离级别会导致不同的问题:
持久性(D Durable):一个事务结束后,其对数据库的修改是永久性的,即使系统故障也不会丢失.
6.详细说明rsync命令和实际应用
rsync是开源的,快速,多功能的,可实现全量及增量的本地或远程数据同步工具,适用于linux,unix,window等多种操作系统平台.可以当做文件复制工具,替代mv和cp.
常用命令:
rsync -av source destination //除了可以递归同步以外,还可以同步元信息(比如修改时间、权限等), 目标目录destination如果不存在,rsync 会自动创建。执行上面的命令后, 源目录source被完整地复制到了目标目录destination下面,即形成了destination/source的目录结构。 如果只想同步源目录source里面的内容到目标目录destination,则需要在源目录后面加上斜杠。 $ rsync -a source/ destination 上面命令执行后,source目录里面的内容,就都被复制到了destination目录里面, 并不会在destination下面创建一个source子目录。 rsync 除了支持本地两个目录之间的同步,也支持远程同步。它可以将本地内容,同步到远程服务器。 $ rsync -av source/ username@remote_host:destination 也可以将远程内容同步到本地。 $ rsync -av username@remote_host:source/ destination
参考:rsync 用法教程
1)可使本地和远程两台主机之间的数据快速复制同步镜像,远程备份的功能,这个功能类似ssh带scp命令,但又优于scp命令的功能,scp每次都是全量拷贝,而rsync可以增量拷贝。
2)rsync还可以在本地主机的不同分区或目录之间全量及增量的复制数据,
3)利用rsync还可以实现删除文件和目录的功能。相当于rm
4)rsync相当于scp,cp.rm但是还优于他们每一个命令。
数据备份的方式
- 全量备份 --- 会将所有的数据进行备份,效率比较低下
- 增量备份 --- 只是将变动的数据进行备份,效率比较高,并且适合进行异地备份
rsync -avzP -e 'ssh -i /home/vagrant/.ssh/new*vidat.pem' test2 centos@18.*.*.34:/home/wwwroot/default/test //远程拷贝文件,相当于scp
7.说明app与服务器之间通信的安全机制
- 防非法调用——身份认证
- 防抓包——数据加密
- 防重放攻击——时间戳+随机字符串
- 防篡改——签名机制
- HTTPS协议进行通信
Token身份验证机制 : 防止恶意刷接口,可以反查调用者信息,封账号或token失效
对称加密:
对称加密:对称加密是一种可逆的加密算法,其中“对称”的意思是加密过程和解密过程使用的是同一个密钥,常见的对称加密算法有DES、3DES、AES、IDEA等。
对称加密算法的特点
对称加密算法的特点是算法公开、计算量小、加密速度快、加密效率高。对称加密算法的安全性依赖于密钥,任何人只要拿到密钥就能对数据进行加解密操作。
由于参与通信的双方都需要持有密钥,任何一方的秘钥泄露,那么双方的通信将无安全性可言,所以怎么安全的保存和传递密钥是使用对称加密最需要关注的问题。
非对称加密:
非对称加密指的是加密过程和解密过程使用不同的密钥,非对称加密算法需要一对密钥(公钥和私钥),公钥用来加密数据、私钥用来解密数据。
常见的非对称加密算法有RSA、ECC、ElGamal等。
非对称加密算法特点
非对称加密算法使用公钥加密、私钥解密,私钥不需要公开传输所以安全性较高。同时私钥可以对数据进行签名、公钥可以用来验证签名,可以解决中间人攻击和信息被篡改的问题。
由于加解密过程使用不同的密钥,所以对大量数据进行加解密运算的话速度是比较慢的,通常情况下非对称加密算法只适合对少量数据进行加解密操作。
对称加密算法运算速度快但安全性不足、非对称加密算法安全性高但运算速度慢.那我们可以将两者结合一下:用对称加密算法加解密数据这样可以保证运算速度,用非对称加密算法加密对称加密算法的密钥这样可以兼顾密钥的安全性。
防重放攻击:
防重放攻击:拦截到请求之后只需再原样发送该请求到服务端就可以发起重放攻击,如果接口内有一些查库之类的比较耗性能的逻辑,那么在短时间内发起大量重放攻击的话将会直接导致服务端崩溃。
我们只需要保证请求只能被正确处理一次即可,这里我们采用时间戳+随机字符串的解决方案
在请求中加入时间戳与随机字符串之后,服务端收到请求后会首先对时间戳和随机字符串进行校验,校验通过才会执行正常的业务处理逻辑。
参考: 如何保证APP与服务端通信安全
8.svn和git区别,列举常用的git命令,重点说明git中merge和rebase的区别
9.PHP写出快速排序的算法
(1)快速排序算法是对冒泡算法的一个优化。他的思想是先对数组进行分割, 把大的元素数值放到一个临时数组里,把小的元素数值放到另一个临时数组里(这个分割的点可以是数组中的任意一个元素值,一般用第一个元素,即$array[0]),然后继续把这两个临时数组重复上面拆分,最后把小的数组元素和大的数组元素合并起来。这里用到了递归的思想。
//快速排序
function quickSort($arr)
{
if (!isset($arr[1])) {
return $arr;
}
$mid = $arr[0];
$leftArr = [];
$rightArr = [];
foreach ($arr as $value) {
if ($value > $mid) {
$rightArr[] = $value;
}
if ($value < $mid) {
$leftArr[] = $value;
}
}
$leftArr = quickSort($leftArr);
$leftArr[] = $mid;
$rightArr = quickSort($rightArr);
return array_merge($leftArr, $rightArr);
}
$arr = [2, 4, 88, 33, 44, 5];
print_r(quickSort($arr));
//结果:Array ( [0] => 2 [1] => 4 [2] => 5 [3] => 33 [4] => 44 [5] => 88 )
//冒泡排序(不使用第三变量)
function bubbleSort($arr)
{
for ($i = 0, $c = count($arr); $i < $c; $i++) {
for ($j = 0; $j < $c - 1; $j++) {
if ($arr[$j + 1] > $arr[$j]) {
list($arr[$j + 1], $arr[$j]) = array($arr[$j], $arr[$j + 1]); //不是第三个变量交换数组中的两个值
}
}
}
return $arr;
}
$arr = [2, 4, 88, 33, 44, 5];
var_dump(bubbleSort($arr));
//冒泡排序(使用第三变量)
function bubbleSort2($arr)
{
$len = count($arr);
for ($i = 0; $i < $len; $i++) {
for ($j = 0; $j < $len - 1; $j++) {
if ($arr[$j + 1] < $arr[$j]) {
$tmp = $arr[$j + 1];
$arr[$j + 1] = $arr[$j];
$arr[$j] = $tmp;
}
}
}
return $arr;
}
$arr = [2, 40, 6, 73, 88, 33, 44, 5];
var_dump(bubbleSort2($arr));
10.用PHP写一个算法判断一个整数是否是回文数,考虑CPU和内存使用率最低
11.用装饰器模式写出具有房产销售功能的简单代码
12.设计高并发场景下的CRM软硬件架构
13.curl 抓取页面如何知道是否
===补充笔记 20201103===受到打击要奋起直追啦====
1. mysql数据库主从复制原理?主从延迟如何解决?
2.说说你了解的常见的消息队列及优缺点运用场景?
3.go语言中那种数据类型是值传递,那种是地址传递?map slice 数组
4.redis set 设置完数据后进程挂掉了,如何给这个key设置有效期
5.docker原理是什么?镜像,容器创建方法?
6.mysql如何实现读锁? 写锁? 事务隔离级别? 脏读,幻读,不可重复读解决方案
7.超卖问题?秒杀问题?商户出现负数
8.composer 怎么引入一个项目? 怎么引入一个包?psr4
Composer 是一个用于 PHP 依赖管理的工具。它实现了让你声明项目所依赖的库,并帮你完成安装 / 更新过程。
Composer 要求 PHP 版本在 5.3.2 以上才能运行。还需要对 PHP 做一些设置和编译标志,在安装时会收到所有的不兼容警告。Composer 是多平台的,可以在 Windows,Linux 和 OSX 上良好运行。
简单解释#
composer install - 如有 composer.lock 文件,直接安装,否则从 composer.json 安装最新扩展包和依赖;
composer update - 从 composer.json 安装最新扩展包和依赖;
composer update vendor/package - 从 composer.json 或者对应包的配置,并更新到最新;
composer require new/package - 添加安装 new/package, 可以指定版本,如: composer require new/package ~2.5.
(1)引入完整的项目
composer create-project topthink/think think 5.1.*
对这个命令详细说一下,分为四部分讲解
第一部分就是composer create-project,告诉composer我们要创建项目;
第二部分topthink/think是包名,这个包名是在packagist.org网站可以搜索的到的,如果找不到也创建不了项目,composer会报错;
第三部分think, 这个是给创建的项目取一个名字,其实也就是一个目录名字,这个目录如果在的话,目录一定要为空,不然创建项目会失败,如果目录不存在会自动创建,目录起英文名字,中文会遇到一些不可描述的问题
第四部分,创建的项目的版本,因为我们创建的项目来自于packagist库中的包,包有不同的版本,以我创建的topthink\think为例就有5.1.*、5.0.*,如果我们不指定版本号,默认会使用新的版本来创建,当然也可以使用指定的版本5.1.38。这里也可以使用通配符5.1.*,赋值运算符~5.1等等
更多内容参考:使用composer create-project
(2) 引入一个包进入到vendor
关于扩展包的安装方法
那么,准备添加一个扩展包,install, update, require 三个命令都可以用来安装扩展包,选择哪一个才是正确的呢?答案是:使用 composer require 命令
另外,在手动修改 composer.json 添加扩展包后,composer update new/package 进行指定扩展包更新的方式,也可以正确的安装,不过不建议使用这种方法,因为,一旦你忘记敲定后面的扩展包名,就会进入万劫不复的状态,别给自己留坑呀。
上面的概念不论对新手或者老手来说,都比较混淆,主要记住这个概念:
原有项目新添加扩展的,都使用 composer require new/package 这种方式来安装。
具体参考:正确的 Composer 扩展包安装方法
(3)composer 包版本的范围指定
名称 | 实例 | 说明 |
---|---|---|
不指定版本 | 根据当前Path环境变量中的php版本下载最合适的最新版 | |
确切的版本 | 6.0.1 | 指定下载的具体版本号 |
范围 > < != | > 6.0,< 6.0 | 指定版本范围,自动下载该范围中的最新版 |
通配符 * | 5.*,6.0.* | 5.* 代表版本范围 [5, 6.0) 6.0.* 代表版本范围 [6.0, 6.1) |
赋值运算符(最低版本) ~ | 1.2,6.1.0 | ~1.2 代表版本范围 [1.2, 2.0) ~6.1.0 代表版本范围 [6.1.0, 6.2) |
脱字号版本(最低版本) ^ | ^1.2.3 | ^1.2.3 代表版本范围 [1.2.3, 2.0.0) |
版本约束使用示例
:
和=
都可以- 版本约束可以加引号,也可以不加
- composer文档使用的是
:
并且版本约束加引号(可以说更加规范吧)
composer create-project topthink/think:"5.1.*"
composer create-project topthink/think=5.1.*
(4)composer.json中require-dev和require的区别
- 1.composer.json文件中的require和require-dev中存放的均是package
- 2.两者的区别在于require中所引用的包在线上线下的项目中均会使用,require-dev中的包只在本地开发的时候使用。
当只要引入require中的依赖时候执行
composer install --no-dev
二者都要引入时这不需要 --no-dev。
另外:require-dev和require、autoload-dev和autoload使用方式一致,用途不同
require列出的软件包列表必须安装,都为正式部署所需要;
require-dev列出的软件包一般用于开发或测试,是额外列出的依赖;
执行composer install/update命令时用--no-dev参数跳过require-dev列出的软件包;
autoload自动加载映射,正式部署使用;
autoload-dev自动加载映射,一般多用于测试和开发;
执行composer dump-autoload命令式可通过--no-dev参数来忽略autoload-dev指定的命名空间;
=================20201120持续更新==================
数据库面试题总结:
1.数据库的三范式:
一范式就是属性不可分割,
二范式就是要有主键,其他字段都依赖于主键,
三范式就是要消除传递依赖,消除冗余,就是各种信息只在一个地方存储,不出现在多张表中
2.数据库死锁
当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都进入无限等待的状态,称为死锁。这里我用数据库中的行锁举个例子。
这时候,事务A在等待事务B释放id=2的行锁,而事务B在等待事务A释放id=1的行锁。 事务A和事务B在互相等待对方的资源释放,就是进入了死锁状态。
3.查看当前正在等待的锁
等行锁
现在,经过了表级锁的考验,我们的select 语句终于来到引擎里了。
mysql> select * from t where id=1 lock in share mode;
上面这条语句的用法你也很熟悉了,我们在第8篇《事务到底是隔离的还是不隔离的?》文章介绍当前读时提到过。
由于访问id=1这个记录时要加读锁,如果这时候已经有一个事务在这行记录上持有一个写锁,我们的select语句就会被堵住。
复现步骤和现场如下:
图 8 行锁复现
图 9 行锁show processlist 现场
显然,session A启动了事务,占有写锁,还不提交,是导致session B被堵住的原因。
这个问题并不难分析,但问题是怎么查出是谁占着这个写锁。如果你用的是MySQL 5.7版本,可以通过sys.innodb_lock_waits 表查到。
查询方法是:
select * from sys.innodb_lock_waits where locked_table='`lxw_db`.`t`'\G
#lxw_db 数据库名
#t 表明
可以看到,这个信息很全,4号线程是造成堵塞的罪魁祸首。而干掉这个罪魁祸首的方式,就是KILL QUERY 4或KILL 4。
不过,这里不应该显示“KILL QUERY 4”。这个命令表示停止4号线程当前正在执行的语句,而这个方法其实是没有用的。因为占有行锁的是update语句,这个语句已经是之前执行完成了的,现在执行KILL QUERY,无法让这个事务去掉id=1上的行锁。
实际上,KILL 4才有效,也就是说直接断开这个连接。这里隐含的一个逻辑就是,连接被断开的时候,会自动回滚这个连接里面正在执行的线程,也就释放了id=1上的行锁。
4.回表(04讲深入浅出索引(上))
图4 InnoDB的索引组织结构
从图中不难看出,根据叶子节点的内容,索引类型分为主键索引和非主键索引。
主键索引的叶子节点存的是整行数据。在InnoDB里,主键索引也被称为聚簇索引(clustered index)。
非主键索引的叶子节点内容是主键的值。在InnoDB里,非主键索引也被称为二级索引(secondary index)。
根据上面的索引结构说明,我们来讨论一个问题:基于主键索引和普通索引的查询有什么区别?
- 如果语句是select * from T where ID=500,即主键查询方式,则只需要搜索ID这棵B+树;
- 如果语句是select * from T where k=5,即普通索引查询方式,则需要先搜索k索引树,得到ID的值为500,再到ID索引树搜索一次。这个过程称为回表。
1.索引的作用:提高数据查询效率
2.常见索引模型:哈希表、有序数组、搜索树
3.哈希表:键 - 值(key - value)。
4.哈希思路:把值放在数组里,用一个哈希函数把key换算成一个确定的位置,然后把value放在数组的这个位置
5.哈希冲突的处理办法:链表
6.哈希表适用场景:只有等值查询的场景
7.有序数组:按顺序存储。查询用二分法就可以快速查询,时间复杂度是:O(log(N))
8.有序数组查询效率高,更新效率低
9.有序数组的适用场景:静态存储引擎。
10.二叉搜索树:每个节点的左儿子小于父节点,父节点又小于右儿子
11.二叉搜索树:查询时间复杂度O(log(N)),更新时间复杂度O(log(N))
12.数据库存储大多不适用二叉树,因为树高过高,会适用N叉树
13.InnoDB中的索引模型:B+Tree
14.索引类型:主键索引、非主键索引
主键索引的叶子节点存的是整行的数据(聚簇索引),非主键索引的叶子节点内容是主键的值(二级索引)
15.主键索引和普通索引的区别:主键索引只要搜索ID这个B+Tree即可拿到数据。普通索引先搜索索引拿到主键值,再到主键索引树搜索一次(回表)
16.一个数据页满了,按照B+Tree算法,新增加一个数据页,叫做页分裂,会导致性能下降。空间利用率降低大概50%。当相邻的两个数据页利用率很低的时候会做数据页合并,合并的过程是分裂过程的逆过程。
17.从性能和存储空间方面考量,自增主键往往是更合理的选择。
【今日收获】
1. 主键索引的叶子结点存储了整一行的内容(聚簇索引),使用主键可以快速获取到整行的数据。
2. 非主键索引的叶子结点存储的是主键的值,所以主键字段占用空间不宜过大。同时,其查找数据的过程称为“回表”,需要先查找自己得到主键值,再在主键索引上边查找数据内容。
3. 索引的实现由存储引擎来决定,InnoDB使用B+树(N叉树,比如1200叉树),把整颗树的高度维持在很小的范围内,同时在内存里缓存前面若干层的节点,可以极大地降低访问磁盘的次数,提高读的效率。
4. B+树的插入可能会引起数据页的分裂,删除可能会引起数据页的合并,二者都是比较重的IO消耗,所以比较好的方式是顺序插入数据,这也是我们一般使用自增主键的原因之一。
5. 在Key-Value的场景下,只有一个索引且是唯一索引,则适合直接使用业务字段作为主键索引。
思考题:
如果删除,新建主键索引,会同时去修改普通索引对应的主键索引,性能消耗比较大。
删除重建普通索引貌似影响不大,不过要注意在业务低谷期操作,避免影响业务。
5. 请问没有主键的表,有一个普通索引。怎么回表?
作者回复
没有主键的表,innodb会给默认创建一个Rowid做主键
5.发现有mdl(元数据锁),直接kill query 锁语句id;
赞赏码
非学,无以致疑;非问,无以广识