在Laravel迁移中添加系统版本例外

问题描述 投票:2回答:1

我正试图在Laravel中使用MariaDB 10.3的System Versioned Tables功能。但是,每当我尝试运行改变表的工匠迁移时,我都会收到以下异常。

C:\htdocs\Computers>php artisan migrate:fresh
Dropped all tables successfully.
Migration table created successfully.

   PDOException  : SQLSTATE[42000]: Syntax error or access violation: 1067 Invalid default value for 'row_start'

  at C:\htdocs\Computers\database\migrations\2018_07_14_191112_add_system_version_to_computers.php:16
    12|      * @return void
    13|      */
    14|     public function up()
    15|     {
  > 16|         DB::connection()->getPdo()->exec("ALTER TABLE `COMPUTERS` ADD SYSTEM VERSIONING;");
    17|     }
    18|
    19|     /**
    20|      * Reverse the migrations.

  Exception trace:

  1   PDO::exec("ALTER TABLE `COMPUTERS` ADD SYSTEM VERSIONING;")
      C:\htdocs\Computers\database\migrations\2018_07_14_191112_add_system_version_to_computers.php:16

  2   AddSystemVersionToComputers::up()
      C:\htdocs\Computers\vendor\laravel\framework\src\Illuminate\Database\Migrations\Migrator.php:359

  Please use the argument -v to see more details.
  1. 我在空桌上以及已有数据的桌子上尝试过这个
  2. 我已经尝试用以下方法抑制PDO异常,但它的作用就像它可以工作但是当我检查表时没有添加系统版本控制 DB::connection()->getPdo()->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
  3. 如果我在HeidiSQL中执行相同的SQL,我可以在表中添加系统版本控制
  4. 我已经在Laravel文档和代码中搜索了任何允许我在创建时添加此表选项但无法找到任何内容的方法。

我可以手动解决这个问题,但我真的想将它包含在Laravel迁移文件中,因此它将包含在Git存储库中。


运行命令的结果

SHOW CREATE TABLE `computers`;

...

+-----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table     | Create Table                                                                                                                                                                                                                                                                                                                                                          |
+-----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| computers | CREATE TABLE `computers` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `Name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `computers_name_unique` (`Name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci |
+-----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.000 sec)

以下是从MariaDB命令行运行相同SQL语句的结果。请注意在表定义中添加了“WITH SYSTEM VERSIONING”。

MariaDB [computers]> ALTER TABLE COMPUTERS ADD SYSTEM VERSIONING;
Query OK, 0 rows affected (0.025 sec)
Records: 0  Duplicates: 0  Warnings: 0

MariaDB [computers]> SHOW CREATE TABLE `computers`;
+-----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table     | Create Table                                                                                                                                                                                                                                                                                                                                                                                 |
+-----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| computers | CREATE TABLE `computers` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `Name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `computers_name_unique` (`Name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci WITH SYSTEM VERSIONING |
+-----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.002 sec)

在Artisan Tinker中执行相同的alter table命令并得到相同的错误:

    >>>             DB::connection()->getPdo()->exec("ALTER TABLE `COMPUTERS` ADD SYSTEM VERSIONING;");
PDOException with message 'SQLSTATE[42000]: Syntax error or access violation: 1067 Invalid default value for 'row_start''

如果我尝试为computers-lcl用户授予所有权限,仍会得到相同的错误。

DROP USER IF EXISTS `computers-lcl`@`localhost`;
FLUSH PRIVILEGES;
GRANT ALL ON *.* TO `computers-lcl`@`localhost` IDENTIFIED BY 'qej8lOjoc81Ekub1d26uzerOv332Qa' WITH GRANT OPTION;

提前感谢您提供的任何指导。

sql laravel mariadb laravel-5.6 php-7.2
1个回答
0
投票

TL; DR:问题是由laravel使用的NO_ZERO_DATE中设置sql_mode引起的。在'strict' => false'mysql' => []部分设置config/database.php


我自己偶然发现了这个问题,我很确定我们正在处理同样的问题,这是因为你的NO_ZERO_DATE设置了sql_mode

由于ALTER TABLE语句在您通过CLI客户端或HeidiSQL(或任何其他DB GUI)执行语句时工作正常,因此请将该客户端的sql_mode与laravel数据库会话中的sql_mode进行比较。

这是我的CLI客户端使用的SQL_MODE

mysql -u root -p    
MariaDB [(none)]> SELECT @@SQL_MODE;
+-----------------------------------------------------------------------+
| @@SQL_MODE                                                            |
+-----------------------------------------------------------------------+
| ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+-----------------------------------------------------------------------+
1 row in set (0.000 sec)

这是laravel使用的SQL_MODE

php artisan tinker
Psy Shell v0.9.9 (PHP 7.3.4-1+ubuntu18.10.1+deb.sury.org+3 — cli) by Justin Hileman
>>> DB::select( DB::raw("SELECT @@SQL_MODE") );
=> [
     {#3102
       +"@@SQL_MODE": "ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION",
     },
   ]

正如你所看到的,laravel正在使用NO_ZERO_DATE,而我的命令行客户端却没有。这是由于strict模式,这是config/database.php中MySQL数据库的默认设置。如果'strict' => true,在laravel/framework/src/Illuminate/Database/Connectors/MySqlConnector.php中的DB连接设置期间触发以下代码:

    /**
     * Get the query to enable strict mode.
     *
     * @param  \PDO  $connection
     * @return string
     */
    protected function strictMode(PDO $connection)
    {
        if (version_compare($connection->getAttribute(PDO::ATTR_SERVER_VERSION), '8.0.11') >= 0) {
            return "set session sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'";
        }

        return "set session sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'";
    }

还有那个有罪的NO_ZERO_DATE。在'strict' => false设置config/database.php,laravel将不再摆弄你的sql_mode。如果你只想在保留其余严格模式的同时删除NO_ZERO_DATE部分,一个解决方案可能是提供your own MySqlConnector ServiceProvider。

© www.soinside.com 2019 - 2024. All rights reserved.