PHP MySQL X DevAPI Collection::existsInDatabase() 方法无法识别带有附加列的集合
Posted
技术标签:
【中文标题】PHP MySQL X DevAPI Collection::existsInDatabase() 方法无法识别带有附加列的集合【英文标题】:PHP MySQL X DevAPI Collection::existsInDatabase() method does not recognise Collections with additional columns 【发布时间】:2020-04-06 12:42:57 【问题描述】:根据php docs,existsInDatabase()
方法旨在确定数据库中是否存在 Collection 的实例(作为 SchemaObject 又名表)。但是只有当它的表模式完全符合使用Schema::createCollection()
方法创建的集合时,它才会认为集合存在,例如。正好 2 列称为 doc
和 _id
。
这是不是PHP模块过于严格导致的bug?
这是一个演示(取决于mysql_xdevapi PHP module)...
首先,使用 MySQL 在您的数据库中创建一个名为“people”的集合(取自 MySQL's world_x.sql script in examples for javascript/Python):
CREATE TABLE `countryinfo` (
`doc` json DEFAULT NULL,
`_id` varbinary(32) GENERATED ALWAYS AS (json_unquote(json_extract(`doc`,_utf8mb4'$._id'))) STORED NOT NULL,
`_json_schema` json GENERATED ALWAYS AS (_utf8mb4'"type":"object"') VIRTUAL,
PRIMARY KEY (`_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
其次,创建一个名为“people”的集合,与上面非常相似,但省略了_json_schema
列:
CREATE TABLE `people` (
`doc` json DEFAULT NULL,
`_id` varbinary(32) GENERATED ALWAYS AS (json_unquote(json_extract(`doc`,_utf8mb4'$._id'))) STORED NOT NULL,
PRIMARY KEY (`_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
第三,使用 PHP 的 createCollection()
方法创建一个名为 'animals' 的集合:
$dbSession = mysql_xdevapi\getSession("mysqlx://test:test@localhost");
$schema = $dbSession->getSchema("world_x");
$collection = $schema->createCollection('animals');
现在,使用 PHP 的 existsInDatabase()
方法检查 3 个集合:
$dbSession = mysql_xdevapi\getSession("mysqlx://test:test@localhost");
$schema = $dbSession->getSchema("world_x");
if ($schema->getCollection('countryinfo')->existsInDatabase())
print "countryinfo collection exist! ";
if ($schema->getCollection('people')->existsInDatabase())
print "People collection exist! ";
if ($schema->getCollection('animals')->existsInDatabase())
print "Animals collection exist! ";
根据 MySQL 文档,所有这 3 个都是有效的集合,但上面的 PHP 代码仅将“人”和“动物”识别为存在。
作为进一步的实验,使用 MySQL 将任何随机命名的列添加到名为“animals”的集合中(通过 PHP 创建),然后重新执行脚本,看看它现在如何不认为它存在。
ALTER TABLE animals ADD COLUMN test tinyint;
现在,如果您使用$schema->getCollections()
和$schema->getTables()
,您将看到animals
被归类为表而不是集合。删除该列,它会再次跳回。在引擎盖下,这是模块决定 Collection 是否“存在”的方式。
我怀疑 PHP 模块可能过于严格。这是一个问题,因为它将您的数据库模式与特定语言紧密耦合。例如,如果我想构建一个 PHP 脚本来与最初通过 JavaScript 填充的现有 MySQL 文档存储进行交互,那么它可能会出现错误,因为可能会在 some/all 中存在额外的 _json_schema
列(或其他一些列)的集合。
我认为拥有doc
和_id
以外的列是合法的,因为我没有找到相反的规范。我可以想象一个非常真实的用例,在 Collection 上有一个 created_at
日期时间列。
另外,我是否真的发现了不是 PHP 模块的问题,而是 MySQLs 文档的问题? _json_schema
列是早期版本的遗留问题,现在应该删除吗?集合表的定义现在是否已在所有语言中标准化,并且它们必须严格按照指定的那两列来定义?
MySQL 含糊不清,而 PHP 严格,这一切都显得有些松散。
感谢任何帮助。如果一致认为存在错误,我将向维护人员报告错误。
【问题讨论】:
【参考方案1】:------------------- 编辑 4 月 21 日 ----------- --------------------
看起来 xplugin/server 的行为既没有任何错误也没有变化。不允许向集合添加额外的列。 'countryinfo' 集合中的 _json_schema 列不被视为额外的东西 - 它用于称为“模式验证”的新功能,并且是可选的。所以它可能出现在集合的表中,也可能不出现。因此,给定的表仍然被视为集合,无论它是否包含“_json_schema”。虽然,将其名称从 '_json_schema' 更改为例如就足够了。 'json_schema'(即只删除前导下划线),它将被视为额外列,因此给定的表将不再报告为集合(existsInDatabase()返回false)。
引用的样本:
https://dev.mysql.com/doc/refman/8.0/en/mysql-shell-tutorial-javascript-download.html
适用于 8.0.19,但看起来该版本的服务器已经为“模式验证”做好了准备,而 mysql_xdevapi 将从 v8.0.21 开始正式支持该功能。
在这样的调用之后提到的新版本.21:
$coll = $schema->createCollection("animals");
“动物”表中的列如下所示
mysql> show columns from animals;
+--------------+---------------+------+-----+---------+-------------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+---------------+------+-----+---------+-------------------+
| doc | json | YES | | NULL | |
| _id | varbinary(32) | NO | PRI | NULL | STORED GENERATED |
| _json_schema | json | YES | | NULL | VIRTUAL GENERATED |
+--------------+---------------+------+-----+---------+-------------------+
3 rows in set (0.00 sec)
它会被报告为一个集合。
------------------- 4 月 21 日编辑结束 --------- ----------------------
我们检查了 con/php 的行为,看起来它的性能与 con/nodejs 相似,即
-
'countryinfo' 被报告为集合
添加/删除列也会导致 con/nodejs 或 shell 中报告的“动物”类型发生变化(集合与表格)。
请运行以下脚本,让我们知道您的环境中的输出是什么。
// please align below variables according to your environment
$connection_uri = "mysqlx://test:test@localhost";
$db = "testx";
$session = mysql_xdevapi\getSession($connection_uri);
$session->sql("create database $db")->execute();
$schema = $session->getSchema($db);
$session->sql("USE $db")->execute();
$countryinfo_table_stmt="CREATE TABLE `countryinfo` (
`doc` json DEFAULT NULL,
`_id` varbinary(32) GENERATED ALWAYS AS (json_unquote(json_extract(`doc`,_utf8mb4'$._id'))) STORED NOT NULL,
`_json_schema` json GENERATED ALWAYS AS (_utf8mb4'\"type\":\"object\"') VIRTUAL,
PRIMARY KEY (`_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4";
echo "$countryinfo_table_stmt\n";
$session->sql($countryinfo_table_stmt)->execute();
$people_table_stmt="CREATE TABLE `people` (
`doc` json DEFAULT NULL,
`_id` varbinary(32) GENERATED ALWAYS AS (json_unquote(json_extract(`doc`,_utf8mb4'$._id'))) STORED NOT NULL,
PRIMARY KEY (`_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4";
echo "$people_table_stmt\n";
$session->sql($people_table_stmt)->execute();
if ($schema->getCollection('countryinfo')->existsInDatabase())
print "countryinfo collection exists!\n";
else
print "countryinfo collection DOES NOT exist!\n";
if ($schema->getCollection('people')->existsInDatabase())
print "People collection exists!\n";
else
print "People collection DOES NOT exist!\n";
$coll = $schema->createCollection("animals");
if ($schema->getCollection('animals')->existsInDatabase())
print "Animals collection exists!\n";
else
print "Animals collection DOES NOT exist!\n";
$session->sql("ALTER TABLE $db.animals ADD COLUMN test tinyint")->execute();
if ($schema->getCollection('animals')->existsInDatabase())
print "Animals collection exists!\n";
else
print "Animals collection DOES NOT exist!\n";
$session->sql("ALTER TABLE $db.animals DROP COLUMN test")->execute();
if ($schema->getCollection('animals')->existsInDatabase())
print "Animals collection exists!\n";
else
print "Animals collection DOES NOT exist!\n";
print "done!\n";
在我们的环境中,输出如下所示:
CREATE TABLE `countryinfo` (
`doc` json DEFAULT NULL,
`_id` varbinary(32) GENERATED ALWAYS AS (json_unquote(json_extract(`doc`,_utf8mb4'$._id'))) STORED NOT NULL,
`_json_schema` json GENERATED ALWAYS AS (_utf8mb4'"type":"object"') VIRTUAL,
PRIMARY KEY (`_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
CREATE TABLE `people` (
`doc` json DEFAULT NULL,
`_id` varbinary(32) GENERATED ALWAYS AS (json_unquote(json_extract(`doc`,_utf8mb4'$._id'))) STORED NOT NULL,
PRIMARY KEY (`_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
countryinfo collection exists!
People collection exists!
Animals collection exists!
Animals collection DOES NOT exist!
Animals collection exists!
done!
此外,您使用的服务器/连接器版本是什么?
【讨论】:
我得到一个不同的输出:“countryinfo 集合不存在!/ People 集合存在!/ Animals 集合存在!/ Animals 集合不存在!/ Animals 集合存在!/完成!”。我正在使用 mysql 版本 8.0.18、mysql_xdevapi 8.0.19、PHP 版本 7.3.16-1+ubuntu18.04.1+deb.sury.org+1。 好的,我确认服务器 v8.0.18 con/php 的行为不同,即返回“countryinfo 集合不存在!”。我假设你机器上的 con/nodejs 或 shell 的唯一区别(我假设 v8.0.18)是它们返回“countryinfo 集合存在!”,但输出的其余部分(对于集合 'People' 和 'Animals')是一样的吗? 我没有尝试过 NodeJS。不管是 Node 还是 PHP,补丁版本是 18 还是 19。我们可以定义 /correct/ 的行为应该是什么吗?是否有关于何时 MySQL 表是“集合”以及何时未定义和记录的规范?因为这种二元区分似乎对跨所有连接器非常重要。 好的,正如你提到的那样,PHP 可能过于严格,所以我想研究一下连接器之间可能存在的这些差异。但这没关系。无论如何,在 PHP 中,我们不执行任何额外的限制性检查并依赖来自服务器的信息,所以我联系了 xplugin/server 人员以进一步进行。 请检查我的答案 - 它在上述消息的开头(我已经编辑过)以上是关于PHP MySQL X DevAPI Collection::existsInDatabase() 方法无法识别带有附加列的集合的主要内容,如果未能解决你的问题,请参考以下文章
如何设置 MySQL 连接器/Python X DevAPI 连接的选项?
如何在 Mysql X DevAPI 中查询 Null 或 Missing 字段?
您如何为 MySQL X DevAPI 使用 Java 连接池?
X DevAPI mysqlx::Session() over linux socket 失败并显示“CDK 错误:意外消息”