1. 程式人生 > >laravel教程第4課: 玩轉資料遷移laravel migration(超詳細版)

laravel教程第4課: 玩轉資料遷移laravel migration(超詳細版)

這裡寫圖片描述補充上節課:配置虛擬主機
不用修改nginx的配置檔案,減少學習成本,只要在homestead.yaml 和host檔案兩個檔案中做很小的改動就行
D:\03www2018\homestead\Homestead.yaml

map: myblog.app
to: /home/vagrant/abcde/study/myblog/public

C:\Windows\System32\drivers\etc\hosts

  192.168.10.10 www.myblog.app  

D:\03www2018\study\myblog\config\app.php

'timezone' => 'Asia/Shanghai'
,

D:\03www2018\study\myblog.env.home

DB_PREFIX=study_

D:\03www2018\study\myblog\config\database.php

'migrations' => 'migrations2017',
'prefix' => env('DB_PREFIX', ''),

一:資料庫配置

  1. 新建連線和資料庫
    在navicat for mysql中新建連線,使用者名稱homestead,密碼secret,新建資料庫myblog,字符集為utf8mb4 -- UTF-8 Unicode,規則排序為utf8mb4_general_ci
  2. 新增加一個使用者

    GRANT ALL PRIVILEGES ON myblog.* TO [email protected] IDENTIFIED BY ‘daqi168’ WITH GRANT OPTION;

  3. 給應用指定開發環境

    有5個地方可以指定開發環境[我們這裡使用第1種方法或第2種方法]

    • 在homestead.yaml中
    • 在入口檔案的最開始加上 putenv("APP_ENV=home");
    • 修改web伺服器的配置檔案,如nginx配置檔案中加上 env APP_ENV=home;
      apache配置檔案中加上SetEnv APP_ENV home
    • 在.htaccess中加上
    • php主配置檔案php-fpm.conf來設定

修改homestead.yaml加下

    variables:
       - key: 'APP_ENV'
         value: 'home'
       - key: 'APP_DEBUG'
         value: 'true'

4.編輯應用配置檔案.env.home
先生成應用的key

[email protected]:~/abcde/study/myblog$ php artisan key:generate
Application key [base64:s6Rhb/LhTYIpjXi3x+tN9Yon/iBavjnxO4bjXmrYq1g=] set successfully.
將生成的key放在配置檔案.env.home中APP_KEY
有關base64的詳細瞭解參考: 阮一峰的base64筆記
每個laravel必須得生成一個key,它是在加密模組中必須要用到的,

APP_NAME=我的部落格
APP_ENV=local
APP_KEY= base64:s6Rhb/LhTYIpjXi3x+tN9Yon/iBavjnxO4bjXmrYq1g=
APP_DEBUG=true
APP_LOG_LEVEL=debug
APP_URL=http://localhost

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=myblog
DB_USERNAME=daqi
DB_PASSWORD=daqi168
DB_PREFIX=study_ //自己加

D:\03www2018\study\myblog\config\database.php中改

'prefix' => env('DB_PREFIX', ''),
'migrations' => 'migrations2017',

安裝除錯檔案(可選)

[email protected]:~/abcde/study/myblog$ composer require advance100/helper

二:生成第一個遷移檔案

官方文件參考
先了解一下有關migrate的所有命令

make:migration 新建一個遷移檔案
migrate 執行資料庫遷移,這個是安裝軟體時執行的
migrate:fresh 會刪除所有已經生成的表,並重新執行所有的遷移
migrate:install 新建一個遷移倉庫,會在homestead資料庫中生成一個表migrations
migrate:refresh Reset and re-run all migrations
migrate:reset Rollback all database migrations
migrate:rollback 只回滾最後一條遷移
migrate:status 顯示每條遷移的狀態

make:migration

參考: \Illuminate\Database\Console\Migrations\MigrateMakeCommand
檔名格式為: date(‘Y_m_d_His’)的值
檔案的儲存路徑:預設為基本路徑/database/migrations/下面,如果指定了–path引數就是基本路徑/+指定路徑
問題來了?如果我想放在其它路徑,如vendor下面的某個模組下面如做操作?
答:這要用到 php artisan vendor:publish

以新建一個使用者許可權管理為例,建以下幾個表
admins
roles
permissons
role_user
permisson_user

生成建表admins的遷移檔案

vagrant@homestead:~/abcde/study/myblog$ php artisan make:migration create_admins_table
Created Migration: 2017_10_31_231348_create_admins_table

注意make:migration有1個必寫的引數name, 3個可選的選項 –create,–tabel,–path

  1. –path是指定遷移檔案生成的位置,預設是放在 應用根目錄/database/migrations下面,如果指定了–path=x/y/x,就會在 應用根目錄/x/y/z下面生成遷移檔案,注意的是得保證該目錄已存在,否則會報錯
  2. 新建表時,name的寫法可以是 create_表名_table,這種寫法,後面的create可以省略,否則不能省,如make:migration wang –create=members
  3. 選項前有兩個減號–,新手易寫掉一個
  4. –create=表名,新建一個表,表名一般全為小寫字母,複數形式
  5. –table=表名,修改現成的表
  6. –create與–tabel是2選1
  7. 在命令列自動生成的遷移檔案只能是在當前專案下,如果想在專案外如vendor/包/模組中生成遷移檔案,得手工編寫,或自動生成後拷貝到指定地方,但要注意的是模組中的服務提供商中得寫publish方法
  8. 生成的遷移檔名格式是 yyyy_mm_dd_His_name.php,檔案中類名是將name寫在大駝峰的格式,如name為create_admins_table變成class CreateAdminsTable extends Migration
  9. 生成的檔名是可以修改的,用來調整順序,系統的排序是asort(名字名組成的陣列,SORT_REGULAR ); 以升序的方式排列的,所以改名時要注意
  10. 沒有執行migrate之前,遷移檔案是可以手工刪除和改名,修改內容的

按上面生成另外幾個遷移檔案

php artisan make:migration create_roles_table
php artisan make:migration create_permissions_table
php artisan make:migration create_role_user_table
php artisan make:migration create_permission_role_table

三:編輯遷移檔案

up是migrate時執行的方法
down是migrate:rollback,migrate:reset,migrate:fresh,migrate:refresh時會執行的方法
Facade(有人翻譯成門面,我覺得翻譯成表面比較合適些) Schema::方法實際上是執行 \Illuminate\Database\Schema\MySqlBuilder的方法,分下面幾種

判斷的有 hasTable,hasColumn,hasColumns
讀取的有 getAllTables,getColumnListing,getColumnType,getConnection
設定的有 setConnection,blueprintResolver
刪除的有 dropAllTables
操作的有 rename,enableForeignKeyConstraints,disableForeignKeyConstraints
* 遷移常用有 create,table,drop,dropIfExists *

Blueprint(翻譯成藍圖),其實就是代表一個數據庫中的表,它的方法主要有2種,一是針對命令commands的方法,另是針對列columns的方法,命令和列都是一個流Fluent物件,處理命令的方法不多,主要熟悉的是處理列的方法,下面是針對Mysql資料的一些列方法和修飾器

<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateAdminsTable extends Migration{
    public function up(){
        Schema::create('admins', function (Blueprint $table) {       
            $table->charset='utf8mb4';
            $table->collation='utf8mb4_unicode_ci';
            $table->engine='innodb';
            //$table->temporary();
            // 上面四條是演示可以單獨給某個表指定以上屬性
            $table->increments('id');
            $table->string('name')->comment("使用者名稱");
            $table->string('email')->unique()->comment("郵箱必須唯一"); //unique()為索引命令,comment為修飾
            $table->string('password',60)->comment("密碼最長為60個位元組");
            $table->rememberToken()->comment("口令");
            $table->text('description')->nullable()->comment("管理員說明");
            $table->timestamps();
        });
    }

    public function down(){
        Schema::dropIfExists('admins');
    }
}

3.1 列Columns

  • getColumns()獲取藍圖Blueprint的所有列,每一列也是一個流Fluent物件,流物件中有type和name兩個必須指定
  • addColumn(type,name, array $parameters = []) 重點講
  • removeColumn($name)
  • getAddedColumns() 獲取所有新加的列
  • getChangedColumns() 獲取所有改動了的列

3.1.1 字串型別

分類 方法 mysql型別 使用說明
字串01 char(列名, 長度 = null) char 定長字串
字串02 string(列名, 長度 = null) varchar 長度可變字串
字串03 text(列名) text 支援2^16-1個位元組,相當於2.1萬個漢字
字串04 mediumText(列名) mediutext 支援2^24-1個位元組,相當於560萬個漢字
字串05 longText(列名) longtext 支援2^32-1個位元組,相當於14億個漢字
實現01: rememberToken() varchar(100) string(‘remember_token’, 100)->nullable()
實現02: uuid(列名) char(36)
實現03: ipAddress(列名) varchar(45)
實現04: macAddress(列名) varchar(17)

說明1: string長度指的是字元長度,不是位元組,最大支援2^8-1=255個字元,1個數字,字母,漢字都是算一個字元,string(‘name’,25)表示可以儲存25個漢字
說明2: text長度指的是位元組,
說明3: char適合等長密碼,郵編等,預設為…Builder::$defaultStringLength,這個值是可以在服務提供商中修改的
說明4: text與string有些不一樣,在utf8編碼下,一個漢字相當於3個位元組,最大支援21845個漢字,多一個字就會報錯

3.1.2 整數型別

分類 方法 mysql型別 使用說明
整數01 引數(列名, 自增長 = false, 無符號 = false)
tinyIntegert 和 unsignedTinyInteger
tinyint 佔1個位元組,長度2^8
整數02 integer 和 unsignedInteger int 佔2個位元組,長度2^16
整數03 smallInteger 和 unsignedSmallInteger smallint 佔3個位元組,長度2^24
整數04 mediumInteger 和 unsignedMediumInteger mediumint 佔4個位元組,長度 2^32
整數05 bigInteger 和 unsignedBigInteger bigint 佔8個位元組,長度2^63
自增長列01 increments(列名) unsignedInteger(列名, true)
自增長列02 tinyIncrements(列名) unsignedTinyInteger(列名, true)
自增長列03 smallIncrements(列名) unsignedSmallInteger(列名, true)
自增長列04 mediumIncrements(列名) unsignedMediumInteger(列名, true)
自增長列05 bigIncrements(列名) unsignedBigInteger(列名, true)
真假 boolean($column) tinyint(1)

說明1: 整數型別都指定不了長度,也指定不了zerofill,不過這沒有關係,因為整數實際儲存的長度與指定的長度沒有關係,只是顯示的長度而已

3.1.3 小數型別

分類 方法 mysql型別 使用說明
單精度浮點數 float(column,total = 8, $places = 2) 棄用 單精度必須要指定M和D
雙精度浮點數 double(column,total = null, $places = null) double(M,D) 或double
正負定點數 decimal(column,total = 8, $places = 2)
unsignedDecimal
decimal(M,D) 精度和標度必須指定,預設為(8,2)

說明1: float是單精度浮點數,double是雙精度浮點數,decimal是定點數
說明2: float佔4個位元組,double佔8個位元組
說明3: 這3個型別也可以理解為小數
說明4: 浮點數存在誤差問題,定點數精確,對貨幣等對精度敏感的資料,應該用定點數表示或儲存;
說明5: 程式設計中,如果用到浮點數,要特別注意誤差問題,並儘量避免做浮點數比較;
說明6: FLOAT(M,D),DOUBLE(M,D)。表示共M位數,小數點前面為M-D位,小數點後面為D位
說明7: decimal在mysql記憶體是以字串儲存的

3.1.4 日期時間

分類 方法 mysql型別 使用說明
日期 date($column) date
時間 time($column) time
時間 timeTz($column) time
日期時間 dateTime(column,precision = 0) datetime(精度)
datetime
日期時間 dateTimeTz(column,precision = 0) datetime
時間戳 timestamp(column,precision = 0) timestamp 用使用useCurrent使用當前時間
時間戳 timestampTz(column,precision = 0) timestamp
時間戳實現 timestamps(precision=0)...||timestamp(createdat,precision)->nullable();
timestamp(‘updated_at’, $precision)->nullable();
時間戳實現 timestampsTz(precision=0)...||timestampTz(createdat,precision)->nullable();
timestampTz(‘updated_at’, $precision)->nullable();
時間戳實現 nullableTimestamps($precision = 0) 是timestamps的別名
時間戳實現 softDeletes(列名 = ‘deleted_at’,精度 = 0)
時間戳實現 softDeletesTz($precision = 0)

說明01: datetime不支援取預設值now(),版本5.6之後的可以預設值CURRENT_TIMESTAMP,它會取當前時間,並轉為2017-11-01 23:25:45類的格式,但這種情況不能指定精度,另處寫法是new \Illuminate\Database\Query\Expression(‘CURRENT_TIMESTAMP’)才能使用Mysql中的常量
說明02: timestamp(‘列名’,精度),如果指定了精度就不能使用修飾->useCurrent(),框架原始碼此處是一個bug,等修正, 只有不指定精度時才可能使用useCurrent
說明03: datetime(3)意思是保留3為毫秒數,timestamp(‘login’,3);的結果如2017-11-02 02:08:34.864,也是保留3位毫秒
說明04: TZ是系統時區的意思,但實際使用中使用非Tz格式就行
說明05: 未提供year的方法,可能是year的範圍太小的原因捨棄了,可以使用date獲取

日期型別 儲存空間 日期格式 日期範圍
datetime 8 bytes YYYY-MM-DD HH:MM:SS 1000-01-01 00:00:00 至 9999-12-31 23:59:59
timestamp 4 bytes YYYY-MM-DD HH:MM:SS 1970-01-01 00:00:01 至 2038
date 3 bytes YYYY-MM-DD 1000-01-01 至 9999-12-31
year 1 bytes YYYY 1901 至 2155

3.1.5 其它

分類 方法 mysql型別 使用說明
列舉 enum($column, [‘市場部’,’設計部’,’總裁辦’]) 生成enum(‘市場部’,’設計部’,’總裁辦’)
json($column) json 這是5.7.7後才有的功能
jsonb($column) json 這是5.7.7後才有的功能
二進位制 binary($column) blob

說明:json很好用,但要看mysql版本支不支援
說明: 沒有mediumblob和longblob,這樣儲存圖片聲音等檔案沒有辦法,解決辦法是在

Schema::create("member", function($table) {
    // 這裡可以放SchemaBuilder支援的各種方法
});
DB::statement("ALTER TABLE member ADD imagedata MEDIUMBLOB");

3.1.6 空間

MySQL 5.7 GIS特性

方法 mysql型別 使用說明
geometry($column) geometry
point($column) point
lineString($column) linestring
polygon($column) polygon
geometryCollection($column) geometrycollection
multiPoint($column) multipoint
multiLineString($column) multilinestring
multiPolygon($column) multipolygon

3.1.7 綜合實現: 生成索引

morphs($name, $indexName = null){
    $this->unsignedInteger("{$name}_id");
    $this->string("{$name}_type");
    $this->index(["{$name}_id", "{$name}_type"], $indexName);
}

nullableMorphs($name, $indexName = null){
    $this->unsignedInteger("{$name}_id")->nullable();
    $this->string("{$name}_type")->nullable();
    $this->index(["{$name}_id", "{$name}_type"], $indexName);
}

3.2: Blueprint中的列的修飾符

Nullable,Default,Comment,Unsigned,VirtualAs,StoredAs,Charset,Collate,Increment,After,First

3.3 索引

新增索引的命令是

indexCommand(type,columns, index,algorithm = null)

刪除索引的命令是

dropIndexCommand(command,type, $index)

5種索引的單獨命令

命令 實際
primary indexCommand(‘primary’, columns,name, $algorithm)
unique indexCommand(‘unique’, columns,name, $algorithm)
index indexCommand(‘index’, columns,name, $algorithm)
spatialIndex indexCommand(‘spatialIndex’, columns,name)
foreign indexCommand(‘foreign’, columns,name)
dropIndex dropIndexCommand(‘dropIndex’, ‘index’, $index)
dropPrimary dropIndexCommand(‘dropPrimary’, ‘primary’, $index)
dropUnique dropIndexCommand(‘dropUnique’, ‘unique’, $index)
dropForeign dropIndexCommand(‘dropForeign’, ‘foreign’, $index)

說明:如果將某單列定義為某種索引,可以直接按修飾命令的方式定義,如 $table->string(‘name’)->unique();但這種方式不適合外來鍵

3.4 命令

每一個命令都是一個流(Flent)物件,流物件中name必須指定,比如 create()就是在commands增加一個name為create的流物件
處理命令的有: getCommands獲取所有的命令,addCommand,createCommand
判斷是否有create命令creating
對錶create,drop,dropIfExists,rename
對錶中的列,dropColumn,renameColumn

四: 熟悉遷移命令

  1. 生成遷移檔案
    php artisan make:migration create_wang04_table --path=database/migrations2
    php artisan make:migration create_wang05_table --path=database/migrations2
  2. 執行遷移,凡在指定路徑下有的檔名,沒有出現在倉庫表的migration欄位中的,就會執行
    php artisan migrate --database=mysql2 --path=database/migrations2
  3. 撤銷上一步遷移,只一步啊,上一次migrate有多少變動,如生成5張表,這一次會全部撤銷
    php artisan migrate:rollback --database=mysql2 --path=database/migrations2
  4. 撤銷全部,清空倉庫表,除了倉庫表外,所有的表都刪除
    php artisan migrate:reset --database=mysql2 --path=database/migrations2
  5. 刪除所有的表,再重新執行一個遷移,它的效率比6要高
    php artisan migrate:fresh --database=mysql2 --path=database/migrations2
  6. 全部撤銷並重新執行遷移,與fresh的差別是它是一步一步的撤銷,原來假設有78步,那麼就一步一步撤,再一步一步執行,它倆有一個共同點是,最後只算一批,也就是所有的遷移是一批,倉庫表中的batch值全部為1
    php artisan migrate:refresh --database=mysql2 --path=database/migrations2
  7. 顯示當前遷移的狀態
    php artisan migrate:status --database=mysql2 --path=database/migrations2
id migration batch
6 2017_11_02_091523_wang01 1
7 2017_11_02_103519_create_json_table 1
8 2017_11_02_142016_create_wang01_table 1
9 2017_11_02_142040_create_wang02_table 1
10 2017_11_02_142103_create_wang03_table 1
11 2017_11_02_142928_create_wang04_table 2
12 2017_11_02_143043_create_wang05_table 3
13 2017_11_02_143104_create_wang06_table 3

migate命令會將沒有執行過的遷移檔案執行,有幾個執行幾個
migrate:rollback 只會撤銷最後一批,如上面會撤銷第3批生成的兩個表
migrate:install 用來生成倉庫表,不用執行,系統會自動執行,且只會執行一次,該表不會被撤銷
migrate:status 顯示哪些遷移檔案還未執行,N表示還未執行
migrate:reset Rollback all database migrations
migrate:fresh 會刪除所有已經生成的表,並重新執行所有的遷移
migrate:refresh Reset and re-run all migrations

Ran? Migration
Y 2017_11_02_091523_wang01
Y 2017_11_02_103519_create_json_table
Y 2017_11_02_142016_create_wang01_table
Y 2017_11_02_142040_create_wang02_table
Y 2017_11_02_142103_create_wang03_table
Y 2017_11_02_142928_create_wang04_table
N 2017_11_02_143043_create_wang05_table
N 2017_11_02_143104_create_wang06_table

五: 遷移檔案釋出

資料遷移檔案一般與模組放在一起,比如你開發了一個模組,有自己的資料表,當別人使用你的模組時,得先將你的資料遷移檔案拷貝到應用的指定資料夾下。這樣很不方便,所以得在模組的服務提供商檔案中寫好釋出方法

<?php
namespace Wang\Providers;
use Illuminate\Support\ServiceProvider;
class ModuleServiceProvider extends ServiceProvider{
    protected $defer = false;
    public function boot(){
          $this->publishMigrations(); 
    }
    private function publishMigrations()    {
        $this->publishes([__DIR__ . '/../../migrations/' => base_path('database/migrations2')],