预定义常量
数据类型
//布尔数据类型
PDO::PARAM_BOOL
//NULL数据类型
PDO::PARAM_NULL
//整型
PDO::PARAM_INT
//CHAR、VARCHAR或其他字符串类型
PDO::PARAM_STR
//标记了字符使用的是国家字符集(national character set)。 自 PHP 7.2.0 起。
PDO::PARAM_STR_NATL
//标记了字符使用的是常规字符集(regular character set)。 自 PHP 7.2.0 起。
PDO::PARAM_STR_CHAR
//表示 SQL 中大对象数据类型。
PDO::PARAM_LOB
//表示一个记录集类型。当前尚未被任何驱动支持。
PDO::PARAM_STMT
//指定参数为一个存储过程的 INOUT 参数。必须用一个明确的 PDO::PARAM_* 数据类型跟此值进行按位或
PDO::PARAM_INPUT_OUTPUT
//强制以字符串方式对待所有的值
PDO::ATTR_STRINGIFY_FETCHES
获取方式
//将结果集中的每一行作为一个对象返回,此对象的变量名对应着列名,在PDOStatement::fetchAll()中无效
PDO::FETCH_LAZY
//将对应结果集中的每一行作为一个由列名索引的数组返回。如果结果集中包含多个名称相同的列,则PDO::FETCH_ASSOC每个列名只返回一个值
PDO::FETCH_ASSOC
//将对应结果集中的每一行作为一个由列名索引的数组返回。如果结果集中包含多个名称相同的列,则PDO::FETCH_ASSOC每个列名返回一个包含值的数组
PDO::FETCH_NAMED
//将对应结果集中的每一行作为一个由列号索引的数组返回,从第0列开始
PDO::FETCH_NUM
//将对应结果集中的每一行作为一个由列号和列名索引的数组返回,从第0列开始
PDO::FETCH_BOTH
//将结果集中的每一行作为一个属性名对应列名的对象返回
PDO::FETCH_OBJ
//从结果集中的下一行返回所需要的那一列
PDO::FETCH_COLUMN
//返回一个所请求类的新实例,映射列到类中对应的属性名
PDO::FETCH_CLASS
//更新一个请求类的现有实例,映射列到类中对应的属性名
PDO::FETCH_INTO
//允许在运行中完全用自定义的方式处理数据。(仅在 PDOStatement::fetchAll() 中有效),参数为字段的值(多少个字段,多少个参数),没有字段名
PDO::FETCH_FUNC
//根据值分组返回。通常和 PDO::FETCH_COLUMN 或 PDO::FETCH_KEY_PAIR 一起使用
PDO::FETCH_GROUP
//获取一个有两列的结果集到一个数组,其中第一列为键名,第二列为值
PDO::FETCH_KEY_PAIR
列名
//保留数据库驱动返回的列名
PDO::CASE_NATURAL
//强制列名小写
PDO::CASE_LOWER
//强制列名大写
PDO::CASE_UPPER
游标
//获取或设置使用游标的名称。当使用可滚动游标和定位更新时候非常有用
PDO::ATTR_CURSOR_NAME
//选择游标类型。 PDO 当前支持 PDO::CURSOR_FWDONLY 和 PDO::CURSOR_SCROLL。一般为 PDO::CURSOR_FWDONLY,除非确实需要一个可滚动游标
PDO::ATTR_CURSOR
//在结果集中获取下一行。仅对可滚动游标有效。
PDO::FETCH_ORI_NEXT
//在结果集中获取上一行。仅对可滚动游标有效。
PDO::FETCH_ORI_PRIOR
//在结果集中获取第一行。仅对可滚动游标有效。
PDO::FETCH_ORI_FIRST
//在结果集中获取最后一行。仅对可滚动游标有效。
PDO::FETCH_ORI_LAST
/根据行号从结果集中获取需要的行。仅对可滚动游标有效。
PDO::FETCH_ORI_ABS
//根据当前游标位置的相对位置从结果集中获取需要的行。仅对可滚动游标有效。
PDO::FETCH_ORI_REL
//创建一个只进游标的 PDOStatement 对象。此为默认的游标选项,因为此游标最快且是 PHP 中最常用的数据访问模式。
PDO::CURSOR_FWDONLY
//创建一个可滚动游标的 PDOStatement 对象。通过 PDO::FETCH_ORI_* 常量来控制结果集中获取的行。
PDO::CURSOR_SCROLL
事件
//分配事件
PDO::PARAM_EVT_ALLOC
/解除分配事件
PDO::PARAM_EVT_FREE
//执行一条预处理语句之前触发事件。
PDO::PARAM_EVT_EXEC_PRE
//执行一条预处理语句之后触发事件。
PDO::PARAM_EVT_EXEC_POST
//从一个结果集中取出一条结果之前触发事件。
PDO::PARAM_EVT_FETCH_PRE
//从一个结果集中取出一条结果之后触发事件。
PDO::PARAM_EVT_FETCH_POST
//在绑定参数注册允许驱动程序正常化变量名时触发事件
PDO::PARAM_EVT_NORMALIZE
超时
//设置连接数据库的超时秒数
PDO::ATTR_TIMEOUT
持久连接
//请求一个持久连接,而非创建一个新连接
PDO::ATTR_PERSISTENT
错误
//对应 SQLSTATE '00000',表示 SQL 语句没有错误或警告地成功发出。当用 PDO::errorCode() 或 PDOStatement::errorCode() 来确定是否有错误发生时,此常量非常方便
PDO::ERR_NONE
//如果发生错误,则不显示错误或异常。希望开发人员显式地检查错误。此为默认模式
PDO::ERRMODE_SILENT
//如果发生错误,则显示一个 PHP E_WARNING 消息
PDO::ERRMODE_WARNING
//如果发生错误,则抛出一个 PDOException 异常
PDO::ERRMODE_EXCEPTION
PDO类
创建连接
//创建一个表示数据库连接的PDO实例
PDO::__construct(string $dsn , string $username = ? , string $password = ? , array $driver_options = ? )
一个 DSN 由 PDO 驱动名、紧随其后的冒号、以及具体 PDO 驱动的连接语法组成。
设置属性
//设置属性
PDO::setAttribute(int $attribute , mixed $value):bool
//返回一个数据库连接的属性值,失败返回null
PDO::getAttribute(int $attribute):mixed
attribute PDO::ATTR_* 常量中的一个
为sql语句中字符串添加引号
//为SQL查询里的字符串添加引号
PDO::quote(string $string , int $parameter_type = PDO::PARAM_STR):string
string 要添加引号的字符串。
parameter_type 为驱动提示数据类型,以便选择引号风格
执行语句
//执行一条 SQL 语句,并返回受影响的行数
PDO::exec(string $statement):int
//执行SQL语句,以PDOStatement对象形式返回结果集
PDO::query(string $statement):PDOStatement
//准备要执行的语句,并返回语句对象
PDO::prepare(string $statement , array $driver_options = array()):PDOStatement
statement 必须是对目标数据库服务器有效的 SQL 语句模板
driver_options 数组包含一个或多个 key=>value 键值对,为返回的 PDOStatement 对象设置属性。 常见用法是:设置 PDO::ATTR_CURSOR 为 PDO::CURSOR_SCROLL,将得到可滚动的光标。
获取最后插入行的ID
//返回最后插入行的ID或序列值,如果没有为参数name指定序列名称,则返回一个表示最后插入数据库那一行的行ID的字符串
PDO::lastInsertId(string $name = null):string
name 应该返回ID的那个序列对象的名称
事务
//启动一个事务
PDO::beginTransaction():bool
//提交事务
PDO::commit():bool
//回滚一个事务
PDO::rollBack():bool
驱动
//返回一个可用驱动的数组
PDO::getAvailableDrivers():array
//检查驱动内的一个事务当前是否处于激活。此方法仅对支持事务的数据库驱动起作用。
PDO::inTransaction():bool
状态与错误
//获取跟数据库句柄上一次操作相关的 SQLSTATE
PDO::errorCode():mixed
//获取与数据库句柄上的最后一个操作关联的扩展错误信息
PDO::errorInfo():array
PDOStatement类
代表一条预处理语句,并在该语句被执行后代表一个相关的结果集
预处理语句
//绑定一个PHP变量到用作预处理的SQL语句中的对应命名占位符或问号占位符。
PDOStatement::bindParam(mixed $parameter , mixed &$variable , int $data_type = PDO::PARAM_STR , int $length = ? , mixed $driver_options = ?):bool
parameter 参数标识符。对于使用命名占位符的预处理语句,应是类似 :name 形式的参数名。对于使用问号占位符的预处理语句,应是以1开始索引的参数位置。
variable 绑定到 SQL 语句参数的 PHP 变量名。
data_type 使用 PDO::PARAM_* 常量明确地指定参数的类型。要从一个存储过程中返回一个 INOUT 参数,需要为 data_type 参数使用按位或操作符去设置 PDO::PARAM_INPUT_OUTPUT 位。
length 数据类型的长度。为表明参数是一个存储过程的 OUT 参数,必须明确地设置此长度。
driver_options
//绑定一个值到用作预处理的 SQL 语句中的对应命名占位符或问号占位符
PDOStatement::bindValue(mixed $parameter , mixed $value , int $data_type = PDO::PARAM_STR):bool
parameter 参数标识符。对于使用命名占位符的预处理语句,应是类似 :name 形式的参数名。对于使用问号占位符的预处理语句,应是以1开始索引的参数位置。
value 绑定到参数的值
data_type 使用 PDO::PARAM_* 常量明确地指定参数的类型
//执行预处理过的语句。如果预处理过的语句含有参数标记,必须选择下面其中一种做法
调用 PDOStatement::bindParam()绑定 PHP 变量到参数标记:如果有的话,通过关联参数标记绑定的变量来传递输入值和取得输出值
传递一个只作为输入参数值的数组
PDOStatement::execute(array $input_parameters = ?):bool
input_parameters 一个元素个数和将被执行的 SQL 语句中绑定的参数一样多的数组。所有的值作为PDO::PARAM_STR对待。不能绑定多个值到一个单独的参数;比如,不能绑定两个值到 IN()子句中一个单独的命名参数。绑定的值不能超过指定的个数
//直接打印出一条预处理语句包含的信息。提供正在使用的 SQL 查询、所用参数(Params)的数目、参数的清单、参数名、用一个整数表示的参数类型(paramtype)、键名或位置、值、以及在查询中的位置(如果当前 POD 驱动不支持,则为-1)。用于调试的功能,在正常输出的情况下直接输出数据
PDOStatement::debugDumpParams():bool
返回结果集
//返回结果集中的列数
PDOStatement::columnCount():int
//从结果集中获取下一行数据,fetch_style 参数决定 POD 如何返回行;失败返回 false
PDOStatement::fetch(int $fetch_style = ? , int $cursor_orientation = PDO::FETCH_ORI_NEXT , int $cursor_offset = 0 ):mixed
fetch_style 此值必须是 PDO::FETCH_* 系列常量中的一个,默认为PDO::FETCH_BOTH
cursor_orientation 对于 一个 PDOStatement 对象表示的可滚动游标,该值决定了哪一行将被返回给调用者。此值必须是 PDO::FETCH_ORI_* 系列常量中的一个,默认为 PDO::FETCH_ORI_NEXT。要想让 PDOStatement 对象使用可滚动游标,必须在用 PDO::prepare()预处理SQL语句时,设置 PDO::ATTR_CURSOR 属性为 PDO::CURSOR_SCROLL
offset 对于一个 cursor_orientation 参数设置为 PDO::FETCH_ORI_ABS 的PDOStatement 对象代表的可滚动游标,此值指定结果集中想要获取行的绝对行号。
//返回一个包含结果集中所有行的数组
PDOStatement::fetchAll(int $fetch_style = ? , mixed $fetch_argument = ? , array $ctor_args = array()):array
fetch_style 此值必须是 PDO::FETCH_* 系列常量中的一个,默认为PDO::FETCH_BOTH
fetch_argument 根据 fetch_style 参数的值,此参数有不同的意义
PDO::FETCH_COLUMN:返回指定以0开始索引的列。
PDO::FETCH_CLASS:返回指定类的实例,映射每行的列到类中对应的属性名。
PDO::FETCH_FUNC:将每行的列作为参数传递给指定的函数,并返回调用函数后的结果
ctor_args 当 fetch_style 参数为 PDO::FETCH_CLASS 时,自定义类的构造函数的参数
//从结果集中的下一行返回单独的一列,没有返回false
PDOStatement::fetchColumn(int $column_number = 0 ):string
column_number 你想从行里取回的列的索引数字(以0开始的索引)。如果没有提供值,则获取第一列。
//获取下一行并作为一个对象返回。
PDOStatement::fetchObject(string $class_name = "stdClass" , array $ctor_args = ?):mixed
class_name 创建类的名称。
ctor_args 此数组的元素被传递给构造函数
获取语句影响行数
//返回受上一个 SQL 语句影响的行数
PDOStatement::rowCount():int
状态和错误
//获取跟上一次语句句柄操作相关的 SQLSTATE
PDOStatement::errorCode():string
//获取跟上一次语句句柄操作相关的扩展错误信息
PDOStatement::errorInfo():array
其他
//释放到数据库服务的连接,以便发出其他 SQL 语句,但使语句处于一个可以被再次执行的状态;当上一个执行的 PDOStatement 对象仍有未取行时,此方法对那些不支持再执行一个 PDOStatement 对象的数据库驱动非常有用。 如果数据库驱动受此限制,则可能出现失序错误的问题。
PDOStatement::closeCursor():bool
异常类PDOException
DSN
sqlite:/opt/databases/mydb.sq3
sqlite::memory:
sqlite:
mysql:host=xxx;port=xxx;dbname=xxx;charset=xxx
sqlsrv:Server=localhost,hostport;Database=databasename
示例
//建立一个持久化连接
$dbh = new PDO('mysql:host=xxx;port=xxx;dbname=xxx', $user, $pass, array(PDO::ATTR_PERSISTENT => true));
mysqlnd
MySQL本机驱动程序是MySQL客户端库(libmysqlclient)的替代品,与使用MySQL客户端库相比,使用MySQL本机驱动程序具有许多优势
1、过去,您需要针对MySQL客户端库的副本构建MySQL数据库扩展。这通常意味着您需要在构建PHP源代码的计算机上安装MySQL。同样,当您的PHP应用程序运行时,MySQL数据库扩展将在运行时调用MySQL客户端库文件,因此需要在系统上安装该文件。使用MySQL Native Driver不再是这种情况,因为它已包含在标准发行版中。因此,您不需要安装MySQL即可构建PHP或运行PHP数据库应用程序。
2、由于MySQL本机驱动程序是作为PHP扩展编写的,因此它与PHP的工作紧密相关。由于驱动程序使用PHP内存管理系统,因此可以提高效率,尤其是在内存使用方面。它还支持PHP内存限制。与使用MySQL客户端库相比,使用MySQL本机驱动程序可获得可比的性能或更好的性能,它始终可以确保最有效地使用内存。内存效率的一个例子是,当使用MySQL客户端库时,每行在内存中存储两次,而对于MySQL Native Driver,每行仅在内存中存储一次。
安装
在Unix上安装:为了使用MySQL本机驱动程序,需要构建PHP,指定使用MySQL本机驱动程序支持编译MySQL数据库扩展。这是在构建PHP源代码之前通过配置选项完成的。
./configure --with-mysql = mysqlnd \
--with-mysqli = mysqlnd \
--with-pdo-mysql = mysqlnd \
在Windows上安装:在正式的PHP Windows发行版中,默认情况下启用了MySQL本机驱动程序,因此不需要其他配置即可使用它。
mysqlnd_ms
Mysqlnd主从复制和负载均衡插件
Mysql 主从复制和负载均衡插件 (mysqlnd_ms) 可以帮助我们很简单的支 持所有使用 mysqlnd 的 PHP MySQL 扩展(mysqli, mysql, PDO_MYSQL)
限制
内置的读写分离机制非常基础, 任何一个以 SELECT 开头的查询, 都被认为是读操作, 从而发送给 slave 服务器. 所有其他的查询 (包括 SHOW) 都会被认为是写操作, 而被发送给 master 服务器.
读写分离不能提供对于多查询的结构支持, 多查询结果会被认为是一个单一查询. 通过开头的字符串来决定如何执行这些查询. 例如, 如果使用 mysqli_multi_query() 执行多查询 SELECT id FROM test; INSERT INTO test(id) VALUES (1) 将会被认为是一个查询操作, 而被发送给 slave 服务器, 以为他开头使用了 SELECT. 其中的 INSERT 结构,将不会被发送给 master 服务器
启用插件
mysqlnd_ms.enable=1
mysqlnd_ms.config_file=/path/to/mysqlnd_ms_plugin.ini
配置插件
插件使用他自己的配置文件,使用 PHP 指令 mysqlnd_ms.config_file 定义插件配置文件的完整路径,在 mysqlnd_ms.config_file 指定的目录中,创建保存插件的配置文件
插件的 配置文件 基于 JSON 格式。 配置写在一个或者多个章节中。每个章节都包含一个名称,例如: myapp。 每个章节包含自己的配置信息
一个章节的配置中,至少要包含 MySQL 主从复制中的 master 服务器和相关 slave 服务器。 每个章节只能使用一个 master 服务器。 目前还不能完全支持多 master(Multi-master)的设置。 master 用于设定 MySQL master 服务器的 hostname、port 或 socket。 而 MySQL slave 服务器信息使用 slave 来设定。必须配置 MySQL slave 服务器列表
{
"myapp": {
"master": {
"master_0": {
"host": "localhost",
"socket": "\/tmp\/mysql.sock"
}
},
"slave": {
"slave_0": {
"host": "192.168.2.27",
"port": "3306"
}
}
}
}
示例:开启负载均衡连接
/* 根据配置针对 myapp 开启一个负载均衡的链接 */
$mysqli = new mysqli("myapp", "username", "password", "database");
$pdo = new PDO('mysql:host=myapp;dbname=database', 'username', 'password');
$mysql = mysql_connect("myapp", "username", "password");
SQL Hints (SQL 优化器)
SQL 优化器可以强行指定连接池中特定的链接。可以给定插件一个优化器去使用特定的服务器连接, 这样可以解决由于链接切换引起的链接状态变化问题。
插件支持 SQL hints,MYSQLND_MS_MASTER_SWITCH指定语句在 master 上运行,MYSQLND_MS_SLAVE_SWITCH 指定在 slave 上运行,MYSQLND_MS_LAST_USED_SWITCH指定语句在上一条语句执行的 slave 上运行
插件会扫描语句的内容,查询是否有 SQL hints。他只能在语句的开头被识别
示例
$mysql->query("SET @myrole='master'");
$mysql->query(sprintf("/*%s*/SELECT @myrole AS _role", MYSQLND_MS_LAST_USED_SWITCH));
事务
当前版本的插件并不是事务安全的,因为他并没有识别全部的事务操作。 SQL 事务单元是在单一服务器中运行的。插件并不能有效的知道事务单元 何时开始,何时终止。所以,在事务单元中,可能数据库连接会被切换。可以通过 SQL hints 来解除这个限制。可以选择性的调用事务 API 进行监控, 然后调用 API 执行控制事务。
从 PHP 5.4.0 版本开始,调用 API autocommit 模式,插件设定中有 trx_stickiness=master, 那么插件将在事务中自动禁止负载均衡和连接切换。在 autocommit 禁用的配置当中, 插件将在事务过程中将所有的语句发送给 master,禁用负载均衡。当 autocommit 重新启用以后,插件将重新开始负载均衡所有的语句。
服务级别和一致性
不同类型的 MySQL 群组提供了,不同的服务和数据一致性级别。异步的 MySQL 主从同步 提供最终的数据一致性,一个读操作是否能够得到当前的数据、状态,一类与 slave 是否已经从 master 获取了最后的更新。从 1.2.0 版本开始,插件能够自动的进行 MySQL 主从同步的节点,来完成 session 一致性 或者完成很强的一致性要求。session 一致性是指一个客户端可以读取他的写入内容, 其他客户端可能不能看到他的写入内容。很强的一致性要求是指所有客户端都能够看到 其他所有客户端的写入内容。
示例
在运行时使用 mysqlnd_ms_set_qos() 设定服务级别
/* 使用 master 完成读写分离 */
if (!$mysqli->query("INSERT INTO orders(order_id, item) VALUES (1, 'christmas tree, 1.8m')")) {
/* Please use better error handling in your code */
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
}
/* 要求 session 一致性,读取写入内容 */
if (!mysqlnd_ms_set_qos($mysqli, MYSQLND_MS_QOS_CONSISTENCY_SESSION))
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
/* 插件选择一个改变数据的节点,这里是 master */
if (!$res = $mysqli->query("SELECT item FROM orders WHERE order_id = 1"))
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
/* 返回到最终数据一致性状态,允许陈旧数据 */
if (!mysqlnd_ms_set_qos($mysqli, MYSQLND_MS_QOS_CONSISTENCY_EVENTUAL))
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
/* 插件选择任何一个 slaver 完成允许陈旧数据的读取 */
if (!$res = $mysqli->query("SELECT item, price FROM specials"))
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
服务级别写在插件的配置文件中
{
"myapp": {
"master": {
"master_0": {
"host": "localhost",
"socket": "\/tmp\/mysql.sock"
}
},
"slave": {
"slave_0": {
"host": "127.0.0.1",
"port": "3306"
}
},
"failover" : "master"
}
}
限制 slave 延迟
/* 若 slave 延迟不超过 4 秒,则从 Slave 读取 */
$ret = mysqlnd_ms_set_qos($mysqli,
MYSQLND_MS_QOS_CONSISTENCY_EVENTUAL,
MYSQLND_MS_QOS_OPTION_AGE, 4);
/* 选择一个 slave,他可能没有改变 */
if (!$res = $mysqli->query("SELECT item, price FROM daytrade"))
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
/* 恢复默认状态,使用所有的 slave 和 master */
if (!mysqlnd_ms_set_qos($mysqli, MYSQLND_MS_QOS_CONSISTENCY_EVENTUAL))
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
最终一致性服务级别可以使用一个可选的参数设定最大允许的延迟,用于选择 slave。 如果设定这个值,插件会检查所有 slave 的 SHOW SLAVE STATUS。 在范例中,只有满足 Slave_IO_Running=Yes, Slave_SQL_Running=Yes 和 Seconds_Behind_Master <= 4 的 slave 会被执行语句 SELECT item, price FROM daytrade。在应用运行时,会透明的执行 SHOW SLAVE STATUS 命令。 任何错误会以 warning 的方式报警,但是错误信息不会被保存在连接中。 即使所有的 SHOW SLAVE STATUS 都失败了,用户的执行请求也不会被终止, 给定的 master 作为最后的选择。然而应用不需要做任何调整。
注意:在任何程序的开始,对所有的 slave 进行 SHOW SLAVE STATUS 查询,是一个非常耗时和缓慢的操作。不要经常这样操作。MySQL 主从同步集群并没有 提供一个客户端从一个中心控制器获取备选方案的能力。 然而,没有更多有效的方式获取 slave 延迟。
分区和分片
MySQL 主从同步支持过滤方式的分区,他可以让你创建所有数据库同步,或者部分数据库同步。 这样就要求应用能够拥有同样的策略,你可以通过 node_groups 手动的支持这个策略,或者使用实验性质的表过滤器。
以使用一个节点群组用于共享,并且使用使用群组名称作为一个地址共享, 就像 Shard_A_Range_0_100
{
"myapp": {
"master": {
"master_0": {
"host": "localhost",
"socket": "\/tmp\/mysql.sock"
}
},
"slave": {
"slave_0": {
"host": "simulate_slave_failure",
"port": "0"
},
"slave_1": {
"host": "127.0.0.1",
"port": 3311
}
},
"filters": {
"node_groups": {
"Partition_A" : {
"master": ["master_0"],
"slave": ["slave_0"]
}
},
"roundrobin": []
}
}
}
通过 SQL hints 完成手动分区
$mysqli->query("/*Partition_A*/" . sprintf("SELECT CONNECTION_ID() AS _thread, '%s' AS _hint FROM DUAL", $msg));
默认的,插件使用所有配置的 master 和 slave 进行查询操作。但是如果一个查询,使用 /*node_group*/ 的 SQL hint,那么插件将只使用在 node_group 列出的服务器进行查询操作。所以,SELECT 查询操作,只会在 /*Partition_A*/ 列出的 slave_0 中进行。
MySQL Fabric
是一个用于管理MySQL服务器场以实现高可用性并可选地支持分片的系统。从技术上讲,它是管理和监视MySQL服务器的中间件
客户端查询MySQL Fabric以获取MySQL服务器列表,它们的状态和角色。例如,客户端可以请求一个MySQL复制组的从属列表,以及它们是否准备好处理SQL请求。另一个示例是一个分片的MySQL服务器群集,客户端在其中寻求寻找要查询给定表和分片键的分片。如果配置为使用Fabric,该插件将使用基于HTTP的XML RCP在运行时从MySQL Fabric主机获取列表。XML远程过程调用本身是在后台完成的,并且从开发人员的角度来看是透明的。而不是直接在插件配置文件中列出MySQL服务器,它包含一个或多个MySQL Fabric主机的列表。
{
"myapp": {
"fabric": {
"hosts": [
{
"host" : "127.0.0.1",
"port" : 8080
}
]
}
}
}
用户利用新功能 mysqlnd_ms_fabric_select_shard()和 mysqlnd_ms_fabric_select_global()切换到负责给定分片键的服务器集。然后,插件选择一个合适的服务器来运行查询。这样做时,插件会处理其他负载平衡规则集。
示例
使用SQL提示进行手动分区,假定已将MySQL Fabric设置为test.fabrictest使用表的id列作为分片键对表进行分片。
mysqlnd_ms_fabric_select_global($mysqli, "test.fabrictest");
if (!$mysqli->query("CREATE TABLE test.fabrictest(id INT NOT NULL PRIMARY KEY)"))
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
mysqlnd_ms_fabric_select_shard($mysqli, "test.fabrictest", 10);
if (!($res = $mysqli->query("INSERT INTO fabrictest(id) VALUES (10)")))
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
mysqlnd_ms_fabric_select_shard($mysqli, "test.fabrictest", 10);
if (!($res = $mysqli->query("SELECT id FROM test WHERE id = 10")))
die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error));
创建分片表,插入一条记录,然后读取该记录。分片表上的所有SQL数据定义语言(DDL)操作都必须应用于所谓的全局服务器组。在创建或更改分片表之前, 调用mysqlnd_ms_fabric_select_global()将给定的连接切换到全局组的相应服务器。数据操作(DML)SQL语句必须直接发送到分片。这 mysqlnd_ms_fabric_select_shard()将连接切换到处理某个分片密钥的分片
负载均衡
有 4 中复杂均衡策略,可以用于支持 MySQL slave 的配置。
- random:当执行语句的时候随机选择一个服务器。
- random once (默认值):当第一个查询执行的时候,随机选择一个服务器,在本页面随后的查询中, 使用相同的一个服务器连接。这是默认值,并且这种方式对于连接状态信息可能产生的变数影响最小
- round robin:轮循配置中的所有服务器。
- user-defined via callback:可以用于制定任何一种其他的策略
单主主从配置
php.ini
mysqlnd_ms.enable = 1
mysqlnd_ms.config_file = /path/to/mysqlnd_ms_plugin.ini
mysqlnd_ms_plugin.ini
{
"myapp":{
"master":{
"master_1":{
"host":"localhost",
"socket":"/tmp/mysql57.sock"
}
},
"slave":{
"slave_0": {
"host":"127.0.0.1",
"port":3308
},
"slave_1":{
"host":"192.168.2.28",
"port":3306
}
},
"filters":{
"random": {
"sticky":"1"
}
}
}
}
多个主和分区的主副本
php.ini
mysqlnd_ms.enable = 1
mysqlnd_ms.config_file = /path/to/mysqlnd_ms_plugin.ini
mysqlnd_ms.multi_master = 1
mysqlnd_ms_plugin.ini
{
"myapp":{
"master":{
"master_1":{
"host":"localhost",
"socket":"/tmp/mysql57.sock"
}
"master_2":{
"host":"192.168.2.27",
"socket":"3306"
}
},
" slave":{
"slave_1":{
"host":" 127.0.0.1",
"port":3308
},
"slave_2":{
"host": "192.168.2.28",
"port":3306
}
},
"filters":{
"node_groups":{
"Partition_A":{
"master":["master_1"],
"slave":["slave_1"]
},
"Partition_B":{
"master":["master_2"],
"slave":["slave_2"]
}
},
"roundrobin":[]
}
}
}
在所有群集(例如MySQL群集)中使用同步更新
仅配置主服务器并禁用读写拆分
php.ini
mysqlnd_ms.enable = 1
mysqlnd_ms.config_file = /path/to/mysqlnd_ms_plugin.ini
mysqlnd_ms.multi_master = 1
mysqlnd_ms.disable_rw_split = 1
mysqlnd_ms_plugin.ini
"myapp": {
"master": {
"master_1": {
"host": "localhost",
"socket": "/tmp/mysql57.sock"
},
"master_2": {
"host": "192.168.2.28",
"port": 3306
}
},
"slave": {
},
"filters": {
"roundrobin": {
}
},
"failover": {
"strategy": "loop_before_master",
"remember_failed": true
}
}
}
需求
所有的 PHP MySQL扩展必须配置为使用mysqlnd并且在mysqlnd中使用mysqlnd_ms。
安装
扩展地址:https://pecl.php.net/package/mysqlnd_ms
windows扩展DLL当前不可用
配置
#是否启动插件,如果禁用插件将不会嵌入mysqlnd库中内部PROXY调用的mysqlnd C API接口
mysqlnd_ms.enable
#如果启用,插件会在每次尝试MySQL连接的时候通过配置文件检查服务器参数。如果存在问题,连接将被阻塞。这个参数对于运行中的系统没有什么用处,用于调试配置文件。
mysqlnd_ms.force_config_usage
#是否启动MySQL multi master集群
mysqlnd_ms.multi_master
#是否启动读写分离
mysqlnd_ms.disable_rw_split
预定义常量
sql提示
//SQL提示,用于向MySQL复制主服务器发送查询
MYSQLND_MS_MASTER_SWITCH
//SQL提示,用于将查询发送到其中一个MySQL复制从属服务器
MYSQLND_MS_SLAVE_SWITCH
//SQL提示,用于向最后使用的MySQL服务器发送查询。在MySQL复制设置中,最后使用的MySQL服务器可以是主服务器或从服务器。
MYSQLND_MS_LAST_USED_SWITCH
发送查询
//如果mysqlnd_ms_is_select()返回MYSQLND_MS_QUERY_USE_MASTER给定查询,则内置的读/写拆分机制建议将查询发送到MySQL复制主服务器
MYSQLND_MS_QUERY_USE_MASTER
//如果mysqlnd_ms_is_select()返回 MYSQLND_MS_QUERY_USE_SLAVE给定查询,则内置的读/写拆分机制建议将查询发送到MySQL复制从属服务器
MYSQLND_MS_QUERY_USE_SLAVE
//如果mysqlnd_ms_is_select()返回 MYSQLND_MS_QUERY_USE_LAST_USED给定查询,则内置的读/写拆分机制建议将查询发送到最后使用的服务器
MYSQLND_MS_QUERY_USE_LAST_USED
一致性
//用于从mysqlnd_ms_set_qos()请求服务级别的最终一致性 。从异步MySQL复制从站读取时,最终一致性是默认的服务质量。在此服务级别中返回的数据可能是过时的,也可能不是过时的,这取决于所选的从属是否恰好从MySQL复制主数据库复制了最新更改。
MYSQLND_MS_QOS_CONSISTENCY_EVENTUAL
//用于从mysqlnd_ms_set_qos()请求服务级别会话的一致性 。会话一致性定义为“读即写”。保证客户可以看到他的最新更改。
MYSQLND_MS_QOS_CONSISTENCY_SESSION
//用于从mysqlnd_ms_set_qos()请求服务级别的强一致性 。强一致性用于确保所有客户端都能看到彼此的更改
MYSQLND_MS_QOS_CONSISTENCY_STRONG
//用作mysqlnd_ms_set_qos()的服务级别选项, 以参数化会话一致性
MYSQLND_MS_QOS_OPTION_GTID
//与mysqlnd_ms_set_qos()一起用作服务级别选项, 以参数化最终的一致性
MYSQLND_MS_QOS_OPTION_AGE
函数
服务列表
//返回当前配置的服务器的列表
mysqlnd_ms_dump_servers(mixed $connection):array
connection 从mysqli, mysql或 PDO_MYSQL扩展的任何连接函数获得的MySQL连接句柄。
切换服务器
//切换到给定表的全局分片服务器
mysqlnd_ms_fabric_select_global(mixed $connection , mixed $table_name):array
connection 从mysqli, mysql或 PDO_MYSQL扩展的任何连接函数获得的MySQL连接句柄。
table_name 询问Fabric的表名称。
//切换到分片,将连接切换到负责给定表名和分片键的分片
mysqlnd_ms_fabric_select_shard(mixed $connection , mixed $table_name , mixed $shard_key):array
connection 从mysqli, mysql或 PDO_MYSQL扩展的任何连接函数获得的MySQL连接句柄。
table_name 询问Fabric的表名称。
shard_key 询问Fabric的分片键。
全局GTID
//返回最后的全局同步 ID (GTID),返回最后一次写操作以后的 GTID,他并不能保证一定是那次写操作产生的 GTID,但是得到的 GTID 一定比这次写操作产生的 GTID 大。
mysqlnd_ms_get_last_gtid(mixed $connection):string
connection 由 PDO_MYSQL, mysqli> 或者 ext/mysql 产生的 MySQL 服务器连接, 这些链接受 PECL/mysqlnd_ms 连接控制。连接的创建是通过 mysqlnd_ms 配置文件中 约定的群组名称建立的。
连接池
//返回一个数组,该数组描述用户连接句柄当前指向的插件连接池中最后使用的连接。如果使用插件,则用户连接句柄表示数据库连接池。从用户连接句柄属性无法分辨用户连接句柄指向池中的哪个数据库服务器。该函数可用于调试或监视PECL mysqlnd_ms。
mysqlnd_ms_get_last_used_connection(mixed $connection):array
connection 从mysqli, mysql或 PDO_MYSQL扩展的任何连接函数获得的MySQL连接句柄。
负载均衡
//返回由复制和负载平衡插件收集的一组统计信息;PHP配置设置 mysqlnd_ms.collect_statistics 控制统计信息的收集。出于性能原因,默认情况下禁用统计信息收集。如果PHP配置指令mysqlnd_ms.enable已禁用插件返回null。否则,返回统计信息数组。
mysqlnd_ms_get_stats():array
匹配表名
//查找表名是否与通配符模式匹配,该插件尚不支持MySQL复制表过滤。
mysqlnd_ms_match_wild(string $table_name , string $wildcard):bool
table_name 检查通配符是否匹配的表名
wildcard 用于对照表名检查的通配符模式。通配符模式支持与MySQL复制过滤器相同的占位符。可以使用来对占位符进行转义\
支持的占位符是
% 零个或多个文字
_ 一个字面量
分析查询发送服务器
//查询给定的 SQL 会发送给 master、slave 还是最后使用的 MySQL server 执行。插件内置的读写分离会分析 SQL,然后决定到底把他发送到哪里执行。这个读写分离器非常 的基本和简单。插件会将所有的查询发送给 master,除非他以 SELECT 开头,或者使用 SQL hints 指定要去 slave 执行。因为这个读写分离很简单, 所以会将一些只读查询发送给主从同步的 master,例如:SHOW TABLES。
返回 MYSQLND_MS_QUERY_USE_MASTER 说明发送给 master。 返回 MYSQLND_MS_QUERY_USE_SLAVE 说明是一个只读语句, 将发送给 slave 执行。返回 MYSQLND_MS_QUERY_USE_LAST_USED 说明会在上一次执行的服务器连接中执行,这可能是 master 也可能是 slave。如果通过设定 mysqlnd_ms.disable_rw_split 禁用了读写分离, 那么函数可能返回 MYSQLND_MS_QUERY_USE_MASTER 或者返回 MYSQLND_MS_QUERY_USE_LAST_USED。
mysqlnd_ms_query_is_select(string $query):int
query 要测试的 SQL 字符串
设置
//设置集群所需的服务质量。数据库集群根据其体系结构为用户提供一定的服务质量。服务质量的一个主要方面是群集可以提供的一致性级别。异步MySQL复制集群默认为从站读取最终保持一致:从站可能会提供陈旧数据,当前数据,或者可能根本没有请求的数据,因为它与主数据库不同步。在MySQL复制群集中,只有主访问才能提供强一致性,从而保证所有客户端都能看到彼此的更改。
mysqlnd_ms_set_qos(mixed $connection , int $service_level , int $service_level_option = ? , mixed $option_value = ?):bool
connection 与要设置服务级别的PDO_MYSQL 类型,mysqli或 ext / mysql类型的MySQL服务器的PECL / mysqlnd_ms连接句柄 。当使用上述三个MySQL驱动程序扩展中的任何一个打开具有与mysqlnd_ms配置文件条目匹配的主机名的连接时,将获得连接句柄。
service_level 所请求的服务级别:MYSQLND_MS_QOS_CONSISTENCY_EVENTUAL, MYSQLND_MS_QOS_CONSISTENCY_SESSION或 MYSQLND_MS_QOS_CONSISTENCY_STRONG
service_level_option 用于参数化请求的服务级别的选项。选项可以是MYSQLND_MS_QOS_OPTION_GTID 或MYSQLND_MS_QOS_OPTION_AGE。
MYSQLND_MS_QOS_OPTION_GTID:可用于优化服务级别MYSQLND_MS_QOS_CONSISTENCY_SESSION,它必须与第四个功能参数option_value结合使用,如果设置,则插件将同时考虑主服务器和异步从服务器以确保会话一致性(请阅读您的文章)。否则,仅使用主服务器来实现会话一致性。从站被认为是最新的,并检查它是否已经从复制了全局事务ID option_value。请注意,搜索合适的从站是一项昂贵且缓慢的操作。如果主机不能单独处理读取负载,请稀疏使用该功能。
MYSQLND_MS_QOS_OPTION_AGE:可以与MYSQLND_MS_QOS_CONSISTENCY_EVENTUAL 服务级别结合使用,以过滤出异步从站,该异步从站比主站滞后option_value秒.如果设置,插件将只考虑slave读,如果 SHOW SLAVE STATUS报告 Slave_IO_Running=Yes, Slave_SQL_Running=Yes和 Seconds_Behind_Master <= option_value。请注意,搜索合适的从站是一项昂贵且缓慢的操作。在1.2.0版中稀疏使用此功能。
option_value 服务级别选项的参数值。
//设置用户定义的读/写拆分的回调,仅当pick[]=user插件配置文件相关部分中的服务器选择默认规则时,插件才会调用回调
mysqlnd_ms_set_user_pick_server(string $function):bool
function 要调用的函数。也可以使用此函数通过传递array($classname, $methodname)给此参数来静态调用类方法 。另外,可以通过传递array($objectinstance, $methodname)给该参数来调用对象实例的类方法 。