PHP拓展 mysql、mysqli、pdo_mysql 区别与选择

今天是2020年,PHP连接MySQL有什么接口呢?还在用mysql函数?试试mysqli、pdo_mysql吧?那mysqli和pdo_mysql又有什么异同呢?来看看

PHP_mysql

PHP-MySQL 是 PHP 操作 MySQL 资料库最原始的 Extension

为了让自己强大起来,mysql 自己为安全也做了很多努力。以前例的 SQL 叙述来说,在sql 语句中使用 变量 直接拼接 的地方容易被 SQL Injection。后来于是发展出了 mysql_escape_string() (备注:5.3.0之后弃用) 以及
mysql_real_escape_string()解决此问题。

php_mysqli

PHP-MySQLi 的 i 代表 Improvement ,提更了相对进阶的功能,就 Extension 而言,本身也增加了安全性.

MySQL增强扩展,可以用于使用 MySQL4.1.3或更新版本中新的高级特性。其特点为:面向对象接口 、prepared语句支持、多语句执行支持、事务支持 、增强的调试能力、嵌入式服务支持 、预处理方式完全解决了sql注入的问题。不过其也有缺点, 就是只支持mysql数据库。如果你要是不操作其他的数据库,这无疑是最好的选择。

PDO_mysql

其功能类似于JDBC、ODBC、DBI之类接口。

PDO是PHP5.1之后才支持的,他为访问数据库采用了一致性的接口,有非常多的操作却是MySQL扩展库所不具备的:

1). PDO真正的以底层实现的统一接口数库操作接口
2). PDO支持更高级的DB特性操作,如:存储过程的调度等,mysql原生库是不支持的.
3). PDO是php官方的PECL库,兼容性稳定性必然要高于MySQL Extension,可以直接使用 pecl upgrade pdo 命令升级

过渡

那我自己举例,我最早接触的就是php_mysql 拓展,就是一个个的函数,封装一下就面向对象了。后来又听人说mysqli更好,更安全。发现从mysql过渡到mysqli,就是find mysql, repalce mysqli 这么简单。而PDO呢,对外提供的是完全的面向对象的API,而我们mysqli 同时对外暴露了 函数式和 面向对象 API。所以,你用mysqli面向对象那种方式,再切换到PDO 也很容易。

用PDO的好处是,PDO支持多种数据库,而MySQLi只支持MySQL,一但你掌握了就你可以使用连接多种数据库。

bind

php_mysql不能 Bind Column ,以前例的 SQL 叙述来说,$location 的地方容易被 SQL Injection。后来于是发展出了 mysql_escape_string() (备注:5.3.0之后弃用) 以及 mysql_real_escape_string()来解决这个问题,不过这麽一搞,整个叙述会变得複杂且丑陋,而且如果栏位多了,可以想见会是怎样的 情形.

在 PHP-MySQLi 中有了不少进步,除了透过 Bind Column 来解决上述问题,而且也多援 Transaction, Multi Query ,

并且同时提供了 Object oriented style (下面这段 PHP-MySQLi 范例的写法) 和 Procedural style

直观对比

特性、指标 PHP的mysqli扩展 PDO (使用PDO MySQL驱动和MySQL Native驱动) PHP的mysql扩展
引入的PHP版本 5.0 5.0 3.0之前
PHP5.x是否包含
MySQL开发状态 活跃 在PHP5.3中活跃 仅维护
在MySQL新项目中的建议使用程度 建议 建议 不建议
API的字符集支持
服务端prepare语句的支持情况
客户端prepare语句的支持情况
存储过程支持情况
多语句执行支持情况 大多数
是否支持所有MySQL4.1以上功能 大多数
参数命名 不支持 支持 不支持
API 编程范式 OOP + 函数式 OOP 函数式
对象映射(Object Mapping) 不支持 支持 不支持

结语

其实从php_mysql, mysqli,pdo_mysql 得过渡就可以看到php自己的设计哲学,不要以很强硬的方式推倒以前的,要慢慢过渡,设计规则让用户慢慢适应。php_mysql->mysqli->pod_mysql, 从过程编码到过程和OOP兼得的mysqli,再到纯OOP的pdo_mysql. 慢慢得大家都用pdo了,mysql也淡出了php的版本。

MacOS 下 Docker 容器内挂载的文件内外不一致问题

Docker挂载的文件,在外部修改后,容器内不生效问题

问题

MacOS,装了vbox,在里面运行的Docker,拉了一个 openresty-alpine镜像,发现volume挂载的文件,通过tail -n 100 /usr/share/nginx/xx.lua, 和 cat /usr/share/nginx/xx.lua 两个命令展示的结果不一致。

我想大家也会有类似的,在IDE编辑了代码,发现Docker容器内的文件没变化这样的问题。

解决否

已解决

方案

version: "2"
services:
    php:
        image: php
        volumes:
            - /mnt/vbox/compose/bs/php/:/var/www/html/:rw,cached

最简单粗暴的就是在rw后面加上cached,至于原因,见下面的官方解释,以及国内大牛讲解。

官方解释:link

国内大佬的总结:blog

MySQL 查询优化,explain 各个字段指标说明

MySQL explain 优化sql时,你知道 select_type, type, possible_keys, key, key_len,ref, row, Extra 这些个字段是代表什么意思?那就来看看吧

explain

别名:desc

例子些

  • 例子1:
select * from `tuanmei_deals` where deal_id = 23421;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE tuanmei_deals const PRIMARY PRIMARY 4 const 1 NULL

例子2:

select * from `tuanmei_deals` where ( `end_time` > '1592234464' ) limit 2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE tuanmei_deals range end_time end_time 4 NULL 234142 Using index condition; Using MRR
  • 例子3:
select * from `tuanmei_deals` where hash_id = 'ht2020517p51688' or ( `end_time` > '1592234464' ) limit 2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE tuanmei_deals index_merge hash_id,end_time,idx_HashId_StartTm hash_id,end_time 32,4 NULL 234143 Using sort_union(hash_id,end_time); Using where

id, table

Id 就不说了,table就是你查阅了哪个表,key就是实际用到的索引

select_type

查询类型,就是我们从sql语法角度来看,会被拆封成什么任务

(1) SIMPLE(简单SELECT,不使用UNION或子查询等), 比如上面的一个单表查询

(2) PRIMARY(查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY)

(3) UNION(UNION中的第二个或后面的SELECT语句) 如果你使用了union了多个select 集合

(4) DEPENDENT UNION(UNION中的第二个或后面的SELECT语句,取决于外面的查询)

(5) UNION RESULT(UNION的结果)

(6) SUBQUERY(子查询中的第一个SELECT), 例如你用到了 where in (select )

(7) DEPENDENT SUBQUERY(子查询中的第一个SELECT,取决于外面的查询)

(8) DERIVED(派生表的SELECT, FROM子句的子查询)

(9) UNCACHEABLE SUBQUERY(一个子查询的结果不能被缓存,必须重新评估外链接的第一行)

type

ALL:Full Table Scan, MySQL将遍历全表以找到匹配的行

index: Full Index Scan,index与ALL区别为index类型只遍历索引树

range:只检索给定范围的行,使用一个索引来选择行

ref: 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值

eq_ref: 类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件。触发条件:只匹配到一行的时候。除了system和const之外,这是最好的连接类型了。当我们使用主键索引或者唯一索引的时候,且这个索引的所有组成部分都被用上,才能是该类型。

const、system: 当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量,system是const类型的特例,当查询的表只有一行的情况下,使用system。system的触发条件:表只有一行,这是一个const type 的特殊情况。

NULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。

possible_keys

指出MySQL能使用哪个索引在表中找到记录,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用

key列显示MySQL实际决定使用的键(索引)

key

如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。

key_len

表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度(key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的)

不损失精确性的情况下,长度越短越好。

key_len 表示一行数据该索引占用的数据宽度,比如对一个 字段类型为 int 建立索引,那么索引的key_len 就是 4。和数量多少没有关系。

ref

显示索引的哪一列被使用了,如果可能的话,是一个常数

表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值

rows

表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数, 注意:这是预估值,非实际值

Extra

该列包含MySQL解决查询的详细信息

  • Using index:表示使用索引,如果只有 Using index,说明他没有查询到数据表,只用索引表就完成了这个查询,这个叫覆盖索引。如果同时出现Using where,代表使用索引来查找读取记录, 也是可以用到索引的,但是需要查询到数据表。
  • Using where:表示条件查询,如果不读取表的所有数据,或不是仅仅通过索引就可以获取所有需要的数据,则会出现 Using where。如果type列是ALL或index,而没有出现该信息,则你有可能在执行错误的查询:返回所有数据。
  • Using MRR:MMR全称是Multi-Range Read,是MYSQL5.6优化器的一个新特性,在MariaDB5.5也有这个特性。优化的功能在使用二级索引做范围扫描的过程中减少磁盘随机IO和减少主键索引的访问次数。将随机IO转换为顺序IO
  • Using filesort:不是“使用文件索引”的含义!filesort是MySQL所实现的一种排序策略,通常在使用到排序语句ORDER BY的时候,会出现该信息。
  • Using temporary:表示为了得到结果,使用了临时表,这通常是出现在多表联合查询,结果排序的场合。

MRR和没有MRR的区别

给出一个简单的例子,在innodb表执行下面的查询:

SELECT non_key_column FROM tbl WHERE key_column=x

在没有MRR的情况下,它是这样得到结果的:

1.  select key_column, pk_column from tb where key_column=x order  by key_column ---> 假设这个结果集是t2.  for each row in t ; 
select non_key_column from tb where pk_column = pk_column_value。(在oracle里第2步叫回表)在有MRR的情况下,它是这样执行的:
1.  select key_column, pk_column from tb where key_column = x  order by key_column ---> 假设这个结果集是t
2.  将结果集t放在buffer里面(直到buffer满了),然后对结果集t按照pk_column排序 ---> 假设排序好的结果集是t_sort
3.  select non_key_column fromtb where pk_column in (select pk_column from t_sort)

两者的区别主要是两点:

  1. 没有MRR的情况下,随机IO增加,因为从二级索引里面得到的索引元组是有序,但是他们在主键索引里面却是无序的,所以每次去主键索引里面得到non_key_column的时候都是随机IO。(如果索引覆盖,那也就没必要利用MRR的特性了,直接从索引里面得到所有数据)

  2. 没有MRR的情况下,访问主键索引的次数增加。没有MRR的情况下,二级索引里面得到多少行,那么就要去访问多少次主键索引(也不能完全这样说,因为mysql实现了BNL),而有了MRR的时候,次数就大约减少为之前次数t/buffer_size。

关于 Explain 的相关注意事项

总结:
– • EXPLAIN不会告诉你关于触发器、存储过程的信息或用户自定义函数对查询的影响情况
– • EXPLAIN不考虑各种Cache
– • EXPLAIN不能显示MySQL在执行查询时所作的优化工作
– • 部分统计信息是估算的,并非精确值
– • EXPALIN只能解释SELECT操作,其他操作要重写为SELECT后查看执行计划。

show profile

show profile作用:
能够查出最近15条SQL语句的运行状态(包含运行过程中执行了哪些操作,各占用了多长时间),以便开发者的分析。

1、查看MySQL的版本是否支持show profie
2、查看是否已经开启show profile

$ SHOW VARIABLES LIKE 'profiling';

3、开启功能,默认是关闭
SET profiling=ON;
SHOW VARIABLES LIKE ‘profiling’;

4、运行sql
随便运行几条SQL,以便于show prifiles的日志分析。
5、查看结果
show profiles;

6、诊断SQL
用于单独分析某条sql,查看某条sql的生命周期以及各占用多少时间。
SHOW PROFILE cpu, block io FOR QUERY id;
id为show profiles查出来的某条记录的id


set profiling=1; //打开分析 run your sql1; run your sql2; show profiles; //查看sql1,sql2的语句分析 show profile for query 1; //查看sql1的具体分析 show profile ALL for query 1; //查看sql1相关的所有分析【主要看i/o与cpu,下边分析中有各项意义介绍】 set profiling=0; //关闭分析

引用

  • https://mengkang.net/1124.html
  • https://www.cnblogs.com/fu-yong/p/8496368.html
  • https://www.cnblogs.com/kubidemanong/p/10734045.html
  • https://blog.csdn.net/liang_0609/article/details/44040357
  • https://zhuanlan.zhihu.com/p/100427746
  • https://blog.csdn.net/mingover/article/details/79066064
  • https://www.tuicool.com/articles/ZFrUzia
  • https://blog.csdn.net/lihuayong/article/details/42044593
  • https://www.cnblogs.com/xuanzhi201111/p/4175635.html

WordPress 禁用feeds订阅

我用的百度BCE搭建的该站点,这天它检查我的站点后,告知我一个安全隐患,吓我一跳,赶紧解决啊

因何而起

百度检查我的站点发现一个安全隐患:

http://blog.itjsz.com/?cat=http%3A%2F%2Fcirt.net%2Frfiinc.txt&feed=rss2

其实呢,这就是一个rss订阅功能,作为一个小博主,没有必要。

设置

这里可以限制feed输出,但不能完全限制。

wordpress setting

插件禁用

有个插件 disable feeds

disable feeds

好久没更新了,不知能用不。

手动改代码

这里需要改动,你正在使用的主题文件。

<?php
// WordPress/wp-content/themes/xxx/function.php
function wpjam_disable_feed() {
    wp_die(__('<h1>本博客不再提供 Feed,请访问网站<a href="'.get_bloginfo('url').'">首页</a>!</h1>'));
}
add_action('do_feed',      'wpjam_disable_feed', 1);
add_action('do_feed_rdf',  'wpjam_disable_feed', 1);
add_action('do_feed_rss',  'wpjam_disable_feed', 1);
add_action('do_feed_rss2', 'wpjam_disable_feed', 1);
add_action('do_feed_atom', 'wpjam_disable_feed', 1);

没有生效,尝试切换主题,多刷新试试。

Mac Homebrew 使用

HomeBrew 是 MacOS 上使用非常广泛的包管理工具. 他有着自由开放特点,广受喜爱。作为程序员,它太好用了,必须学会使用brew

是什么

HomeBrew 是 MacOS 上使用非常广泛的包管理工具. 他有着自由开放特点,广受喜爱。

好比 Debian 上的 apt-get, CentOS 上的 yum。

安装

## 官方推荐的默认安装方式
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"

## 手动安装方式
$ mkdir homebrew && curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C homebrew

试试看,安装好没有。

## 检查版本
$ brew -v

通过brew安装的文件会自动设置环境变量,所以不用担心命令行不能启动的问题。 比如安装好了gradle,即可运行 gradle -v。

包管理

HomeBrew 软件的命令入口是 brew.

注意,使用HomeBrew软件不要加上sudo权限,哪怕是有报错,或者提示没有权限覆盖系统自带软件,也不要加sudo!

## 检查版本
$ brew -v

## 帮助
$ brew --help

## 安装一个软件
$ brew install wget

## 卸载软件
$ brew uninstall wget

## 通过 *.rb 文件的方式安装软件,如:mpv
$ wget https://raw.githubusercontent.com/Homebrew/homebrew-core/master/Formula/mpv.rb
$ brew install ./mpv.rb

## 搜索软件 vim
$ brew search vim

升级软件

## 升级 HomeBrew
$ brew update

## 升级所有已过时的软件,(这里软件指,通过brew安装的软件)
$ brew upgrade

## 指定升级某个软件
$ brew upgrade python

## 升级所有软件包,包裹未清理干净的旧版本包
$ brew upgrade --all
  • 不让某些包的升级
## 锁住 git,不让其更新
$ brew pin git

## 解锁 git
$ brew unpin git

卸载 & 清理

## 清理所有旧版本的软件包
$ brew cleanup

## 
$ brew cleanup -n

## 清理具体的一个包 node
$ brew cleanup node

## 强制卸载,不管依赖
$ brew unistall <fromula> --force

## 移除软件包
$ brew remove <fromula> 

查看

HomeBrew 安装的软件会放到文件夹 /usr/local/Cellar/ 下.

## 查看已安装列表
$ brew list

## 查看一个具体软件信息, 如 nginx
$ brew info nginx

## 查看各个包的依赖关系
$  brew deps

## 查看已安装的包的依赖,树形显示
$ brew deps --installed --tree

通过依赖关系,就能知道哪些包还在使用。

为 HomeBrew 软件,新增图标

$ brew linkapps mpv

HomeBrew 管理

自检

如果你的 Hombrew 没有办法正常的工作,你可以执行 brew doctor 来开启 Homebrew 自带的检查,从而确认有哪些问题,并进行修复。

服务

诸如 Nginx、MySQL 等软件,都是有一些服务端软件在后台运行,如果你希望对这些软件进行管理,可以使用 brew services 命令来进行管理

好比是 Linux 上的 systemctl

## 查看所有服务
$ brew services list

## 单次运行某个服务 nginx
$ brew services run nginx

## 运行某个服务,并设置开机自动运行。 sleepwatcher
$ brew services start sleepwatcher 

## 停止某个服务 nginx
$ brew services stop nginx

## 重启某个服务 nginx
$ brew services restart nginx

HomeBrew 加速

换源

  • 中科大 镜像
cd "$(brew --repo)"
git remote set-url origin git://mirrors.ustc.edu.cn/brew.git
cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"
git remote set-url origin git://mirrors.ustc.edu.cn/homebrew-core.git
  • 清华大学 镜像
git -C "$(brew --repo)" remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/brew.git

git -C "$(brew --repo homebrew/core)" remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/homebrew-core.git

网络代理

brew支持全局socks代理,使用前打开终端,加上这一句:


$ export ALL_PROXY=socks5://127.0.0.1:port ## 或者仅这条命令使用代理 $ ALL_PROXY=socks5://127.0.0.1:port brew upgrade

结语

(完)