资料库迁移是以执行一个个档案来逐步建立资料库表单的作法,可以纪录资料库变化的过程。逐步变更可以降低对已上线系统的影响,也能在出错的时候退回到还能正常运作时的资料库结构。
可以先来看看 Laravel 预先建立好的 Migration 档案
// database\migrations\2014_10_12_000000_create_users_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('users');
}
}
这是用来建立 User 表单的迁移,首先可以看到主要分成了 up / down 两个功能, up 就是推进迁移时执行, down 则是退回迁移步骤时执行。
up 不一定是建立或增加栏位,可能会是删除栏位,变更栏位属性(移除 Foreign key 等),或是删除表单也有可能,而 down 中需要对应 up 的内容执行相反的指令。
如果还没跑过可以先跑一次 Migration 建立使用者登入相关的表单
sail artisan migrate
成功的话可以在资料库看到新建的表单
用指令建立 Migration 档案
sail artisan make:migration <migratoin_name>
这样建出来的 Migration 会放在 database/migrations 目录下,并且 up / down 方法都是空的。
如果 Migration 是用来建立表单的话,可以在指令中指定要建立的表单名称
sail artisan make:migration create_todos_table --create todos
这样建立的 Migration 中就会预设好建立表单的指令, down 也会填好删除表单的指令。
// database\migrations\XXXX_XX_XX_XXXXX_create_todos_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTodosTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('todos', function (Blueprint $table) {
$table->id();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('todo');
}
}
另外说一下 Migration 档案都会在档名前面加上时间戳,以辨别 Migration 的执行顺序。
如果不是想建立表单而是变更某个表单的内容的话,指令会变成
sail artisan make:migration update_todos_table --table todos
另外如果想指定 migrations 建立的位置,指令可以加上 path 参数
sail artisan make:migration update_todos_table --table todos --path database/migrations/Todos
path 会是相对於专案目录的位置
如果是在 Migration 中增改删除表单,都是利用 Schema 这个帮手。
Schema::create() 方法会建立新的表单
public function up()
{
Schema::create('todos', function (Blueprint $table) {
$table->id();
$table->timestamps();
});
}
up() 里是建立表单的话,down() 里就会写删除表单的方法
public function down()
{
Schema::dropIfExists('todos');
}
关於表单的名称,一般会加上 's' ,这样之後建立 Eloquent ORM 的模型时,就不用在特地宣告模型对应的表单,Eloquent ORM 会自动对应,例如 Flight 模型会自动找 flights 表单进行查询。
当然如果名称对不上的话,手动宣告模型对应的表单就好。
建立表单的同时,可以宣告表单要有的栏位。
栏位的定义包含名称、型别、是否可为空等,这边列一些比较常用的。
$table->uuid('id'); // id -> 第一个参数是栏位名称,其他方法也一样
建立值为 UUID 的栏位,通常用来当主键,或宣告外键栏位。
$table->boolean('confirmed');
$table->integer('votes');
$table->float('amount', 3, 2); // 3->数字总数 , 2->小数位数 ,例: 1.23
$table->string('name', 100); //100->字数上限
$table->longText('description');
$table->dateTime('created_at');
常用型别以及日期时间型别
$table->json('options');
可以把大量资料包成 json 存起来,要用的时候再解析,我们这通常用来保存机器的通讯数据原始资料。
$table->timestamps();
一次建立常用的 created_at 跟 updated_at 栏位。
$table->string('description')->nullable();
nullable 宣告该栏位可为空值,没有宣告 nullable 的话当栏位没值会报错。
$table->bool('receive_ads')->default(true);
当未宣告栏位值的话自动填入预设的值,就不用宣告 nullable 了。
$table->string('email')->unique();
宣告必须为独特值的栏位,该栏位内的所有值必须是独一无二的,写入时若发现有重复会报错。
建立表单时也可以加上表单间的关联性,通常是宣告一个外键後绑定到其他表单的主键上。
$table->uuid('user_id');
$table->foreign('user_id')->references('id')->on('users');
要注意的是当宣告关连到 users 时, users 表单必须已经建立,而且有 id 这个栏位。
这是资料库层的限制,之後当写入值的时候如果 user_id 为空或找不到任何 users 表单中的参照,会报错。
可以进一步宣告当资料被删除的话要如何处里关联的资料。
像是建立一个 user_settings 表单,当中的资料都会关连到 user
public function up()
{
Schema::create('user_settings', function (Blueprint $table) {
$table->uuid('id');
$table->uuid('user_id');
$table->foreign('user_id')->references('id')->on('users')
->onDelete('cascade');
$table->timestamps();
});
}
宣告 onDelete('cascade') 的话,当 user 被删除时,跟他关联的 user_setting 资料也会被删除。
其他选项
onDelete('restrict'); //阻止删除动作,除非 user_setting 被删除不然 user 删不了
onDelete('set null'); //删除後 user_setting 的 user_id 为 null
//要将 user_id 设为 nullable 不然会报错
也有 onUpdate,当关联资料被更新时执行,选项跟 onDelete 一样。
可以更改既有的表单名称
Schema::rename($from, $to);
或是删除表单
Schema::drop('users'); //找不到表单的话会报错
Schema::dropIfExists('users');
要变更现存的表单内的栏位的话,用 Schema::table()
public function up()
{
Schema::table('user_settings', function (Blueprint $table) {
//
});
}
如果是新增栏位,做法跟建立表单时相同,直接宣告就好
Schema::table('user_settings', function (Blueprint $table) {
$table->integer('height');
});
如果要变更现有的栏位,首先要安装套件
sail composer require doctrine/dbal
然後用套件的 change 方法宣告是要变更现有栏位。
Schema::table('user_settings', function (Blueprint $table) {
$table->string('name', 50)->nullable()->change();
});
套件也有提供变更栏位名称的方法
Schema::table('users', function (Blueprint $table) {
$table->renameColumn('from', 'to');
});
然後是删除栏位的方法,这个也是套件的功能
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('votes');
$table->dropColumn(['avatar', 'location']); //删除多个
});
想将之前设定的外键关联移除的话
$table->dropForeign(['user_id']);
这样只会将关联性移除,栏位会保留
如果是要变更现有的关联关系的话,只能先移除关联後建立新的关联
$table->dropForeign(['user_id']);
$table->foreign('user_id')->references('id')->on('users')
->onDelete('set_null');
删除的话也是一样
$table->dropForeign(['user_id']);
$table->dropColumn('user_id');
一般会用 id 栏位作为主键值
$table->uuid('id')->primary();
若查询时没有指定栏位,就会以主键栏位做查询。
也可以在宣告完所有栏位後再指定 primary 的栏位 ,阅读上会比较容易辨识到主键的设定
$table->uuid('id');
...
$table->primary('id');
注意 primary 宣告必须在栏位被建立後才能执行,不然会报错。
除了主键外有时也需要必须唯独特值的栏位
$table->string('email')->unique();
跟 primary 一样,也可以事後宣告
$table->string('email');
$table->unique('email');
另外偶尔会有需要联合多个栏位为键值的设计
$table->primary(['account_id', 'created_at'],);
$table->unique(['account_id', 'created_at']);
要移除键值的设定的话,以预设的键值名称作为参照
$table->dropPrimary('users_id_primary'); //移除 users 表单中 id 的 primary 设定
$table->dropUnique('users_email_unique'); //移除 users 表单中 email 的 unique 键
Laravel 预设的键值名称会以 "表单_栏位_属性" 构成,如果不想要预设的名称的话,可以在宣告键值时设定名称
$table->primary(['account_id', 'created_at'],"account_created_at");
之後移除时以自订的名称作为参照
$table->dropPrimary('account_created_at');
执行 migration 的基础指令是
sail artisan migrate
这个指令会从最後一次 migration 的档案之後开始执行 migration。
如果想退回 migration
sail artisan migrate:rollback //退回一个 migration
sail artisan migrate:rollback --step=5 //退回 5 个
sail artisan migrate:reset //退回全部
如果想要从头开始执行 migration
sail artisan migrate:refresh // 一步步退回全部後再执行全部
sail artisan migrate:fresh // 不执行退回而是直接删除所有表单,再执行全部
如果在执行完 migration 後想要植入种子资料
sail artisan migrate --seed
开发上最常用的就是整个资料库清空後重新建表单跟塞种子资料
sail artisan migrate:fresh --seed
网页设计 环境:将多页面的档案建立,连结确认彼此间的关系 layout (布局):评估多个页面皆会出...
设计的部分就不多做分析,主要呈现实作成果。 以下内容有参考教学影片,底下有附网址。 (内容包括我的不...
各位早安,今天是第24天,但其实爬虫的技巧大致上已经教得差不多了,而且我猜会看我的文章的人,应该都想...
我们的第一个Lab就从Simple object system开始,程序码我放在这 https://...
在很多情况下,有些错误是我们可以预知的,就比如前面计算两个数相加的代码,在有些情况下,我们可以预知到...