【面试】 1.php面试(一)

学习方法与经验交流

img

记得我第一次面试PHP这个岗位的时候,哪个时候刚从学校出来混,不知道啥行情啊,又是零经验的(这里插一句,零经验的,如果你从来都没接触过开发一个完整的,或者半成品的项目,公司一般是不会要的,因为公司招你进去,是要你会帮忙做东西,实现公司的业务与业绩的提升的)。那个时候我就直接说试用期800元了,当然,好多年前的了哈!也是一个相当低的价位的,所以公司直接就要了!!!道理很简单,大家都懂的!

相关推荐:《2019年PHP面试题大汇总(收藏)

在公司里做项目,成长是一个过程,提升你自己的学习技能更是一个关键所在的。进入公司之前,你会有一两轮的面试与笔试,做我们这个行业的都是这样,所以除了口语表达能力(能吹)之外,还有一点就是实力能力的,这个也是你的面试题所要体现的。面试题的题型很多,但是都是离不开PHP基础的。一些刚出来的可能不懂试题的。告诉你一个方法,那个时候我真的用了!就是把所有题型都背下来了!方法很老套又不切合实际。但是很有用,因为常见的题型都遇到了~~可能是幸运吧!

可能学习各有各的方法!我以前就是那样子过来的!现在呢,还是要继续的学习与提升技能,活到老学到老!一旦进坑了,很难出来!

以下推荐一些面试常见的试题,希望对你有用!!

1、冒泡排序,面试前一定要记住哦!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function maopao($arr)
{
$len = count($arr);
$n = count($arr) - 1;
for ($i = 0; $i < $len; $i++) {
for ($j = 0; $j < $n; $j++) {
if ($arr[$j] > $arr[$j + 1]) {
$tmp = $arr[$j];
$arr[$j] = $arr[$j + 1];
$arr[$j + 1] = $tmp;
}
}
}
return $arr;
}

2、快速排序,面试前一定要记住哦!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function quick_sort($array) {
if (count($array) <= 1) return $array;
$key = $array[0];
$left_arr = array();
$right_arr = array();
for ($i=1; $i<count($array); $i++){
if ($array[$i] <= $key)
$left_arr[] = $array[$i];
else
$right_arr[] = $array[$i];
}
$left_arr = quick_sort($left_arr);
$right_arr = quick_sort($right_arr);
return array_merge($left_arr, array($key), $right_arr);
}

3、请说明 PHP 中传值与传引用的区别,什么时候传值什么时候传引用?

按值传递:函数范围内对值的任何改变在函数外部都会被忽略

按引用传递:函数范围内对值的任何改变在函数外部也能反映出这些修改

优缺点:按值传递时,php必须复制值。特别是对于大型的字符串和对象来说,这将会是一个代价很大的操作。按引用传递则不需要复制值,对于性能提高很有好处。(优缺点会考到)

4、MySQL数据库中的字段类型varchar和char的主要区别是什么?

Varchar是变长,节省存储空间,char是固定长度。查找效率要char型快,因为varchar是非定长,必须先查找长度,然后进行数据的提取,比char定长类型多了一个步骤,所以效率低一些。

5、MySQL数据库的常用存储引擎以及它们的区别?

MyISAM:不支持事务,表锁,易产生碎片,要经常优化,读写速度较快,支持全文索引。

InnoDB:支持事务,行锁,有崩溃恢复能力。读写速度比MyISAM慢,5.6之后支持全文索引。
存储引擎是基于表的,而不是数据库

(这道题还能更详细点就详细点)

6、对于大流量的网站,采用什么样的方法来解决访问量问题?

首先,确认服务器硬件是否足够支持当前的流量

其次,优化数据库访问。

第三,禁止外部的盗链。

第四,控制大文件的下载。

第五,使用不同主机分流主要流量

第六,使用流量分析统计软件

第七,尽量使用静态页,缓存

7、什么是面向对象?主要特征是什么?

面向对象是程序的一种设计方式,它利于提高程序的重用性,使程序结构更加清晰。主要特征:封装、继承、多态。

8、SESSION 与 COOKIE的区别是什么?这是重点

SESSION存储在服务器端,COOKIE保存在客户端。Session比较安全,cookie用某些手段可以修改,不安全。Session依赖于cookie进行传递。禁用cookie后,session还可以使用,在存储session的文件中,生成sessionID,通过get传参的方式将sessionID传到要实现session共享的页面,读取sessionID,从而从session中获取数据。

建议查找session与cookie这方面的详细教程

9、对缓存技术的了解?redis是个考点

1、缓存技术是将动态内容缓存到文件中,在一定时间内访问动态页面直接调用缓存文件,而不必重新访问数据库。

2、使用memcache可以做缓存。

10、表单中get和post提交方式的区别

get是显式的,数据从url中可以看到,传输的数据量小,安全性低;

post是隐式的,传送的数据量较大,安全性较高

11、优化数据库的方法

选取最适用的字段属性,尽可能减少定义字段宽度,尽量把字段设置NOTNULL

使用连接(JOIN)来代替子查询

适用联合(UNION)来代替手动创建的临时表

事务处理

锁定表、优化事务处理

使用外键,优化锁定表

使用索引

优化查询语句

12、语句include和require的区别是什么?语句include和require的区别是什么?

require是无条件包含,也就是如果一个流程里加入require,无论条件成立与否都会先执行require,当文件不存在或者无法打开的时候,会提示错误,并且会终止程序执行

include有返回值,而require没有(可能因为如此require的速度比include快),如果被包含的文件不存在的化,那么会提示一个错误,但是程序会继续执行下去

13、redis和memcacahe、mongoDB的区别?

都是非关系型数据库,性能都非常高,但是mongoDB和memcache、redis是不同的两种类型。后两者主要用于数据的缓存,前者主要用在查询和储存大数据方面,是最接近数据库的文档型的非关系数据库。

从数据存储位置上来分,memcache的数据存在内存中,而redis既可以存储在内存中,也可以存储的到磁盘中,达到持久化存储的功能,memcache一旦断电,数据全部丢失,redis可以利用快照和AOF把数据存到磁盘中,当恢复时又从磁盘中读取到内存中,当物理内存使用完毕后,可以把数据写入到磁盘中。

从存储数据的类型上来分,memcache和redis存储的方式都是键值对,只不过redis值的类型比较丰富,有string(字符串),hash(哈希),list(列表),set(集合)zset(有序集合),而memcache主要存储的是字符串。

14、PHP的基本变量类型

四种标量类型:boolean (布尔型)、integer (整型)、float (浮点型, 也称作 double)、string (字符串)

两种复合类型:array (数组)、object (对象)

最后是两种特殊类型:resource(资源)、NULL(NULL)

15、静态化如何实现的?伪静态如何实现?

1、 静态化指的是页面静态化,也即生成实实在在的静态文件,也即不需要查询数据库就可以直接从文件中获取数据,指的是真静态。
实现方式主要有两种:

一种是我们在添加信息入库的时候就生成的静态文件,也称为模板替换技术。

一种是用户在访问我们的页面时先判断是否有对应的缓存文件存在,如果存在就读缓存,不存在就读数据库,同时生成缓存文件。

2、伪静态不是真正意义上的静态化,之所以使用伪静态,主要是为了SEO推广,搜索引擎对动态的文件获取难度大,不利于网站的推广。实习原理是基于Apache或Nginx的rewrite机智
主要有两种方式:

一种是直接在配置虚拟机的位置配置伪静态,这个每次修改完成后需要重启web服务器。

另一种采用分布式的,可以在网站的根目录上创建.htaccess的文件,在里面配置相应的重写规则来实现伪静态,这种每次重写时不需要重启web服务器,且结构上比较清晰。

16、Mysql的读写分离?(进阶的会遇到)

读写分离的实现原理就是在执行SQL语句的时候,判断到底是读操作还是写操作,把读的操作转向到读服务器上(从服务器,一般是多台),写的操作转到写的服务器上(主服务器,一般是一台,视数据量来看)。当然为了保证多台数据库数据的一致性,需要主从复制。

17、如何处理负载,高并发?

1、HTML静态化
效率最高、消耗最小的就是纯静态化的html页面,所以我们尽可能使我们的 网站上的页面采用静态页面来实现,这个最简单的方法其实也是最有效的方法。
2、图片服务器分离
把图片单独存储,尽量减少图片等大流量的开销,可以放在一些相关的平台上,如七牛等
3、数据库集群和库表散列及缓存
数据库的并发连接为100,一台数据库远远不够,可以从读写分离、主从复制,数据库集群方面来着手。另外尽量减少数据库的访问,可以使用缓存数据库如memcache、redis。
4、镜像:
尽量减少下载,可以把不同的请求分发到多个镜像端。
5、负载均衡:
Apache的最大并发连接为1500,只能增加服务器,可以从硬件上着手,如F5服务器。当然硬件的成本比较高,我们往往从软件方面着手。

18、说一下单引号双引号?(基础考点)

单引号内部的变量不会执行, 双引号会执行

单引号解析速度比双引号快。

单引号只能解析部分特殊字符,双引号可以解析所有特殊字符。

19、PHP7的新特性?重点

标量类型声明:PHP 7 中的函数的形参类型声明可以是标量了。在 PHP 5 中只能是类名、接口、array 或者 callable (PHP 5.4,即可以是函数,包括匿名函数),现在也可以使用 string、int、float和 bool 了。

返回值类型声明:增加了对返回类型声明的支持。 类似于参数类型声明,返回类型声明指明了函数返回值的类型。可用的类型与参数声明中可用的类型相同。

NULL 合并运算符:由于日常使用中存在大量同时使用三元表达式和 isset()的情况,NULL 合并运算符使得变量存在且值不为NULL, 它就会返回自身的值,否则返回它的第二个操作数。

use 加强:从同一 namespace 导入的类、函数和常量现在可以通过单个 use 语句 一次性导入了

匿名类:现在支持通过new class 来实例化一个匿名类

20、PHP 数组排序

sort() - 以升序对数组排序

rsort() - 以降序对数组排序

asort() - 根据值,以升序对关联数组进行排序

ksort() - 根据键,以升序对关联数组进行排序

arsort() - 根据值,以降序对关联数组进行排序

krsort() - 根据键,以降序对关联数组进行排序

21、建立索引

1
2
3
4
5
6
7
8
9
10
11
(普通索引)->
创建:CREATE INDEX <索引名> ON tablename (索引字段)
修改:ALTER TABLE tablename ADD INDEX [索引名] (索引字段)
创表指定索引:CREATE TABLE tablename([...],INDEX[索引名](索引字段))
(唯一索引)->
创建:CREATE UNIQUE <索引名> ON tablename (索引字段)
修改:ALTER TABLE tablename ADD UNIQUE [索引名] (索引字段)
创表指定索引:CREATE TABLE tablename([...],UNIQUE[索引名](索引字段))
(主键)->
它是唯一索引,一般在创建表是建立,格式为:
CREATA TABLE tablename ([...],PRIMARY KEY[索引字段])

22、PHP支持多继承吗?

不支持。PHP中只允许单继承,父类可以被一个子类用关键字“extends”继承。

23、使用过Memcache缓存吗,如果使用过,能够简单的描述一下它的工作原理吗?

Memcahce是把所有的数据保存在内存当中,采用hash表的方式,每条数据又key和value组成,每个key是独一无二的,当要访问某个值的时候先按照找到值,然后返回结果。
Memcahce采用LRU算法来逐渐把过期数据清除掉。

24、优化MYSQL数据库的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
(1)选择最有效率的表名顺序
(2)WHERE子句中的连接顺序
(3)SELECT子句中避免使用‘*’
(4)用Where子句替换HAVING子句
(5)通过内部函数提高SQL效率
(6)避免在索引列上使用计算。
(7)提高GROUP BY 语句的效率, 可以通过将不需要的记录在GROUP BY 之前过滤掉。

(1).选取最适用的字段属性,应该尽量把字段设置为NOT NULL
(2).使用连接(JOIN)来代替子查询(Sub-Queries)
(3).使用联合(UNION)来代替手动创建的临时表
(4).尽量少使用 LIKE 关键字和通配符
(5).使用事务和外键

25、MySQL主从备份的原理?

mysql支持单向、异步复制,复制过程中一个服务器充当主服务器,而一个或多个其它服务器充当从服务器。

26、error_reporting() 的作用?

设置 PHP 的报错级别并返回当前级别。

27、如何修改session的生存时间

在php.ini 中设置 session.gc_maxlifetime = 1440 //默认时间

代码实现

1
2
3
$lifeTime = 24 * 3600;  // 保存一天 
session_set_cookie_params($lifeTime);
session_start();

28、常见的 PHP 安全性攻击

SQL注入:用户利用在表单字段输入SQL语句的方式来影响正常的SQL执行。
防止

使用mysql_real_escape_string()过滤数据

手动检查每一数据是否为正确的数据类型

使用预处理语句并绑定变量

参数化SQL:是指在设计与数据库链接并访问数据时,在需要填入数值或数据的地方,使用参数 (Parameter) 来给值,用@或?来表示参数。

XSS攻击 :跨站点脚本攻击,由用户输入一些数据到你的网站,其中包括客户端脚本(通常JavaScript)。如果你没有过滤就输出数据到另一个web页面,这个脚本将被执行。
防止:为了防止XSS攻击,使用PHP的htmlentities()函数过滤再输出到浏览器。

CSRF:跨站点请求伪造,是指一个页面发出的请求,看起来就像是网站的信任用户,但是是伪造的
防止:一般来说,确保用户来自你的表单,并且匹配每一个你发送出去的表单。有两点一定要记住:

对用户会话采用适当的安全措施,例如:给每一个会话更新id和用户使用SSL。

生成另一个一次性的令牌并将其嵌入表单,保存在会话中(一个会话变量),在提交时检查它。 如laravel中的 _token

代码注入:代码注入是利用计算机漏洞通过处理无效数据造成的。问题出在,当你不小心执行任意代码,通常通过文件包含。写得很糟糕的代码可以允许一个远程文件包含并执行。如许多PHP函数,如require可以包含URL或文件名。
防止代码注入

过滤用户输入

在php.ini中设置禁用allow_url_fopen和allow_url_include。这将禁用require/include/fopen的远程文件

题型还有很多,希望大家在学习过程中,慢慢的去发现和慢慢的提升自己的学习技能,最后祝大家学习愉快!!

【运维】 1.入门学习

CentOS7 安装svn

  1. 安装
  • CentOS7下yum命令即可方便的完成安装
1
$ sudo yum install subversion
  • 测试安装是否成功:
1
$ svnserve --version
  1. 建立版本库
  • 创建svn数据目录(subversion默认是把/var/svn作为数据根目录的,开机启动默认也是从这里):

    1
    $ sudo mkdir -p /var/svn
  • 创建版本库:

    1
    $ sudo svnadmin create /var/svn/wangwa
  • 如果删除版本库:
1
$ sudo rm -rf /var/svn/somnus
  1. 配置svn配置文件

每个版本库创建之后都会生成svnserve.conf主要配置文件。编辑它:

1
$ sudo vim /var/svn/somnus/conf/svnserve.conf

编辑示例:

1
2
3
4
5
6
[general]
anon-access = none #控制非鉴权用户访问版本库的权限
auth-access = write #控制鉴权用户访问版本库的权限
password-db = passwd #指定用户名口令文件名
authz-db = authz #指定权限配置文件名
realm = somnus #指定版本库的认证域,即在登录时提示的认证域名称
  1. 编辑svn用户配置文件
1
sudo vim /var/svn/somnus/conf/passwd

编辑示例:

1
2
3
4
[users]
admin = admin #用户,密码
fuhd = fuhd #用户,密码
test = test #用户,密码
  1. 编辑svn权限控制配置文件
1
sudo vim /var/svn/somnus/conf/authz

编辑示例:

1
2
3
4
5
6
7
8
9
[groups]
admin = admin #admin为用户组,等号之后的admin为用户
test = fuhd,test

[somnus:/] #表示根目录(/var/svn/somnus),somnus: 对应前面配置的realm = somnus
@admin = rw #表示admin组对根目录有读写权限,r为读,w为写

[somnus:/test] #表示test目录(/var/svn/somnus/test)
@test = rw #表示test组对test目录有读写权限
  1. 启动,查看和停止SVN服务
  • 启动SVN服务:

    1
    2
    #-d : 守护进程  -r : svn数据根目录 
    $ sudo svnserve -dr /var/svn #用root权限启动
  • 查看SVN服务:
1
$ ps aux|grep svns erve               #默认端口为:3690
  1. 配置防火墙端口

首先要明确CentOS7的默认防火墙为firewallD。subversion的默认端口为3690,如果没有打开会报错:

1
2
$ sudo firewall-cmd --permanent -add-port=3690/tcp
$ sudo firewall-cmd --reload
  1. 检索项目和切换项目的url
  • 项目检错
1
$ svn checkout svn://192.168.0.112/XK_Project . #使用 checkout  服务器资源 本地目录
  • 切换项目url
1
$ svn switch --relocate svn://192.168.0.112/XK_Project svn://192.168.0.120/XK_Project   # 使用 switch 迁移 from  to 新的地址
  1. 设置开机启动

在centos7, 设置开机启动:

1
2
3
4
$ sudo systemctl enable svnserve.service      #注意:根目录必须是/var/svn 这样才能设置成功!!
#设置开机启动后就可以按下面的方式开启或停止服务了
$ sudo systemctl start svnserve.service
$ sudo systemctl stop svnserve.service

临时关闭:

1
$ sudo setenforce 0

永久关闭:

1
$ sudo vim /etc/sysconfig/selinux

修改:

1
SELINUX = disable               #值修改为disable.

【mysql】 2.mysql基础入门(全)

##本单元目标
一、为什么要学习数据库
二、数据库的相关概念
DBMS、DB、SQL
三、数据库存储数据的特点
四、初始MySQL
MySQL产品的介绍
MySQL产品的安装 ★
MySQL服务的启动和停止 ★
MySQL服务的登录和退出 ★
MySQL的常见命令和语法规范
五、DQL语言的学习 ★
基础查询 ★
条件查询 ★
排序查询 ★
常见函数 ★
分组函数 ★
分组查询 ★
连接查询 ★
子查询 √
分页查询 ★
union联合查询 √

六、DML语言的学习    ★             
    插入语句                        
    修改语句                        
    删除语句                        
七、DDL语言的学习  
    库和表的管理     √                
    常见数据类型介绍  √          
    常见约束        √            
八、TCL语言的学习
    事务和事务处理                 
九、视图的讲解           √
十、变量                      
十一、存储过程和函数   
十二、流程控制结构       

##数据库的好处
1.持久化数据到本地
2.可以实现结构化查询,方便管理

##数据库相关概念
1、DB:数据库,保存一组有组织的数据的容器
2、DBMS:数据库管理系统,又称为数据库软件(产品),用于管理DB中的数据
3、SQL:结构化查询语言,用于和DBMS通信的语言

##数据库存储数据的特点
1、将数据放到表中,表再放到库中
2、一个数据库中可以有多个表,每个表都有一个的名字,用来标识自己。表名具有唯一性。
3、表具有一些特性,这些特性定义了数据在表中如何存储,类似java中 “类”的设计。
4、表由列组成,我们也称为字段。所有表都是由一个或多个列组成的,每一列类似java 中的”属性”
5、表中的数据是按行存储的,每一行类似于java中的“对象”。

##MySQL产品的介绍和安装

###MySQL服务的启动和停止
方式一:计算机——右击管理——服务
方式二:通过管理员身份运行
net start 服务名(启动服务)
net stop 服务名(停止服务)

###MySQL服务的登录和退出
方式一:通过mysql自带的客户端
只限于root用户

方式二:通过windows自带的客户端
登录:
mysql 【-h主机名 -P端口号 】-u用户名 -p密码

退出:
exit或ctrl+C

###MySQL的常见命令

1.查看当前所有的数据库
show databases;
2.打开指定的库
use 库名
3.查看当前库的所有表
show tables;
4.查看其它库的所有表
show tables from 库名;
5.创建表
create table 表名(

    列名 列类型,
    列名 列类型,
    。。。
);
6.查看表结构
desc 表名;


7.查看服务器的版本
方式一:登录到mysql服务端
select version();
方式二:没有登录到mysql服务端
mysql --version
或
mysql --V

###MySQL的语法规范
1.不区分大小写,但建议关键字大写,表名、列名小写
2.每条命令最好用分号结尾
3.每条命令根据需要,可以进行缩进 或换行
4.注释
单行注释:#注释文字
单行注释:– 注释文字
多行注释:/* 注释文字 */

###SQL的语言分类
DQL(Data Query Language):数据查询语言
select
DML(Data Manipulate Language):数据操作语言
insert 、update、delete
DDL(Data Define Languge):数据定义语言
create、drop、alter
TCL(Transaction Control Language):事务控制语言
commit、rollback

###SQL的常见命令

show databases; 查看所有的数据库
use 库名; 打开指定 的库
show tables ; 显示库中的所有表
show tables from 库名;显示指定库中的所有表
create table 表名(
    字段名 字段类型,    
    字段名 字段类型
); 创建表

desc 表名; 查看指定表的结构
select * from 表名;显示表中的所有数据

##DQL语言的学习
###进阶1:基础查询
语法:
SELECT 要查询的东西
【FROM 表名】;

类似于Java中 :System.out.println(要打印的东西);
特点:
①通过select查询完的结果 ,是一个虚拟的表格,不是真实存在
② 要查询的东西 可以是常量值、可以是表达式、可以是字段、可以是函数

###进阶2:条件查询
条件查询:根据条件过滤原始表的数据,查询到想要的数据
语法:
select
要查询的字段|表达式|常量值|函数
from

where
条件 ;

分类:
一、条件表达式
    示例:salary>10000
    条件运算符:
    > < >= <= = != <>

二、逻辑表达式
示例:salary>10000 && salary<20000

逻辑运算符:

    and(&&):两个条件如果同时成立,结果为true,否则为false
    or(||):两个条件只要有一个成立,结果为true,否则为false
    not(!):如果条件成立,则not后为false,否则为true

三、模糊查询
示例:last_name like 'a%'

###进阶3:排序查询

语法:
select
    要查询的东西
from
    表
where 
    条件

order by 排序的字段|表达式|函数|别名 【asc|desc】

###进阶4:常见函数
一、单行函数
1、字符函数
concat拼接
substr截取子串
upper转换成大写
lower转换成小写
trim去前后指定的空格和字符
ltrim去左边空格
rtrim去右边空格
replace替换
lpad左填充
rpad右填充
instr返回子串第一次出现的索引
length 获取字节个数

2、数学函数
    round 四舍五入
    rand 随机数
    floor向下取整
    ceil向上取整
    mod取余
    truncate截断
3、日期函数
    now当前系统日期+时间
    curdate当前系统日期
    curtime当前系统时间
    str_to_date 将字符转换成日期
    date_format将日期转换成字符
4、流程控制函数
    if 处理双分支
    case语句 处理多分支
        情况1:处理等值判断
        情况2:处理条件判断

5、其他函数
    version版本
    database当前库
    user当前连接用户

二、分组函数

sum 求和
max 最大值
min 最小值
avg 平均值
count 计数

特点:
1、以上五个分组函数都忽略null值,除了count(*)
2、sum和avg一般用于处理数值型
    max、min、count可以处理任何数据类型
3、都可以搭配distinct使用,用于统计去重后的结果
4、count的参数可以支持:
    字段、*、常量值,一般放1

   建议使用 count(*)

##进阶5:分组查询
语法:
select 查询的字段,分组函数
from 表
group by 分组的字段

特点:
1、可以按单个字段分组
2、和分组函数一同查询的字段最好是分组后的字段
3、分组筛选
        针对的表    位置            关键字
分组前筛选:    原始表        group by的前面        where
分组后筛选:    分组后的结果集    group by的后面        having

4、可以按多个字段分组,字段之间用逗号隔开
5、可以支持排序
6、having后可以支持别名

##进阶6:多表连接查询

笛卡尔乘积:如果连接条件省略或无效则会出现
解决办法:添加上连接条件

一、传统模式下的连接 :等值连接——非等值连接

1.等值连接的结果 = 多个表的交集
2.n表连接,至少需要n-1个连接条件
3.多个表不分主次,没有顺序要求
4.一般为表起别名,提高阅读性和性能

二、sql99语法:通过join关键字实现连接

含义:1999年推出的sql语法
支持:
等值连接、非等值连接 (内连接)
外连接
交叉连接

语法:

select 字段,...
from 表1
【inner|left outer|right outer|cross】join 表2 on  连接条件
【inner|left outer|right outer|cross】join 表3 on  连接条件
【where 筛选条件】
【group by 分组字段】
【having 分组后的筛选条件】
【order by 排序的字段或表达式】

好处:语句上,连接条件和筛选条件实现了分离,简洁明了!

三、自连接

案例:查询员工名和直接上级的名称

sql99

SELECT e.last_name,m.last_name
FROM employees e
JOIN employees m ON e.`manager_id`=m.`employee_id`;

sql92

SELECT e.last_name,m.last_name
FROM employees e,employees m 
WHERE e.`manager_id`=m.`employee_id`;

##进阶7:子查询

含义:

一条查询语句中又嵌套了另一条完整的select语句,其中被嵌套的select语句,称为子查询或内查询
在外面的查询语句,称为主查询或外查询

特点:

1、子查询都放在小括号内
2、子查询可以放在from后面、select后面、where后面、having后面,但一般放在条件的右侧
3、子查询优先于主查询执行,主查询使用了子查询的执行结果
4、子查询根据查询结果的行数不同分为以下两类:
① 单行子查询
    结果集只有一行
    一般搭配单行操作符使用:> < = <> >= <= 
    非法使用子查询的情况:
    a、子查询的结果为一组值
    b、子查询的结果为空

② 多行子查询
    结果集有多行
    一般搭配多行操作符使用:any、all、in、not in
    in: 属于子查询结果中的任意一个就行
    any和all往往可以用其他查询代替

##进阶8:分页查询

应用场景:

实际的web项目中需要根据用户的需求提交对应的分页查询的sql语句

语法:

select 字段|表达式,...
from 表
【where 条件】
【group by 分组字段】
【having 条件】
【order by 排序的字段】
limit 【起始的条目索引,】条目数;

特点:

1.起始条目索引从0开始

2.limit子句放在查询语句的最后

3.公式:select * from  表 limit (page-1)*sizePerPage,sizePerPage
假如:
每页显示条目数sizePerPage
要显示的页数 page

##进阶9:联合查询

引入:
union 联合、合并

语法:

select 字段|常量|表达式|函数 【from 表】 【where 条件】 union 【all】
select 字段|常量|表达式|函数 【from 表】 【where 条件】 union 【all】
select 字段|常量|表达式|函数 【from 表】 【where 条件】 union  【all】
.....
select 字段|常量|表达式|函数 【from 表】 【where 条件】

特点:

1、多条查询语句的查询的列数必须是一致的
2、多条查询语句的查询的列的类型几乎相同
3、union代表去重,union all代表不去重

##DML语言

###插入

语法:
insert into 表名(字段名,…)
values(值1,…);

特点:

1、字段类型和值类型一致或兼容,而且一一对应
2、可以为空的字段,可以不用插入值,或用null填充
3、不可以为空的字段,必须插入值
4、字段个数和值的个数必须一致
5、字段可以省略,但默认所有字段,并且顺序和表中的存储顺序一致

###修改

修改单表语法:

update 表名 set 字段=新值,字段=新值
【where 条件】

修改多表语法:

update 表1 别名1,表2 别名2
set 字段=新值,字段=新值
where 连接条件
and 筛选条件

###删除

方式1:delete语句

单表的删除: ★
delete from 表名 【where 筛选条件】

多表的删除:
delete 别名1,别名2
from 表1 别名1,表2 别名2
where 连接条件
and 筛选条件;

方式2:truncate语句

truncate table 表名

两种方式的区别【面试题】

#1.truncate不能加where条件,而delete可以加where条件

#2.truncate的效率高一丢丢

#3.truncate 删除带自增长的列的表后,如果再插入数据,数据从1开始
#delete 删除带自增长列的表后,如果再插入数据,数据从上一次的断点处开始

#4.truncate删除不能回滚,delete删除可以回滚

##DDL语句
###库和表的管理
库的管理:

一、创建库
create database 库名
二、删除库
drop database 库名

表的管理:
#1.创建表

CREATE TABLE IF NOT EXISTS stuinfo(
    stuId INT,
    stuName VARCHAR(20),
    gender CHAR,
    bornDate DATETIME


);

DESC studentinfo;
#2.修改表 alter
语法:ALTER TABLE 表名 ADD|MODIFY|DROP|CHANGE COLUMN 字段名 【字段类型】;

#①修改字段名
ALTER TABLE studentinfo CHANGE  COLUMN sex gender CHAR;

#②修改表名
ALTER TABLE stuinfo RENAME [TO]  studentinfo;
#③修改字段类型和列级约束
ALTER TABLE studentinfo MODIFY COLUMN borndate DATE ;

#④添加字段

ALTER TABLE studentinfo ADD COLUMN email VARCHAR(20) first;
#⑤删除字段
ALTER TABLE studentinfo DROP COLUMN email;


#3.删除表

DROP TABLE [IF EXISTS] studentinfo;

###常见类型

整型:

小数:
    浮点型
    定点型
字符型:
日期型:
Blob类型:

###常见约束

NOT NULL
DEFAULT
UNIQUE
CHECK
PRIMARY KEY
FOREIGN KEY

##数据库事务
###含义
通过一组逻辑操作单元(一组DML——sql语句),将数据从一种状态切换到另外一种状态

###特点
(ACID)
原子性:要么都执行,要么都回滚
一致性:保证数据的状态操作前和操作后保持一致
隔离性:多个事务同时操作相同数据库的同一个数据时,一个事务的执行不受另外一个事务的干扰
持久性:一个事务一旦提交,则数据将持久化到本地,除非其他事务对其进行修改

相关步骤:

1、开启事务
2、编写事务的一组逻辑操作单元(多条sql语句)
3、提交事务或回滚事务

###事务的分类:

隐式事务,没有明显的开启和结束事务的标志

比如
insert、update、delete语句本身就是一个事务

显式事务,具有明显的开启和结束事务的标志

1、开启事务
取消自动提交事务的功能

2、编写事务的一组逻辑操作单元(多条sql语句)
insert
update
delete

3、提交事务或回滚事务

###使用到的关键字

set autocommit=0;
start transaction;
commit;
rollback;

savepoint  断点
commit to 断点
rollback to 断点

###事务的隔离级别:

事务并发问题如何发生?

当多个事务同时操作同一个数据库的相同数据时

事务的并发问题有哪些?

脏读:一个事务读取到了另外一个事务未提交的数据
不可重复读:同一个事务中,多次读取到的数据不一致
幻读:一个事务读取数据时,另外一个事务进行更新,导致第一个事务读取到了没有更新的数据

如何避免事务的并发问题?

通过设置事务的隔离级别
1、READ UNCOMMITTED
2、READ COMMITTED 可以避免脏读
3、REPEATABLE READ 可以避免脏读、不可重复读和一部分幻读
4、SERIALIZABLE可以避免脏读、不可重复读和幻读

设置隔离级别:

set session|global  transaction isolation level 隔离级别名;

查看隔离级别:

select @@tx_isolation;

##视图
含义:理解成一张虚拟的表

视图和表的区别:

    使用方式    占用物理空间

视图    完全相同    不占用,仅仅保存的是sql逻辑

表    完全相同    占用

视图的好处:

1、sql语句提高重用性,效率高
2、和表实现了分离,提高了安全性

###视图的创建
语法:
CREATE VIEW 视图名
AS
查询语句;
###视图的增删改查
1、查看视图的数据 ★

SELECT * FROM my_v4;
SELECT * FROM my_v1 WHERE last_name='Partners';

2、插入视图的数据
INSERT INTO my_v4(last_name,department_id) VALUES('虚竹',90);

3、修改视图的数据

UPDATE my_v4 SET last_name ='梦姑' WHERE last_name='虚竹';


4、删除视图的数据
DELETE FROM my_v4;

###某些视图不能更新
包含以下关键字的sql语句:分组函数、distinct、group by、having、union或者union all
常量视图
Select中包含子查询
join
from一个不能更新的视图
where子句的子查询引用了from子句中的表
###视图逻辑的更新
#方式一:
CREATE OR REPLACE VIEW test_v7
AS
SELECT last_name FROM employees
WHERE employee_id>100;

#方式二:
ALTER VIEW test_v7
AS
SELECT employee_id FROM employees;

SELECT * FROM test_v7;

###视图的删除
DROP VIEW test_v1,test_v2,test_v3;
###视图结构的查看
DESC test_v7;
SHOW CREATE VIEW test_v7;

##存储过程

含义:一组经过预先编译的sql语句的集合
好处:

1、提高了sql语句的重用性,减少了开发程序员的压力
2、提高了效率
3、减少了传输次数

分类:

1、无返回无参
2、仅仅带in类型,无返回有参
3、仅仅带out类型,有返回无参
4、既带in又带out,有返回有参
5、带inout,有返回有参
注意:in、out、inout都可以在一个存储过程中带多个

###创建存储过程
语法:

create procedure 存储过程名(in|out|inout 参数名  参数类型,...)
begin
    存储过程体

end

类似于方法:

修饰符 返回类型 方法名(参数类型 参数名,...){

    方法体;
}

注意

1、需要设置新的结束标记
delimiter 新的结束标记
示例:
delimiter $

CREATE PROCEDURE 存储过程名(IN|OUT|INOUT 参数名  参数类型,...)
BEGIN
    sql语句1;
    sql语句2;

END $

2、存储过程体中可以有多条sql语句,如果仅仅一条sql语句,则可以省略begin end

3、参数前面的符号的意思
in:该参数只能作为输入 (该参数不能做返回值)
out:该参数只能作为输出(该参数只能做返回值)
inout:既能做输入又能做输出

#调用存储过程
call 存储过程名(实参列表)
##函数

###创建函数

学过的函数:LENGTH、SUBSTR、CONCAT等
语法:

CREATE FUNCTION 函数名(参数名 参数类型,...) RETURNS 返回类型
BEGIN
    函数体

END

###调用函数
SELECT 函数名(实参列表)

###函数和存储过程的区别

        关键字        调用语法    返回值            应用场景
函数        FUNCTION    SELECT 函数()    只能是一个        一般用于查询结果为一个值并返回时,当有返回值而且仅仅一个
存储过程    PROCEDURE    CALL 存储过程()    可以有0个或多个        一般用于更新

##流程控制结构

###系统变量
一、全局变量

作用域:针对于所有会话(连接)有效,但不能跨重启

查看所有全局变量
SHOW GLOBAL VARIABLES;
查看满足条件的部分系统变量
SHOW GLOBAL VARIABLES LIKE '%char%';
查看指定的系统变量的值
SELECT @@global.autocommit;
为某个系统变量赋值
SET @@global.autocommit=0;
SET GLOBAL autocommit=0;

二、会话变量

作用域:针对于当前会话(连接)有效

查看所有会话变量
SHOW SESSION VARIABLES;
查看满足条件的部分会话变量
SHOW SESSION VARIABLES LIKE '%char%';
查看指定的会话变量的值
SELECT @@autocommit;
SELECT @@session.tx_isolation;
为某个会话变量赋值
SET @@session.tx_isolation='read-uncommitted';
SET SESSION tx_isolation='read-committed';

###自定义变量
一、用户变量

声明并初始化:

SET @变量名=值;
SET @变量名:=值;
SELECT @变量名:=值;

赋值:

方式一:一般用于赋简单的值
SET 变量名=值;
SET 变量名:=值;
SELECT 变量名:=值;


方式二:一般用于赋表 中的字段值
SELECT 字段名或表达式 INTO 变量
FROM 表;

使用:

select @变量名;

二、局部变量

声明:

declare 变量名 类型 【default 值】;

赋值:

方式一:一般用于赋简单的值
SET 变量名=值;
SET 变量名:=值;
SELECT 变量名:=值;


方式二:一般用于赋表 中的字段值
SELECT 字段名或表达式 INTO 变量
FROM 表;

使用:

select 变量名

二者的区别:

作用域            定义位置        语法

用户变量 当前会话 会话的任何地方 加@符号,不用指定类型
局部变量 定义它的BEGIN END中 BEGIN END的第一句话 一般不用加@,需要指定类型

###分支
一、if函数
语法:if(条件,值1,值2)
特点:可以用在任何位置

二、case语句

语法:

情况一:类似于switch
case 表达式
when 值1 then 结果1或语句1(如果是语句,需要加分号) 
when 值2 then 结果2或语句2(如果是语句,需要加分号)
...
else 结果n或语句n(如果是语句,需要加分号)
end 【case】(如果是放在begin end中需要加上case,如果放在select后面不需要)

情况二:类似于多重if
case 
when 条件1 then 结果1或语句1(如果是语句,需要加分号) 
when 条件2 then 结果2或语句2(如果是语句,需要加分号)
...
else 结果n或语句n(如果是语句,需要加分号)
end 【case】(如果是放在begin end中需要加上case,如果放在select后面不需要)

特点:
可以用在任何位置

三、if elseif语句

语法:

if 情况1 then 语句1;
elseif 情况2 then 语句2;
...
else 语句n;
end if;

特点:
只能用在begin end中!!!!!!!!!!!!!!!

三者比较:
应用场合
if函数 简单双分支
case结构 等值判断 的多分支
if结构 区间判断 的多分支

###循环

语法:

【标签:】WHILE 循环条件  DO
    循环体
END WHILE 【标签】;

特点:

只能放在BEGIN END里面

如果要搭配leave跳转语句,需要使用标签,否则可以不用标签

leave类似于java中的break语句,跳出所在循环!!!

【mysql】 1.mysql基础入门

一、mysql基础入门

  1. 常见函数

1
2
3
4
5
6
类似与java的方法,将一组逻辑语句封装在方法体中,对外暴露方法名
好处:隐藏了实现细节;提高代码的重用性
调用:select 函数名(实参列表) from 表名;
特点:叫什么(函数名);干什么(函数功能)
分类:1.单行函数:如-contact lenth ifnull等
2.多行函数:功能:做统计使用,又称为统计函数,聚合函数,组函数
  • 单行函数:字符函数、数学函数、日期函数、其他函数、流程控制函数字符函数
字符函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 1.length 获取参数值的字节个数
select length('tom') # 3
# 2.contact 拼接字符串
select contact(last_name,'-',first_name) as 姓名 from user;
# 3.upper、lower 大小写转换
select upper('Tom')
select lower('Tom')
# 4.substr、substring 截取参数值
select substr(string,position,length) output; # 索引从1开始
# 5.instr 获取参数的某字符的开始位置,如果找不到返回0
select instr("你好我是一个傻子",'傻子') #7
# 6.trim 去掉字符串的两端空格
select trim(" Tim ") as name; # 去掉两端空格
select trim('a' from 'aaaaaaaaaaaa你好aaaaa你好aaaaaaa') as output # 去掉两端的a字符
# 7.lpad 用指定的字符实现左填充,超过会从右截断
select lpad('我是',10,‘*’) as output
# 8.rpad 用指定的字符实现右填充,超过会从右截断
select rpad('我是一个傻子',10,‘*’) as output
# 9.replace 替换字符串
select replace('张无忌爱上了周芷若','周芷若','赵敏')
数学函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 1.round 四舍五入
select round(1.65) # 2
select round(1.568,2) # 小数点后保留两位 1.57
# 2.ceil 向上取整(返回大于等于参数的最小整数)
select ceil(1.00) # 1
select ceil(0.01) # 1
# 3.floor 向下取整(返回小于等于参数的最大整数)
select floor(-9.99) # -10
# 4.truncate 截断
select truncate(1.65,1) # 1.6 小数点后保留一位
# 5.mod 取余 mod(a,b) a-a/b*b
select mod(10,3) # 1
select mod(-10,-3) # -1 被除数为正则正
select mod(10,-3) # 1 被除数为负则负
日期函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 1.now 返回当前系统日期+时间
select now();
# 2.curdate 返回当前系统日期,不包含时间
select curdate();
# 3.curtime 返回当前时间,不包含日期
select curtime();
# 4.可以获取指定的部分,年,月,日,时,分,秒等等
select year(now()) 年;
select year('1998-01-01') 年;
select month('1998-01-01') 月;
select monthname('1998-01-01') 月; # 出现月份的英文
# str_to_date:将日期格式的字符转换成指定格式的日期
str_to_date('9-13-1999','%m-%d-%Y');
%Y 4位的年份 %y 2位的年份
%m 月份(01,02....)
%c 月份(1,2,3....)
%d 日(01,02...)
%H 小时(24小时制)
%h 小时(12小时制)
%i 分钟(00,01,02...)
%s 秒(00,01,02)

【PyQt5】 1.PyQt5入门学习

一、基本思路结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 1.导入需要的包和模块
from PyQt5.Qt import * # 主要包含了常用的包和模块
import sys # 通过sys.argv可以获取参数

# 2.创建一个应用程序对象
app = QApplication(sys.argv)
app.arguments() # 获取参数
qApp.arguments() # 全局 qApp获取参数

# 3.控件的操作
# 创建控件,设置样式,信号的处理

# 4.应用程序的执行,进行到 消息循环(无限循环),检测整个程序的用户操作交互
app.exec_()
二、第一个PyQt5程序:hello world
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from PyQt5.Qt import *
import sys

app = QApplication(sys.argv)

window = QWidget()
window.setWindowTitle("微博搜索助手")
window.resize(500,500)
window.move(400,200)

label = QLabel(window)
label.setText("hello world")
label.move(200,200)

window.show()
sys.exit(app.exec_())
封装成面向对象:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from PyQt5.Qt import *


class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("学习入门")
self.resize(500,500)
self.setup_ui()

def setup_ui(self):
pass

if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
设置控件样式:
1
2
3
4
5
6
7
8
9
10
11
def setup_ui(self):
# 加载外部样式qss
with open("QLabel.qss",'r') as f:
qApp.setStyleSheet(f.read())

label = QLabel(self)
label.setObjectName("labelStyle")
label.setProperty("notice_level","warning")
label.setText("文本设置样式")
# 单独设置样式,优先级高于外部加载样式
# label.setStyleSheet("font-size:20px;color:red;")

外部样式文件QLabel.qss:

1
2
3
4
5
6
7
8
QLabel#labelStyle {    
font-size:20;
color:yellow;
}
QLabel#labelStyle[notice_level="warning"] {
font-size:40px;
color:red;
}
设置控件的父子关系:
1
2
3
4
5
6
7
8
obj1 = QObject()
obj2 = QObject()
obj1.setParent(obj2) # 设置obj2为obj1的父对象 一个对象的父对象只有一个,以后设置的为父对象
obj1.parent() # 查看obj1的父对象
obj2.children() # 查看obj2的所有的直接子对象
# 参数1:查找的对象类型;参数2:查找的对象名称;参数3:默认是递归查找#(Qt.FindDirectChildrenOnly- 仅查找直接子对象; Qt.FindChildrenRecursively- 递归查找 默认选项)
obj1.findChild(参数1,参数2,参数3)
obj1.findChildren(参数1,参数2,参数3) # 查找所有子对象
内存管理机制:

所有的对象都是直接或者间接的继承QObject

QObject在一个对象树中组织,当创建一个QObject时,如果使用了其他对象作为其父对象,那么他就会添加到父对象的children列表中

当父对象被销毁时,这么QObject对象就会被销毁,其所有子对象同时也会被销毁

子控件和父控件的关系:显示受父控件约束,父控件销毁子控件也会销毁

如果两个控件都没有父控件,那么都会当做单独的顶级控件显示;

只有顶级控件才能设置标题栏等属性信息;

信号与槽机制:

基本概念:

信号(Signal)和槽(slot)是Qt中的核心机制,主要用于对象之间进行通讯

信号:当一个控件的状态发生改变时,向外界发出的信息

槽:一个执行某些操作的函数或方法

所有继承自QWidget的控件都支持信号与槽机制

信号:

控件内置的一些 QPushButton().pressed/clicked

也可以自定义信号:

槽:

不同控件内置的槽函数

自定义的函数方法

连接方式:

object.信号.connect(槽函数)

特性:

一个信号可以连接多个槽函数

一个信号也可以连接多个槽函数

信号的参数可以使任何python类型

一个槽可以监听多个信号
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 信号一 演示
obj = QObject()
obj.destroyed.connect(lambda :print("对象已被销毁"))
# ouput:
# 对象已被销毁

# 信号二 演示
def change(name):
print("名称发生改变",name)
obj.objectNameChanged.connect(change)
obj.setObjectName("名称修改")
# ouput:
# 名称发生改变 名称修改

# 断开信号连接
def change(name):
print("名称发生改变",name)
obj.objectNameChanged.connect(change)
obj.setObjectName("名称修改1")
obj.objectNameChanged.disconnect()
obj.setObjectName("名称修改2")
# ouput:
# 名称发生改变 名称修改1

# 临时断开信号连接和恢复信号连接
obj = QObject()
def change(name):
print("名称发生改变",name)
obj.objectNameChanged.connect(change)
obj.setObjectName("名称修改1")
obj.blockSignals(True) # 临时阻断信号连接
obj.setObjectName("名称修改2")
obj.blockSignals(False) # 恢复信号连接
obj.setObjectName("名称修改3")
obj.SignalsBlocked() # 查看连接状态(暂停为True,未暂停未False)
obj.obj.receivers(obj.objectNameChanged) # 输出当前连接对应槽的数量:1
# ouput:
# 名称发生改变 名称修改1
# 名称发生改变 名称修改3
QObject 类型判定
1
2
3
4
5
6
7
8
9
10
11
12
13
obj = QObject()
w = QWidget()
btn = QPushButton()
label = QLabel()
objs = [obj,w,btn,label]
for o in objs:
print(o.isWidgetType()) # 是否是控件类型
# print(o.inherits('QWidget'))# 是否是控件类型
# output:
# False
# True
# True
# True
对象删除 obj.deleteLater():
  1. 删除一个对象时,也会接触它与父对象之间的关系
  2. 并没有将对象立即销毁,而是向主消息循环发送了一个event,下次主循环循环收到这个event之后才会销毁对象
  3. 这样做额好处是可以在这些延迟删除的时间内完成一些操作,坏处就是内存释放会不及时

应用场景:想要移除某个对象时候使用

定时器
1
2
3
4
5
6
7
class MyObject(QObject):
def timerEvent(self,evt):
print(evt,"1")

obj = MyObject()
timer_id = obj.startTimer(1000) # 开启定时器
obj.killTimer(timer_id) # 删除定时器

【python】 1.使用虚拟环境搭建项目

pipenv安装和虚拟环境的创建

安装pipenv
1
pip install pipenv -i https://pypi.douban.com/simple # 采用豆瓣源全局安装
创建虚拟环境
1
2
pipenv --three  # 采用python3作为虚拟环境编译版本
pipenv shell # 打开虚拟环境
安装第三方包模块
1
pipenv install pyqt5

直接安装由于直接用的是国外镜像,会出现安装过慢或者安装错误的情况

解决:修改目录下Pipfile文件source下url地址:

​ 改为国内镜像地址:https://pypi.douban.com/simple (豆瓣源)

https://pypi.tuna.tsinghua.edu.cn/simple (清华源)

【php】 1.在CentOS上搭建LNMP环境

一、准备

启动epel的源
1
yum install epel-release
关闭SELinux

SELinux是严格访问模式,初学Linux建议把此功能关闭,编辑/etc/selinux/config

1
SELINUX = disabled  		# 修改此行为disabled
关闭SELinux之后需要重启服务器,或者直接用命令
1
setenforce 0

二、开始安装

安装nginx,mysql,php,fast-cgi:
1
yum install nginx mariadb-server mariadb php php-fpm php-mysql
启动nginx,mysql,php-fpm:
1
2
3
systemctl start nginx
systemctl start mariadb
systemctl start php-fpm
设置成开机启动:
1
2
3
systemctl enable nginx
systemctl enable mariadb
systemctl enable php-fpm
查看运行状态:
1
systemctl status nginx
查看端口占用状态:
1
netstat -tunlp
在nginx上添加新的站点:

编辑vim /etc/nginx/conf.d/test.com.conf,添加以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
server {
listen 80;
server_name www.test.com;
charset utf-8;
index index.php;
location ~ .php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
root /var/www/www.test.com/;
}
创建测试文件:

站点配置好了,我们创建站点的根目录和测试文件:

1
2
mkdir /var/www/www.test.com
touch /var/www/www.test.com/index.php

我们修改此文件 vim /var/www/www.test.com/index.php:

1
2
3
<?php
phpinfo();
?>
然后我们修改目录权限,让此目录属主为nginx:
1
chown -R nginx:nginx /var/www/www.test.com
查看nginx进程:
1
ps aux|grep nginx
让nginx重新加载配置:
1
2
systemctl restart nginx	#用重启命令
systemctl reload nginx #用文件重启命令
##### 重启时候出现问题:

启动nginx提示“Job for nginx.service failed because the control process…”错误:

原因:配置文件错误,nginx配置文件为/etc/nginx/conf.d/*.conf,也就是/etc/nginx/conf.d/文件夹下的所有以.conf结尾的文件,如果同时存在两个以上的配置文件,那么这两个文件是会同时生效的,也就是nginx会把两个文件的内容拼接在一起,然后当成一个文件来运行,所以,如果nginx运行出现问题,记得检查/etc/nginx/conf.d/文件夹下所有以.conf结尾的配置文件。

解决:

1
解决办法:运行systemctl status nginx -l

找到对应错误并修改

【svn】 1.CentOS7 的svn简单安装与使用

CentOS7 安装svn

  1. 安装
  • CentOS7下yum命令即可方便的完成安装
1
$ sudo yum install subversion
  • 测试安装是否成功:
1
$ svnserve --version
  1. 建立版本库
  • 创建svn数据目录(subversion默认是把/var/svn作为数据根目录的,开机启动默认也是从这里):

    1
    $ sudo mkdir -p /var/svn
  • 创建版本库:

    1
    $ sudo svnadmin create /var/svn/wangwa
  • 如果删除版本库:
1
$ sudo rm -rf /var/svn/somnus
  1. 配置svn配置文件

每个版本库创建之后都会生成svnserve.conf主要配置文件。编辑它:

1
$ sudo vim /var/svn/somnus/conf/svnserve.conf

编辑示例:

1
2
3
4
5
6
[general]
anon-access = none #控制非鉴权用户访问版本库的权限
auth-access = write #控制鉴权用户访问版本库的权限
password-db = passwd #指定用户名口令文件名
authz-db = authz #指定权限配置文件名
realm = somnus #指定版本库的认证域,即在登录时提示的认证域名称
  1. 编辑svn用户配置文件
1
sudo vim /var/svn/somnus/conf/passwd

编辑示例:

1
2
3
4
[users]
admin = admin #用户,密码
fuhd = fuhd #用户,密码
test = test #用户,密码
  1. 编辑svn权限控制配置文件
1
sudo vim /var/svn/somnus/conf/authz

编辑示例:

1
2
3
4
5
6
7
8
9
[groups]
admin = admin #admin为用户组,等号之后的admin为用户
test = fuhd,test

[somnus:/] #表示根目录(/var/svn/somnus),somnus: 对应前面配置的realm = somnus
@admin = rw #表示admin组对根目录有读写权限,r为读,w为写

[somnus:/test] #表示test目录(/var/svn/somnus/test)
@test = rw #表示test组对test目录有读写权限
  1. 启动,查看和停止SVN服务
  • 启动SVN服务:

    1
    2
    #-d : 守护进程  -r : svn数据根目录 
    $ sudo svnserve -dr /var/svn #用root权限启动
  • 查看SVN服务:
1
$ ps aux|grep svns erve               #默认端口为:3690
  1. 配置防火墙端口

首先要明确CentOS7的默认防火墙为firewallD。subversion的默认端口为3690,如果没有打开会报错:

1
2
$ sudo firewall-cmd --permanent -add-port=3690/tcp
$ sudo firewall-cmd --reload
  1. 检索项目和切换项目的url
  • 项目检错
1
$ svn checkout svn://192.168.0.112/XK_Project . #使用 checkout  服务器资源 本地目录
  • 切换项目url
1
$ svn switch --relocate svn://192.168.0.112/XK_Project svn://192.168.0.120/XK_Project   # 使用 switch 迁移 from  to 新的地址
  1. 设置开机启动

在centos7, 设置开机启动:

1
2
3
4
$ sudo systemctl enable svnserve.service      #注意:根目录必须是/var/svn 这样才能设置成功!!
#设置开机启动后就可以按下面的方式开启或停止服务了
$ sudo systemctl start svnserve.service
$ sudo systemctl stop svnserve.service

临时关闭:

1
$ sudo setenforce 0

永久关闭:

1
$ sudo vim /etc/sysconfig/selinux

修改:

1
SELINUX = disable               #值修改为disable.

【scrapy】 2.scrapy进阶学习之随机请求头、随机代理和数据异步存储

使用scrapy框架完成图片的爬取

一、设置随机请求头中间件

修改middlewares.py中间件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import random

# 编写(重写)download中间件
class BmwimagesDownloaderMiddleware(object):
# Not all methods need to be defined. If a method is not defined,
# scrapy acts as if the downloader middleware does not modify the
# passed objects.

USER_AGENT = {
'Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; Acoo Browser 1.98.744; .NET CLR 3.5.30729)',
'Chrome (AppleWebKit/537.1; Chrome50.0; Windows NT 6.3) AppleWebKit/537.36 (KHTML like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393',
'Cyberdog/2.0 (Macintosh; 68k)'
}

def process_request(self, request, spider):

user_agent = random.choice(self.USER_AGENT)
request.headers['User-Agent'] = user_agent

return None

settings.py开启下载中间件

1
2
3
DOWNLOADER_MIDDLEWARES = {
'BmwImages.middlewares.BmwimagesDownloaderMiddleware': 543,
}

二、设置随机代理中间件

修改middlewares.py中间件内容

1
2
3
4
5
6
7
8
import random
def process_request(self, request, spider):

# 设置IP代理中间件
# 如果购买的是代理ip,会得到代理ip及端口列表
proxy_list = []
proxy = random.choice(proxy_list)
request.meta['proxy'] = proxy

settings.py开启下载中间件

1
2
3
DOWNLOADER_MIDDLEWARES = {
'BmwImages.middlewares.BmwimagesDownloaderMiddleware': 543,
}

爬取数据存入数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import pymysql

class JsPipeline(object):
def __init__(self):
dbparams = {
'host': '127.0.0.1',
'port': 3306,
'user': 'root',
'password': 'root',
'database': 'jianshu',
'charset': 'utf8'
}
self.conn = pymysql.connect(**dbparams)
self.cursor = self.conn.cursor()

def process_item(self, item, spider):
sql = "INSERT INTO `article` (`title`) VALUES ('%s')"%item['title']
self.cursor.execute(sql)
self.conn.commit()
return item

修改成爬取异步存储

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from pymysql import cursors
from twisted.enterprise import adbapi

class JsTwistedPipeline(object):

def __init__(self):
dbparams = {
'host': '127.0.0.1',
'port': 3306,
'user': 'root',
'password': 'root',
'database': 'jianshu',
'charset': 'utf8',
'cursorclass':cursors.DictCursor
}
self.dbpool = adbapi.ConnectionPool('pymysql',**dbparams)

def process_item(self, item, spider):
sql = "INSERT INTO `article` (`title`) VALUES ('%s')"%item['title']
defer = self.dbpool.runInteraction(self.insert_item,item)
defer.addErrback(self.handle_error,item,spider)
return item

def insert_item(self,cursor,item):
sql = "INSERT INTO `article` (`title`) VALUES ('%s')"%item['title']
cursor.execute(sql)

def handle_error(self,error,item,spider):
print('='*10+"error"+"="*10)
print(error)
print('='*10+"error"+"="*10)

使用selenium+webdriver爬取ajax请求的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from selenium import webdriver
from scrapy.http import HtmlResponse
import time

class JsSeleniumWebDriverMiddleware(object):

def __init__(self):
driver_path = r"D:\python\scrapy\study\20191009\chromedriver\chromedriver2-0.exe"
self.driver = webdriver.Chrome(executable_path=driver_path)

def process_request(self, request, spider):
self.driver.get(request.url)
time.sleep(1)
try:
while True:
showmore = self.driver.find_element_by_xpath("更多")
showmore.click()
time.sleep(0.3)
if not showmore:
break
except:
pass

source = self.driver.page_source
response = HtmlResponse(url=self.driver.current_url,body=source,request=request,encoding='utf-8')
return response

开启selenium+webdriver中间件

1
2
3
DOWNLOADER_MIDDLEWARES = {
'BmwImages.middlewares.JsSeleniumWebDriverMiddleware': 543,
}

【scrapy】 1.使用scrapy框架高效爬取汽车之家图片

使用scrapy框架完成图片的爬取

一、项目基础配置

创建项目

1
2
3
scrapy startproject BmwImages
cd BmwImages
scrapy genspider bmwSpider car.autohome.com.cn

修改基础配置

1
2
3
* settings中ROBOTSTXT_OBEY
* DEFAULT_REQUEST_HEADERS
* USER_AGENT

增加start.py启动爬虫文件

1
2
from scrapy import cmdline
cmdline.execute("scrapy crawl bmwSpider".split())

二、爬取图片数据

获取图片类别名称和urls列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import scrapy
from urllib import parse
from BmwImages.items import BmwimagesItem

class BmwspiderSpider(scrapy.Spider):
name = 'bmwSpider'
allowed_domains = ['car.autohome.com.cn']
start_urls = ['https://car.autohome.com.cn/pic/series/66.html']

def parse(self, response):
uiboxs = response.xpath("//div[@class='uibox']")[1:]
for uibox in uiboxs:
category = uibox.xpath(".//div[@class='uibox-title']/a/text()").get()
urls = uibox.xpath(".//div//ul/li/a/img/@src").getall()
image_urls = list(map(lambda x:parse.urljoin(response.url,x.replace("240x180_0_q95_c42_","")),urls))
item = BmwimagesItem(category=category,image_urls=image_urls)
yield item

设置图片管道下载

1
2
3
4
5
6
import scrapy

class BmwimagesItem(scrapy.Item):
category = scrapy.Field()
image_urls = scrapy.Field()
images = scrapy.Field()

settings.py代码

1
2
3
4
5
6
7
8
import os

ITEM_PIPELINES = {
# 'BmwImages.pipelines.BmwimagesPipeline': 300,
'scrapy.pipelines.images.ImagesPipeline': 1
}

IMAGES_STORE = os.path.join(os.path.dirname(os.path.dirname(__file__)),'images')

重写方法设置目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import os
from scrapy.pipelines.images import ImagesPipeline
from BmwImages import settings

class BmwImagesPipeline(ImagesPipeline):

# 请求下载之前调用 发送下载请求
def get_media_requests(self, item, info):
request_objs = super(BmwImagesPipeline,self).get_media_requests(item, info)
for request_obj in request_objs:
request_obj.item = item
return request_objs

# 请求之后调用 图片将要被存储时调用获取路径
def file_path(self, request, response=None, info=None):
path = super(BmwImagesPipeline, self).file_path(request, response, info)
category = request.item.get('category')
image_store = settings.IMAGES_STORE
category_path = os.path.join(image_store,category)
if not os.path.exists(category_path):
os.mkdir(category_path)

image_name = path.replace("full/","")
image_path = os.path.join(category_path,image_name)
return image_path

使用crawlSpider进行改进,爬取更多图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# -*- coding: utf-8 -*-
import scrapy
from urllib import parse
from BmwImages.items import BmwimagesItem
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor

class BmwspiderSpider(CrawlSpider):
name = 'bmwCrawlSpider'
allowed_domains = ['car.autohome.com.cn']
start_urls = ['https://car.autohome.com.cn/pic/series/66.html']

rules = {
Rule(LinkExtractor(allow=r"https://car.autohome.com.cn/pic/series/66.+"),callback="parse_images",follow=True),
}

def parse_images(self,response):
category = response.xpath("//div[@class='uibox-title']/text()").getall()
category = "".join(category).split()
srcs = response.xpath("//div[contains(@class,'uibox-con')]/ul/li//img/@src").getall()
srcs = list(map(lambda x:parse.urljoin(response.url,x.replace("240x180_0_q95_c42_","1024x0_1_q95_")),srcs))
if len(category) != 0:
yield BmwimagesItem(category=category[0], image_urls=srcs)