【问题标题】:Laravel Timestamp Being Updated Without Explicit Call To Do SoLaravel 时间戳在没有明确调用的情况下更新
【发布时间】:2019-09-26 11:27:54
【问题描述】:

所以我在 Laravel 更新和保存方面遇到了一个烦人的问题。我有一个模型/表Invoiceinvoices,有一个时间戳sent_at

Invoice.php

class Invoice extends Model {
    protected $dates = [
        "sent_at",
    ];
}

我有以下更新Invoice的函数:

InvoicesController.php:

public function postPayInvoice(Request $request, $invoiceId){
    $user = $this->apiResponse->user;

    $invoiceItemIds = $request->input("invoice_item_ids");

    $invoice = Invoice::with(["invoiceItems" => function($subQuery) use($invoiceItemIds){
        return $subQuery->whereIn("invoice_items.id", $invoiceItemIds);
    }])->where("id", "=", $invoiceId)->first();

    \Log::info("Load: ".$invoice->sent_at);

    DB::beginTransaction();
    try {
        foreach($invoice->invoiceItems AS $invoiceItem){
            $invoiceItem->status = "paid";
            $invoiceItem->paid_at = Carbon::now();
            $invoiceItem->save();
        }

        $totalInvoices = $invoice->invoiceItems()->count();
        $paidInvoiceItems = $invoice->invoiceItems()->where("status", "=", "paid")->count();

        if($totalInvoices == $paidInvoiceItems){
            $invoice->status = "paid";
            $invoice->paid_at = Carbon::now();
        } else {
            $invoice->status = "partially_paid";
        }

        \Log::info("Pre: ".$invoice->sent_at);

        $invoice->save();

        \Log::info("Post: ".$invoice->sent_at);

    } catch(\Exception $ex){
        DB::rollBack();
        return $this->apiResponse->returnFail([], "Unable to Pay Invoice: ".$ex->getMessage(), 200);
    }

    DB::{$request->input("rollback", null) ? "rollback" : "commit"}();

    \Log::info("Post Commit: ".$invoice->sent_at);

    return $this->apiResponse->returnSuccess($invoice, "Invoice paid!", 200);
}

这样做是支付选定的InvoiceItemsInvoice 的子模型),如果所有InvoiceItems 都标记为paid,则将invoices.status 更新为paid(或partially_paid ) 和invoices.paid_atCarbon::now()(或null)。

这一切都很好,但不知何故,这段代码也在更新sent_at(因此\Log语句)。当代码加载Invoice,在应用所有保存逻辑之后,在保存之后,最后在提交之后,sent_at 属性被记录:

[2019-05-08 12:43:24] local.INFO:加载:2019-05-08 12:42:50
[2019-05-08 12:43:24] local.INFO: Pre: 2019-05-08 12:42:50
[2019-05-08 12:43:24] local.INFO: Post: 2019-05-08 12:42:50
[2019-05-08 12:43:24] local.INFO:提交后:2019-05-08 12:42:50

如您所见,sent_at 时间戳始终为2019-05-08 12:42:50。但是当我重新查询数据库时,时间戳是2019-05-08 12:43:24,这是paid_atupdated_at 时间戳的值。

(status, sent_at, paid_at, created_at, updated_at)

请注意,这是从 API 调用的,随后请求加载Invoice 模型列表,该模型具有以下逻辑来确定附加逻辑:

$cutoff = $this->sent_at->addDays(3)->endOfDay();

但我看不出这会如何修改 sent_at 列(没有调用保存/更新,即使这样做了,2019-05-08 12:43:24 也不等于 addDays(3)->endOfDay();

有人见过这个吗?它在另一个视图中弄乱了一些排序逻辑,所以我最终需要修复它......

编辑

如果我禁用$invoice->save();,它的updated_at 时间戳仍在更新,但我不知道为什么。而且,奇怪的是,禁用 $invoiceTransaction->save();$invoiceItem->save(); 不会导致 updated_at 发生任何变化...确实会导致数据错误,但这仍在开发中。

二次编辑

"CREATE TABLE `invoices` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`account_id` int(11) NOT NULL,
`description` text,
`subtotal` decimal(10,2) NOT NULL,
`grand_total` decimal(10,2) NOT NULL,
`status` enum('pending','sent','partially_paid','paid') NOT NULL DEFAULT 
'pending',
`sent_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`paid_at` timestamp NULL DEFAULT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
`deleted_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8"

我认为那里有问题:

sent_attimestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

【问题讨论】:

  • 你们班有观察员吗?
  • 你能显示show create table invoices吗?
  • 这是你的问题:`sent_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
  • 我不确定迁移会如何发生,因为它似乎根本不在蓝图中。非常好奇。我想您总是可以在迁移中将其设置为可为空,然后在数据库中手动修复它。 (编辑)显然这是一个已知问题? ma.ttias.be/…
  • 我也没见过。事实证明,这是一个 MySQL 5.7 设置。 The first TIMESTAMP column in a table, if not explicitly declared with the NULL attribute or an explicit DEFAULT or ON UPDATE attribute, is automatically declared with the DEFAULT CURRENT_TIMESTAMP and ON UPDATE CURRENT_TIMESTAMP attributes.dev.mysql.com/doc/refman/5.7/en/…

标签: php mysql laravel transactions laravel-5.4


【解决方案1】:

这是由于 MySQL 5.7 配置,而不是 Laravel。

表中的第一个 TIMESTAMP 列,如果没有使用 NULL 属性或显式 DEFAULT 或 ON UPDATE 属性显式声明,则会自动使用 DEFAULT CURRENT_TIMESTAMP 和 ON UPDATE CURRENT_TIMESTAMP 属性声明。

src - Mysql Docs

解决方法是在迁移中将时间戳设置为可为空,和/或手动更改表。

ALTER TABLE invoices CHANGE sent_at sent_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-29
    • 2010-09-14
    • 1970-01-01
    相关资源
    最近更新 更多