我的迁移可以在本地运行,但在生产中失败并出现错误:
Migrating: 2024_03_19_145356_tasks
Illuminate\Database\QueryException
SQLSTATE[42000]: Syntax error or access violation: 1067 Invalid default value for 'send_before' (SQL: create table `tasks` (`id` bigint unsigned not null auto_increment primary key, `subscription_id` bigint unsigned not null, `send_after` timestamp not null, `send_before` timestamp not null, `sent_at` timestamp null comment 'null = not sent', `failed_at` timestamp null, `delivered` tinyint(1) null default '0' comment '0 - not delivered, 1 - delivered, null - unknown', `created_at` timestamp null, `updated_at` timestamp null) default character set utf8mb4 collate 'utf8mb4_unicode_ci')
我调试失败了,因为 SQL 是有效的,并且实际上在通过 phpMyAdmin 或终端运行时在生产环境中运行良好:
create table `tasks` (`id` bigint unsigned not null auto_increment primary key, `subscription_id` bigint unsigned not null, `send_after` timestamp not null, `send_before` timestamp not null, `sent_at` timestamp null comment 'null = not sent', `failed_at` timestamp null, `delivered` tinyint(1) null default '0' comment '0 - not delivered, 1 - delivered, null - unknown', `created_at` timestamp null, `updated_at` timestamp null) default character set utf8mb4 collate 'utf8mb4_unicode_ci'
2024_03_19_145356_tasks.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class Tasks extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->foreignId('subscription_id')->constrained('subscriptions')->cascadeOnDelete();
$table->timestamp('send_after')->index();
$table->timestamp('send_before')->index();
$table->timestamp('sent_at')->nullable()->index()->comment('null = not sent');
$table->timestamp('failed_at')->nullable();
$table->boolean('delivered')->default(0)->comment('0 - not delivered, 1 - delivered, null - unknown')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('tasks');
}
}
服务器版本:5.5.60-MariaDB MariaDB服务器
PHP 7.4.33 (cli)(构建时间:2023 年 12 月 12 日 14:45:16)(NTS)
Laravel 框架 8.83.27
更新1
在迁移中添加了
dump(\DB::select("SELECT @@version, @@sql_mode"));
,我发现迁移期间的 sql_mode
有以下 sql_mode
设置:
array:1 [
0 => {#1958
+"@@version": "5.5.60-MariaDB"
+"@@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"
}
]
已更新(已解决?)
我找到了问题所在。我不想假装我知道发生了什么,所以我会按原样说: 当迁移有多个列类型
timestamp
其中 is not nullable
时,就会出现问题。以下是一些示例:
作品:
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->timestamp('test1');
$table->timestamp('test2')->nullable();
$table->timestamp('test3')->nullable();
});
错误
1067 Invalid default value for 'test2'
:
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->timestamp('test1');
$table->timestamp('test2');
$table->timestamp('test3')->nullable();
});
作品:
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->timestamp('test1')->nullable();
$table->timestamp('test2')->nullable();
$table->timestamp('test3');
});
错误
1067 Invalid default value for 'test2'
:
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->timestamp('test1');
$table->timestamp('test2');
});
作品:
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->timestamp('test1')->nullable();
$table->timestamp('test2');
$table->timestamp('test3')->nullable();
});
而且......如果我使用
dateTime
它总是有效的。所以......问题已经解决了,尽管我不知道发生了什么,我想知道
时间戳列的隐式默认值(即,未显式定义默认值时的默认值)很复杂。在表的第一个时间戳列之后,它的行为有所不同。真是太奇怪了
如果您未指定任何默认值,则第一个时间戳列将自动给出
DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
选项,并且 explicit_defaults_for_timestamp
为 false。
后续时间戳列不会自动获取这些选项。
NOT NULL
时间戳的隐式默认值是“default default”时间戳值,即 0。
但是Laravel显然设置了一个包含
sql_mode
的会话NO_ZERO_IN_DATE,NO_ZERO_DATE
,这使得时间戳的0值无效。
所以你的选择是:
DEFAULT
。sql_mode
以允许日期为零。我不推荐这样做,因为带零的日期不是真正的日期。禁止它们是个好主意。