赵特纳/ php-mysql-git
将 SQL 结构存储在 PHP 数组中,这些数组可以添加到 git 中,允许您根据存储的结构配置 MySQL 数据库。
Requires
- php: >=7.2.0
This package is auto-updated.
Last update: 2024-09-29 05:49:27 UTC
README
将 SQL 结构存储在 PHP 数组中,这些数组可以添加到 git 中,允许您根据存储的结构配置 MySQL 数据库。
工作原理
- 您的当前 MySQL/mariaDB 数据库(您选择的表、列和数据)存储在一个目录中的 PHP 文件中的数组。
- 这些文件可以置于版本控制之下,并在另一台机器上检出。
- 在另一台机器上,运行中的数据库与 PHP 文件(存储的表、列和您选择的第 1 步数据)进行比较。比较结果生成 SQL 语句,以更改数据库,使其与存储的结构相匹配。
与迁移不同,php-mysql-git 正在进行数据库和存储结构的真实比较,并独家生成 SQL 语句。
安装
通过 composer
composer require peterhufner/php-mysql-git
或克隆此存储库。
用法
如果您未通过 composer 安装,您可以通过 require_once 'src/PhpMySqlGit/autoload.php';
来通过 require_once 'src/PhpMySqlGit/autoload.php';
要求额外的自动加载器。
基本示例
require_once 'PATH/TO/COMPOSER/vendor/autoload.php'; $phpMySqlGit = new PhpMySqlGit\PhpMySqlGit([ 'connectionString' => 'mysql:host=DATABASE-HOST;port=DATABASE-PORT;dbname=DATABASE-NAME', 'username' => 'DATABASE-USERNAME', 'password' => 'USER-PASSWORD', ]); $structureDirectory = 'PATH/TO/DIRECTORY/WHERE/STRUCTURE/SHOULD/STORED'; // save the structure of the current database to a directory $phpMySqlGit->saveStructure($structureDirectory); // save the data of some tables $phpMySqlGit->saveData($structureDirectory, [ 'TABLE1', 'ANOTHER_TABLE' ]); // ouput all statements that are necessary to change the database according to stored structure echo(implode("\n\n", $phpMySqlGit->configureDatabase($structureDirectory))); // ouput the insert statements to the stored data echo(implode("\n\n", $phpMySqlGit->configureData($structureDirectory)));
在示例中,SQL 语句始终输出,而不会直接执行。尽管您可以直接将语句传递给 PDO 实例,但您不应该这样做。在执行之前始终审查语句总是更好的,并且您不应该给予您的 web 服务器用户更改数据库结构的权限。
带有选项的示例
在此示例中展示了几乎所有可能的选项。
require_once 'PATH/TO/COMPOSER/vendor/autoload.php'; $phpMySqlGit = new PhpMySqlGit\PhpMySqlGit([ // specify the database name in the connection string //'connectionString' => 'mysql:host=DATABASE-HOST;port=DATABASE-PORT;dbname=DATABASE-NAME', // specify the database name later 'connectionString' => 'mysql:host=DATABASE-HOST;port=DATABASE-PORT;', 'username' => 'DATABASE-USERNAME', 'password' => 'USER-PASSWORD', ]); // if you haven't specified the database name in the connection string, then do it here $phpMySqlGit->setDbname("DATABASE-NAME"); $structureDirectory = 'PATH/TO/DIRECTORY/WHERE/STRUCTURE/SHOULD/STORED'; // if you want to ensure that a charset and collation is used globally ignoring the local used $phpMySqlGit->setOverwriteCharset(true); // utf8mb4 is the default, so there is no need to specify it again - just here to demonstrate $phpMySqlGit->setCharset('utf8mb4'); $phpMySqlGit->setCollation('utf8mb4_unicode_ci'); // these defaults are also available for engine and row format $phpMySqlGit->setRowFormat('DYNAMIC'); // DYNAMIC is the default $phpMySqlGit->setEngine('InnoDB'); // InnoDB is the default $phpMySqlGit->setOverwriteRowFormat(true); //false is default $phpMySqlGit->setOverwriteEngine(true); // false is default // you also can omit charset, engine and row format - so ignore the checking completely $phpMySqlGit->setIgnoreCharset(true); $phpMySqlGit->setIgnoreEngine(true); $phpMySqlGit->setIgnoreRowFormat(true); // when generating statements to change database, foreign keys are dropped before and created afterwards, to ensure the databse structure can be changed. // defaults to false // you should disable it only when you have a reason (for example a bug in php-mysql-git) $phpMySqlGit->setSkipForeignKeyChecks(true or false); // when using with data you can disable foreign key checks, but be careful it can damage the database when data is not consistent // this leads to the generation of the statement: SET FOREIGN_KEY_CHECKS = 0; so this is done in the database server $phpMySqlGit->setForeignKeyChecksForData(false); // mod to create files with $phpMySqlGit->setFileMod('0664'); //default // mod to create directories with $phpMySqlGit->setDirMod('0775'); //default // and now the real stuff // save the structure of the current database to a directory $phpMySqlGit->saveStructure($structureDirectory); // save the data of some tables // if you call saveData only with the path, the data of all tables is saved // if you specify some tables, the data is stored (and later inserted) in order of the appearance in the array // with the correct order of data, you can insert data with foreign key checks enabled $phpMySqlGit->saveData($structureDirectory, [ 'TABLE1', 'ANOTHER_TABLE' ]); // save data but exclude columns // if you call saveData with an array as third argument, you can exclude columns // an element in that array with an integer as key is an exclude for all tables // an element with tablename as key and value as column or an array of columns exclude only for that table $phpMySqlGit->saveData( $structureDirectory, [], // meaning all tables [ 'uid', // exclude the column uid for all tables 'TABLE_NAME' => ['lastUpdate', 'createDate'], // exclude two columns for specific table 'ANOTHER_TABLE' => 'status', // exclude one column for specific table ] ); // Passing true as the 4th. argument to saveData, will create data files with an numeric incremental index, in order of the occurence of the table-name in the table-Array // If the table-array (2th. argument) is empty, the order of table of databaseserver is used. // When using the index-feature you can ensure that the created Insert-Statements of configureData are in the same order as you have saveData called. // But be careful with the index-feature, when you use saveData multiple times with different tables. It may creates multiple data files per table with different numeric index. $phpMySqlGit->saveData($structureDirectory, [], [], true); // ouput all statements that are necessary to change the database according to stored structure echo(implode("\n\n", $phpMySqlGit->configureDatabase($structureDirectory))); // ouput the insert statements to the stored data echo(implode("\n\n", $phpMySqlGit->configureData($structureDirectory)));
使用 PDO 实例构造
您可以直接传递 PDO 类的实例,而不是使用数组调用 PhpMySqlGit 类。
$phpMySqlGit = new PhpMySqlGit\PhpMySqlGit(new PDO("mysql:host=DATABASE-HOST;port=DATABASE-PORT;", "DATABASE-USER"));
使用这种技术,您可以指定一些额外的设置。
存储多个数据库
通常,您可以多次重复存储一个数据库的过程。所以将数据库 'shop1' 存储到目录 'shop1' 中,依此类推。
使用设置器 $phpMySqlGit->setSaveNoDbName(false)
您可以在一个目录中存储多个数据库。在这种情况下,PhpMySqlGit 将为每个数据库处理一个子目录结构。您必须为每个数据库重复保存和配置过程,唯一的优点是您不需要担心目录结构。
在这种情况下,保存结构和数据库服务器中必须具有相同的数据库名称。使用 $phpMySqlGit->setDbname("DATABASE-NAME");
您只需从目录中的 '池' 中选择一个数据库。
当您想要存储多个数据库且数据库名称在使用的服务器上不同时,您必须为每个数据库使用单独的目录。
确保您的默认设置生效
您可以使用设置器为每个字符集、校对、引擎和行格式指定默认值。您必须通过 setOverwrite
...-函数启用这些设置的覆盖。当启用默认设置和覆盖时,它将在将结构保存到文件时以及从存储的结构配置数据库时使用。这意味着,当启用覆盖时,存储到文件中的设置不会从您的数据库中使用,而是从默认设置中,并且在配置从存储的结构数据库时也是如此。
使用默认设置和覆盖,您可以确保每个配置过程都将导致对指定设置的检查和修正。
示例
$phpMySqlGit = new PhpMySqlGit\PhpMySqlGit(...); $phpMySqlGit->setCharset('my_everywhere_wanted_charset'); $phpMySqlGit->setCollation('my_everywhere_wanted_collation'); $phpMySqlGit->setOverwriteCharset(true); $phpMySqlGit->saveStructure(...); // will store your defined charset and collation, but not that from your used database $phpMySqlGit->configureDatabase(...); // will check and change database, tables, columns to your defined charset, regardless which charset you have stored in structure
小心默认设置,它可能会更改您实际上不希望更改的列和表。
CLI 示例
该软件包包含一个简单的类 "CommandLineInterface"。该类收集命令行参数,并将它们传递给主 PhpMySqlGit 类。每个以 set
开头的 CLI 参数,如果它是 PhpMySqlGit 的一个方法,就会被调用并传递相应的值。在您的 PHP 文件中,您可以创建并准备一个带有默认设置的 PhpMySqlGit 实例,这样您就不必每次都调用每个设置器。CommandLineInterface 类对 PhpMySqlGit 构造函数的第一个参数的数组键有特殊的解释。因此,您可以将 --connectionString、--username、--password 作为 CLI 参数传递。
您只需创建一个 PHP 文件来调用 CommandLineInterface 类。例如,一个名为 cli.php 的文件。
<?php // only allow access through command line if (php_sapi_name() !== "cli") { exit(); } require_once 'PATH/TO/vendor/autoload.php'; // optionally you can provide a prepared and connected PhpMySqlGit-Instance in the Constructor $cli = new \PhpMySqlGit\CommandLineInterface(); // optional path to structure, when provided it will overwrite any delcaration in the CLI-Call $cli->setDataDir('PATH/TO/STRUCTUREDIR'); $cli->execute();
然后您可以按照以下方式调用 cli.php
# data dir defined in cli.php php cli.php --connectionString="mysql:host=127.0.0.1;port=3306;" --username=demouser --setOverwriteCharset=true --setDbName=sakila --saveStructure # data dir defined in cli.php, but call extra args on saveData php cli.php --connectionString="mysql:host=127.0.0.1;port=3306;" --username=demouser --setOverwriteCharset=true --setDbName=sakila --saveStructure --saveData='[null,["film", "film_actor"]]' # provide path to strcuture dir inline php cli.php --connectionString="mysql:host=127.0.0.1;port=3306;" --username=demouser --setOverwriteCharset=true --setDbName=sakila --saveStructure --saveData='["/PATH/TO/STRUCTUREDIR",["film", "film_actor"]]' # use a prepared PhpMySqlGit-Instance and a default strcuture path, what means less args in CLI-Call php cli.php --setDbName=sakila --saveStructure --saveData='[null,["film", "film_actor"]]'
配置远程/生产服务器
当更新生产服务器时,您可能希望在更新运行代码之前更新数据库模式。通过此过程,您可以最大限度地减少停机时间。为了实现这一点,您可以在非生产机器上检出新的结构,并从那里通过端口转发连接到生产数据库。然后您可以更改生产模式,而不更改运行代码。代码可以在之后更新。
兼容性
数据库服务器
php-mysql-git 应该与最新的 MySQL 和 mariaDB 版本兼容,并且它会尽可能尊重使用的服务器之间的差异。
在 MySQL 和 mariaDB 的不同版本之间,信息_schema 中存储结构信息的方式存在一些差异,这些差异被尊重,不应该导致存储的 PHP 文件中的数据或结构不同。例如,直到 mariaDB 10.2.6 和所有 MySQL 至少到版本 8,DEFAULT VALUES 在 information_schema 中存储,但没有类型信息。因此,不清楚它是 NULL 还是字符串 'NULL'。此信息可以从 SHOW CREATE TABLE 中获得,但这里也存在版本之间的差异。一些服务器为 INT 打印有引号的 DEFAULT VALUES,而另一些则没有。
总的来说,这些应该会被工具捕获。如果您遇到其他问题,请提交问题。
但是,有些差异实际上不好处理或应该通过审查更好地处理。
这些取决于使用的配置和默认值。
一个例子:innodb_large_prefix 在较新版本中默认启用(MySQL 5.7、mariaDB 10.2.2),而在较旧版本中通常禁用。这会导致 char 和 text 列的最大键长度根据您的字符集而不同。
当 innodb_large_prefix 禁用时,使用 utf8mb4 可以索引最多 191 个字符,启用时最多 768 个字符(AND ROW FORMAT 是 DYNAMIC 或 COMPRESSED)。
因此,您可以看到存在一些版本/配置相关的限制。
当您现在在 mariadb 10.4 中保存一个
- ROW FORMAT DYNAMIC 的 innodb 表
- utf8bm4 列的长度大于 191 个字符
- 和一个没有长度或长度大于 191 个字符的索引时,您将与另一个 innodb_large_prefix 禁用的服务器不兼容。这不能通过 php-mysql-git 解决。
您可能会注意到每次配置数据结构时都会重复出现 DROP KEY 和 ADD KEY 语句。这是因为键在 PHP 文件中没有长度,但在服务器中创建时最大长度为 191 个字符。因此,php-mysql-git 每次都会注意到差异。
或者,您可能无法持久化由 php-mysql-git 生成的 CREATE 语句,因为您的服务器不允许键长度超过 191 个字符。在这种情况下,您应该使您的结构与所有使用的版本兼容。
为了确保在每台机器上都能正常工作,您应该在所有机器上使用相同的服务器、版本和配置(在关键部分,而不是在性能设置中)。
PHP
>= PHP 7.2
依赖项
只需要基本的 PHP 库。PDO 必须启用,这应该是标准配置。
限制
目前不处理 SQL 函数、存储过程、视图、触发器和事件。
只存储和可以配置表和列。