譯文首發於 使用 Laravel 制定 MySQL 資料庫備份計劃任務,轉載請註明出處。
你可以在終端裡通過執行一行命令匯出整個資料庫。這種方案不僅簡單直接而且有效。不過有更加自動化的解決方案。讓我們來看看究竟是什麼!
背景
幾天前,我登入到錯誤的資料庫中然後幹掉了 18 000 行線上資料記錄。更糟糕的是,我們沒有對這個資料庫進行備份。然後,我決定編寫一個能夠自動完成資料庫匯出並儲存到 SQL 檔案的指令碼。
另外,如果你需要一款功能強大的資料備份系統,你可以看看 這個 擴充套件。這樣我們就無需關注更多的資料庫備份細節而僅需將焦點放到資料庫匯出和匯出計劃上。
匯出命令
使用這個單行 snippet,你可以快速的將資料庫匯出到 SQL 檔案。很多應用使用下面這個命令從資料庫匯出資料。
mysqldump -u[user] -p[pass] [db] > [file_path]
正如你所看到的那樣,我們需要傳入使用者名稱、密碼和需要匯出的 DB,然後將輸出重定向到指定的檔案。食用簡單方便,功效顯著。
現在讓我們將這個命令通過使用 artisan 命令進行封裝,使其更易於執行和可加入計劃任務。
Artiasn 控制檯介面熱身
通過使用 artisan 控制檯(console)整合 shell 命令的一個重要出發點是,能夠一次編寫到處執行。我們要做的是配置並使用這些配置。這意味著,一旦有引數被修改,我們不需要通過命令本身進行調整。接下來,我們可以來建立這個控制檯命令。
通過執行 php artisan make:comman 命令來建立一個自定義命令。這裡我們的命令命名為 BackupDatabase。當建立完你的命令後,Laravel 會自動的將命令註冊到系統中。你需要做的,僅僅是去定義命令的簽名(signature)。
讓我們來預覽一下這個命令檔案;稍後會詳細解釋它是如何執行的:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\ProcessFailedException;
class BackupDatabase extends Command
{
protected $signature = 'db:backup';
protected $description = 'Backup the database';
protected $process;
public function __construct()
{
parent::__construct();
$this->process = new Process(sprintf(
'mysqldump -u%s -p%s %s > %s',
config('database.connections.mysql.username'),
config('database.connections.mysql.password'),
config('database.connections.mysql.database'),
storage_path('backups/backup.sql')
));
}
public function handle()
{
try {
$this->process->mustRun();
$this->info('The backup has been proceed successfully.');
} catch (ProcessFailedException $exception) {
$this->error('The backup process has been failed.');
}
}
}
你也看到了,我們的命令簽名為 db:backup。由於 Laravel 已經有了 db 命令空間,這樣命令更加清晰命令。
在建構函式中,我們例項化一個新的 Symfony\Component\Process\Process 例項。原因是這裡我們需要使用 Symfony 的 Process 元件 - 而不是簡單的呼叫 shell_exec 函式。這個元件提供了很多好讚的特性。比如,如果程式失敗,我們可以丟擲異常,然後有效處理異常。
如果你是用的是 process 的 run() 方法,你需要手動的去檢測執行錯誤然後丟擲異常。而通過 mustRun() 方法,它會自動的給我們丟擲異常。你可以從 文件 中獲取更多資訊。
我們將 shell 命令和所需的引數傳入到 sprintf() 函式中,它會將佔位符替換成實際的引數。在處理完 process 例項後,我們可以進行下一步 handle)( 方法的處理。
在 handle 方法裡,我們有個一 try-catch 程式碼塊。首先,我們呼叫 mustRun() 方法,如果沒有錯誤,我們向控制檯中輸出綠色的資訊;否則,丟擲 ProcessFailedException 異常,並在 catch 程式碼塊中捕獲,並向控制檯中輸出 error 資訊。
接下來呢?如果我們在控制檯執行 php artisan db:backup 命令,我們就會到此處資料庫然後將其儲存到 storage/backups/backup.sql 檔案。執行良好,不過,我們還有一些工作要做,就是編寫計劃任務。
編寫備份任務的計劃任務
首先,在 Laravel 中能夠輕鬆建立計劃任務。它內建提供了既簡單又支援鏈式操作的定義任務的 API 介面。在繼續本文閱讀之前,強烈建議閱讀 它的文件 中譯。
然後,進入到 Console/Kernel.php 檔案看看 schedule() 函式。我們可以定義任務和任務執行週期。比如,我們希望在 每週一的 23:00 執行計劃,它的編碼如下:
protected function schedule(Schedule $schedule)
{
$schedule->command('db:backup')->mondays()->at('23:00');
}
是不是很簡單?更棒的是,你可以在這裡定義任意多個命令。排程器(scheduler)會在指定的時間分別處理這些任務。
若要執行這個排程器,我們需要執行 php artisan schedule:run 命令,然後它會觸發所有需要執行的命令。這很棒,我們僅需一行命令就可以在指定的時間觸發對應的任意命令。
但現在的問題時,如何管理排程器自身。這個有點像雞生蛋蛋生雞的問題,但是相信我,沒有這麼複雜。
使用 Forge 設定排程器
如果你還需要掌握 CORN 執行原理相關基礎支援, Mohamed Said 有一個系列文章 深入講解了 CRON 相關知識。其中關鍵點在於,我們無需為每個計劃任務建立 CRON 定時器。我們僅需向前面介紹的那樣定義任務執行手氣,然後執行任務調取器就好了。
不過,我們需要設定執行 php artisan schedule:run 命令的時間。如果你使用了 Laravel Forge,那麼可以很輕易的建立定時任務。只需進入到 Scheduler 選項卡,然後你就能建立任何你想要的計劃任務。
如你所見,預設的已將新增了 schedule:run 命令,你需要做的就是,定義任務週期(frequency)以及替換預設命令到你伺服器的命令。
如果準備好了,排程器將每次在適當的時候執行,並觸發所有要執行的命令。
總結
很高興; 我們可以提供輕量級的解決方案,而不依賴於一個更大的包。在這裡,我們也可以利用 Laravel 的優勢來滿足需求。
我們可以使用 Process 元件輕鬆匯出資料庫,並將其封裝在 artisan 命令中。然後,我們可以快速地為我們的命令設定一個執行週期,而 Laravel 的排程程式將負責剩下的工作。我們可以躺著就把活該幹了。