Migrasi Laravel: kunci unik terlalu panjang, bahkan jika ditentukan


166

Saya mencoba memigrasi tabel pengguna di Laravel. Ketika saya menjalankan migrasi saya, saya mendapatkan kesalahan ini:

[Illuminate \ Database \ QueryException] SQLSTATE [42000]: Kesalahan sintaksis atau pelanggaran akses: 1071 Kunci yang ditentukan terlalu panjang; panjang kunci maks adalah 767 byte (SQL: alter table usersadd unique users_email_uniq ( email))

migrasi saya adalah sebagai berikut:

Schema::create('users', function(Blueprint $table)
{
    $table->increments('id');
    $table->string('name', 32);
    $table->string('username', 32);
    $table->string('email', 320);
    $table->string('password', 64);
    $table->string('role', 32);
    $table->string('confirmation_code');
    $table->boolean('confirmed')->default(true);
    $table->timestamps();

    $table->unique('email', 'users_email_uniq');
});

Setelah beberapa googling saya menemukan laporan bug ini di mana Taylor mengatakan Anda dapat menentukan kunci indeks sebagai parameter ke-2 unique(), yang telah saya lakukan. Itu masih memberi kesalahan. Apa yang terjadi disini?


Mengapa Anda menggunakan 320 karakter untuk email? Ini mungkin masalah Anda.
Antonio Carlos Ribeiro

1
Itu memang masalahnya, tidak tahu kenapa. Tapi ya, Anda benar, saya tidak tahu mengapa saya menentukan panjang karakter untuk setiap bidang. Telah menghapus batasan ini
harryg

Sangat lucu bagaimana tidak ada yang menyarankan menggunakan bidang tetap-panjang yang berisi hash dari email dan voila - masalah diselesaikan selamanya, untuk kerangka kerja apa pun dan untuk basis data relasional. Karena itulah cara kami menjamin keunikan - menggunakan representasi angka-tetap dari input panjang variabel, mengingat fakta bahwa kisaran angka cukup besar (dan untuk sha1 / sha256 begitu).
NB


Jawaban:


280

Tentukan panjang yang lebih kecil untuk email Anda:

$table->string('email', 250);

Yang merupakan default, sebenarnya:

$table->string('email');

Dan kamu harus baik.

Untuk Laravel 5.4 Anda dapat menemukan solusi dalam Laravel 5.4 ini: Kunci yang ditentukan adalah kesalahan yang terlalu panjang, Laravel News post:

Seperti yang diuraikan dalam panduan Migrasi untuk memperbaikinya, yang harus Anda lakukan adalah mengedit file AppServiceProvider.php Anda dan di dalam metode boot, tentukan panjang string default:

use Illuminate\Database\Schema\Builder;


public function boot()
{
    Builder::defaultStringLength(191);
}

6
Panjang email maksimum yang mungkin 254mungkin patut diingat, jadi saya mungkin akan memvalidasi keunikan menggunakan validator dalam kasus itu.
Sebastian Sulinski

12
Untuk Laravel 5.4 , gunakan \Illuminate\Database\Schema\Builder::defaultStringLength(191);untuk jalur referensi fungsi yang benar
webcoder

5
Setelah membuat konfigurasi di AppServiceProvider.php, masalah ini masih terjadi. Saya hanya bingung. Mengapa? Saya me-restart server, database, dan semuanya, tetapi tetap saja. Tolong bantu.
Koushik Das

3
Anda harus mengatur panjang kolom yang diindeks sesuai dengan batas 767 byte. Ketahuilah bahwa VARCHAR mungkin memiliki 1, 2 atau 4 byte untuk setiap unit panjang. Contoh: utf8_mb4 (4 byte) -> 767/4 = 191. Jika tidak utf8_general_ci untuk VARCHAR (X) dengan X <85 (1 byte) = O (85), atau utf8_general_ci untuk VARCHAR (X) dengan X> = 86 (2) byte) -> 767/2 = 383. Pertimbangkan juga kolom lain yang panjang dalam indeks banyak kolom.
Jackie Degl'Innocenti

2
Anda mungkin juga ingin mengedit secara langsung panjang kolom tertentu dalam file migrasi, lebih dari menentukan panjang default untuk semua kolom string, karena tidak semua kolom akan membutuhkan kendala ini karena mereka tidak ada dalam indeks apa pun. $ table-> string ('column_name', 191);
Jackie Degl'Innocenti

109

Perbarui 1

Pada Laravel 5.4, perubahan itu tidak diperlukan lagi.

Laravel 5.4 menggunakan karakter utf8mb4 yang ditetapkan secara default, yang mencakup dukungan untuk menyimpan "emoji" dalam database. Jika Anda meningkatkan aplikasi dari Laravel 5.3, Anda tidak diharuskan untuk beralih ke rangkaian karakter ini.

Perbarui 2

Versi produksi MariaDB saat ini TIDAK mendukung pengaturan ini secara default secara global. Ini diterapkan di MariaDB 10.2.2+ secara default .

Larutan

Dan jika Anda ingin menggunakan masa depan-standar yang benar (mulai dari Laravel 5.4) utf8mb4dukungan multi-byte UTF8 untuk πŸ˜€ maka mulailah untuk memperbaiki configuration konfigurasi basis data Anda.

Dalam Laravel config/database.phpdefine:

'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'engine' => 'InnoDB ROW_FORMAT=DYNAMIC',

DYNAMICmemungkinkan untuk menyimpan indeks kunci yang panjang .

Pengaturan server (secara default termasuk dalam MySQL 5.7.7+ / MariaDB 10.2.2+):

[mysqld]
# default character set and collation
collation-server = utf8mb4_unicode_ci
character-set-server = utf8mb4

# utf8mb4 long key index
innodb_large_prefix = 1
innodb_file_format = barracuda
innodb_file_format_max = barracuda
innodb_file_per_table = 1

Untuk klien:

[mysql]
default-character-set=utf8mb4

Dan kemudian BERHENTI server MySQL / MariaDB Anda. Setelah itu MULAI. Hot RESTART mungkin tidak berfungsi.

sudo systemctl stop mysqld
sudo systemctl start mysqld

Sekarang Anda memiliki Laravel 5.x dengan dukungan UTF8.


3
Ini mungkin cukup baik dengan MySQL 5.5 (tidak mencoba mengkonfigurasi ulang). The 5.7 (mungkin juga 5.6) bekerja tanpa perlu konfigurasi ulang. The 5.7 adalah distribusi Server Komunitas default dengan konfigurasi vanilla.
Pjotr

Saya mengubah mesin di database.php saya seperti yang Anda sebutkan, tetapi masih membuat tabel dengan baris = kompak yang menyebabkan masalah. Saya tidak sepenuhnya mengerti, apakah Anda mengatakan bahwa itu tidak cukup untuk membuat perubahan dalam database.php dan juga diperlukan untuk membuat perubahan pada file my.cnf?
vesperknight

Sudah cukup untuk membuat perubahan hanya dalam database.phpfile konfigurasi dan itu akan berdampak pada proyek Laravel lokal. Pastikan untuk deletemembuat basis data sebelum membuat perubahan dan membuatnya dengan pengaturan baru. Anda perlu mengubah my.cnffile konfigurasi hanya untuk perubahan sisi server global (saat ini semua instalasi baru menggunakan utf8mb4).
pencetak gol

Atau - tambahkan bidang lain, hitung hash email, buat bidang unik, selesaikan masalah selamanya, hindari mengutak-atik variabel inisialisasi basis data.
NB

Jika ada yang menggunakan Doctrine 2 , Anda dapat mengatur ROW_FORMAT dengan memberikan anotasi options={"row_format"="DYNAMIC"}Anda @Table.
Albert221

50

Jika Anda menggunakan atau memperbarui ke Laravel 5.4 Ini bekerja untuk saya;

Hanya 1 perubahan. di AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

public function boot()
{
  Schema::defaultStringLength(191);
}

Seperti disebutkan dalam panduan migrasi https://laravel.com/docs/master/migrations#creating-indexes


Saya melakukan ini pada migrasi itu sendiri.
Amirmasoud

7
Ini (mungkin) karena setiap karakter membutuhkan tepat 4 byte, dan panjang kunci maksimum diukur dalam byte, bukan karakter. Jadi panjang kunci akan 191 * 4 = 764 byte, hanya sedikit di bawah maksimum 767 byte database akan mendukung. Solusi membutuhkan penjelasan IMO jika mereka ingin berkontribusi pada pengetahuan bersama di sini, dan tidak hanya memberikan "prosedur". Namun perbaikan praktis tetap dilakukan.
Jason

33

Jika orang lain menemukan jawaban ini seperti yang saya lakukan tetapi untuk alasan yang berbeda, Anda dapat memeriksa charset / collation Laravel DB Anda.

Saya menginstal aplikasi (Snipe-IT) dan telah mengkonfigurasi konfigurasi database Laravel untuk menggunakan yang berikut:

'charset' => 'utf8mb4',
'collation' => 'utf8mb4_general_ci',

Menghapus mb4dari kedua string memperbaiki masalah, meskipun saya percaya jawaban Antonio adalah solusi nyata untuk masalah tersebut.



16

Hapus mb4 dari charset dan collation dari config / database.php, maka itu akan berhasil dijalankan.
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',


15

Untuk laravel 5.6
Solusi ini menyelesaikan masalah saya,
buka config/database.php
Cari kode di bawah ini

'mysql' => [
    'driver' => 'mysql',
    'host' => env('DB_HOST', '127.0.0.1'),
    'port' => env('DB_PORT', '3306'),
    'database' => env('DB_DATABASE', 'forge'),
    'username' => env('DB_USERNAME', 'forge'),
    'password' => env('DB_PASSWORD', ''),
    'unix_socket' => env('DB_SOCKET', ''),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'strict' => true,
    'engine' => null,
],

Ubah dua bidang ini

'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci'

Dengan ini

'charset' => 'utf8',
'collation' => 'utf8_unicode_ci'

14

Saya telah menghadapi masalah yang sama, dan memperbaikinya dengan menambahkan dua baris di bawah ini di app / database.php saya

'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',

File saya terlihat seperti di bawah ini:

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Default Database Connection Name
    |--------------------------------------------------------------------------
    |
    | Here you may specify which of the database connections below you wish
    | to use as your default connection for all database work. Of course
    | you may use many connections at once using the Database library.
    |
    */

    'default' => env('DB_CONNECTION', 'mysql'),

    'charset' => 'utf8',
    'collation' => 'utf8_unicode_ci',

    ......

2
Jika Anda menginstal versi baru di Laravel. Hapus 'mb4' dari utf8mb4 & utf8mb4_unicode_ci & config / database.php
Muthu17

13

Untuk laravel 5.4, cukup edit file

App \ Providers \ AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

public function boot()
{
    Schema::defaultStringLength(191);
}

7
File: config/database.php
change the following
FROM ->
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',

TO ->
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',

1
Meskipun ini dapat menjawab pertanyaan, lebih baik menambahkan deskripsi tentang bagaimana jawaban ini dapat membantu menyelesaikan masalah. Silakan baca Bagaimana saya menulis jawaban yang bagus untuk mengetahui lebih banyak.
Roshana Pitigala

6

Saya punya masalah yang sama dan saya menggunakan wamp

Solusi: Buka file: config / database.php

'engine' => null, => 'engine' => 'InnoDB',

Terima kasih


Tidak ada jawaban sebelumnya yang bekerja untuk saya, tetapi yang ini bekerja seperti pesona! Dan itu masuk akal, saya percaya pada versi sebelumnya dari mesin Laravel DB diatur ke InnoDB secara default sehingga kami tidak menemukan kesalahan ini sebelumnya.
Sasa Blagojevic

ya perlu melakukan beberapa jawaban lain dan ini juga.
Andrew

6

Dalam file config / database.php di mana:

'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',

Ubah baris ini menjadi ini:

'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',

5

Untuk Laravel> = 5.6 pengguna

Buka AppServiceProvider.phpfile

Gunakan kelas berikut

use Illuminate\Support\Facades\Schema;

Kemudian di dalam bootmetode tambahkan baris berikut

public function boot()
{
    Schema::defaultStringLength(191);
}

4

Saya menambahkan ke migrasi itu sendiri

Schema::defaultStringLength(191);
Schema::create('users', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->string('email')->unique();
    $table->string('password');
    $table->rememberToken();
    $table->timestamps();
});

ya, saya tahu saya harus mempertimbangkannya pada setiap migrasi tapi saya lebih suka daripada menyimpannya di beberapa penyedia layanan yang sama sekali tidak terkait


4

Jika seseorang mengalami masalah ini bahkan setelah melakukan, perubahan yang disebutkan di atas. Sebagai contoh, dalam kasus saya, saya melakukan perubahan di bawah ini,

namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;

class AppServiceProvider extends ServiceProvider
{
  /**
   * Register any application services.
   *
   * @return void
   */
   public function register()
   {
      //
   }

   public function boot()
   {
     Schema::defaultStringLength(191);
   }
}

Tapi itu tidak akan berhasil karena dua alasan. Salah satunya adalah jika Anda menggunakan lumen alih-alih laravel, Anda mungkin harus menghapus komentar baris ini di file app.php Anda terlebih dahulu.

$app->register(App\Providers\AppServiceProvider::class);

Dan kemudian Anda harus membuat skrip migrasi lagi dengan perintah artisan,

php artisan make:migration <your_table_name>

Karena sekarang hanya perubahan yang Anda buat pada ServiceProvider yang akan berfungsi.


4

untuk laravel 5.7 tulis kode ini di appserviceprovider.php

  use Illuminate\Support\Facades\Schema;

public function boot()
{
  Schema::defaultStringLength(191);
}

2

Ubah charset dari 'utf8mb4' ke 'utf8' dan

susun ke 'utf8mb4_unicode_ci' ke 'utf8_unicode_ci'

dalam file config / database.php

Ini berhasil untuk saya.


2

Laravel menggunakan utf8mb4karakter yang ditetapkan secara default, yang mencakup dukungan untuk menyimpan "emoji" dalam database. Jika Anda menjalankan versi MySQL yang lebih lama dari rilis 5.7.7 atau MariaDB yang lebih lama dari rilis 10.2.2, Anda mungkin perlu mengkonfigurasi secara manual panjang string default yang dihasilkan oleh migrasi agar MySQL dapat membuat indeks untuk mereka. Anda dapat mengonfigurasikan ini dengan memanggil Schema::defaultStringLengthmetode di dalam AppServiceProvider:

use Illuminate\Support\Facades\Schema;

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    Schema::defaultStringLength(191);
}

Anda bisa keluar

https://laravel-news.com/laravel-5-4-key-too-long-error https://laravel.com/docs/5.5/migrations#indexes


terima kasih, bekerja untuk saya. mamp mysql dengan laravel 5.6.23
bluesky

2

Itu karena Laravel 5.4 menggunakan utf8mb4 yang mendukung penyimpanan emoji.

Tambahkan ini di aplikasi Anda \ Providers \ AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

public function boot()
{
    Schema::defaultStringLength(191);
}

dan kamu harus baik untuk pergi.


2

Jika Anda menggunakan atau diperbarui ke Laravel 5.4 dan versi terbaru berfungsi;
Hanya 1 perubahan di AppServiceProvider.php

use Illuminate\Support\Facades\Schema;

public function boot()
{
  Schema::defaultStringLength(191);
}

1

Saya ingin menunjukkan sesuatu yang saya lewatkan ...

Saya baru di Laravel, dan saya tidak menyalin "gunakan Illuminate ....." karena saya benar-benar tidak memperhatikan, karena tepat di atas fungsi boot yang telah Anda gunakan. Pernyataan .

Semoga itu bisa membantu siapa saja

**use Illuminate\Support\Facades\Schema;**

public function boot()
{
    Schema::defaultStringLength(191);
}

Anda juga dapat hanya \
mengawali

1

Saya punya masalah, ubah konfigurasi 'config / database'

file 'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',

menjaga pola yang sama di dalam basis data.

Saya kemudian memberi perintah

php artisan migrate

1

Pada 24 Oktober 2016 Taylor Otwell , Pengarang Laravel yang diumumkan di Twitter

"utf8mb4" akan menjadi karakter default MySQL yang diatur dalam Laravel 5.4 untuk dukungan emoji yang lebih baik. πŸ™Œ Posting Twitter Taylor Otwell

yang sebelum versi 5.4 set karakter utf8

Selama abad ini banyak aplikasi web, termasuk obrolan atau semacam platform untuk memungkinkan penggunanya melakukan percakapan, dan banyak orang suka menggunakan emoji atau smiley. dan ini adalah semacam karakter super yang membutuhkan lebih banyak ruang untuk disimpan dan itu hanya mungkin digunakan utf8mb4sebagai charset . Itulah alasan mengapa mereka bermigrasi utf8mb4hanya untuk tujuan ruang.

jika Anda mencari di Illuminate\Database\Schema\Builderkelas Anda akan melihat bahwa $defaultStringLengthdiatur ke 255 , dan untuk memodifikasi bahwa Anda dapat melanjutkan melalui SchemaFacade dan memanggildefaultStringLength metode dan melewati panjang baru.

untuk melakukan perubahan itu panggil metode itu di dalam AppServiceProviderkelas Anda yang berada di bawah subdirektori app \ provider seperti ini

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        // all other code ...

        Schema::defaultStringLength(191); 
    }
    // and all other code goes here
}

Saya akan menyarankan untuk menggunakan 191 sebagai nilai hanya karena MySQL mendukung 767 byte, dan karena 767 / 4yang merupakan jumlah byte yang diambil oleh setiap karakter multibyte Anda akan mendapatkan191 .

Anda dapat mempelajari lebih lanjut di sini Set Karakter utf8mb4 (Encoding Unicode UTF-8 4-Byte) Batas pada Jumlah Kolom Tabel dan Ukuran Baris


Ini adalah satu-satunya jawaban yang menjelaskan angka 191ajaib.
Illya Moskvin


1

Pergi ke Anda config/database.phpdan ubah charset dan collation dari utf8mb4 ke utf8

'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',

Masalah saya terpecahkan dengan menggunakan metode ini, selamat mencoba Bung!


0

Anda tidak akan memiliki masalah ini jika Anda menggunakan MySQL 5.7.7+ atau MariaDB 10.2.2+.

Untuk memperbarui MariaDB di Mac Anda menggunakan Brew terlebih dahulu putuskan tautan yang sekarang: brew unlink mariadbdan kemudian instal yang menggunakanbrew install mariadb --devel

Setelah instalasi selesai, hentikan / mulai menjalankan layanan: brew services stop mariadb brew services start mariadb

Versi dev saat ini adalah 10.2.3. Setelah instalasi selesai Anda tidak perlu khawatir tentang ini lagi dan Anda dapat menggunakan utf8mb4 (yang sekarang menjadi default di Laravel 5.4) tanpa beralih kembali ke utf8 atau mengedit AppServiceProvider seperti yang diusulkan dalam dokumentasi Laravel: https: // laravel .com / docs / master / rilis # laravel-5.4 (gulir ke bawah ke: Panjang String Default Migrasi )


0

Baru saja menginstal MariaDB 10.2.4 RC, menjalankan kolom proyek Laravel 5.4 baru dan migrasi default (varchar (255)).

Tidak perlu mengubah DB conf dan Laravael config/database.php. Demikian seperti yang dicatat oleh @scorer tentang perilaku default untuk 10.2.2+.


0

Semua dijelaskan dengan baik di Anwser yang lain, Anda dapat melihat lebih detail di tautan di bawah (cari dengan kunci 'Panjang Indeks & MySQL / MariaDB ") https://laravel.com/docs/5.5/migrations

TAPI BAIK ITU bukan tentang apa jawaban ini! masalahnya adalah bahkan dengan melakukan hal di atas Anda akan suka mendapatkan kesalahan lain (saat itulah Anda suka meluncurkan php artisan migrateperintah dan karena masalah panjangnya, operasi seperti macet di tengah. solusinya di bawah , dan tabel pengguna seperti dibuat tanpa sisanya atau tidak sepenuhnya benar) kita perlu roll bac k. rollback default tidak akan berfungsi. karena operasi migrasi tidak suka selesai. Anda perlu menghapus tabel yang baru dibuat dalam database secara manual.

kita bisa melakukannya menggunakan tinker seperti di bawah ini:

L:\todos> php artisan tinker

Psy Shell v0.8.15 (PHP 7.1.10 β€” cli) by Justin Hileman

>>> Schema::drop('users')

=> null

Saya sendiri punya masalah dengan tabel pengguna.

setelah itu bagus kamu pergi

php artisan migrate:rollback

php artisan migrate

0

Setel mesin basis data InnoDB:

  Schema::create('users', function (Blueprint $table) {
            $table->engine = 'InnoDB';
            $table->increments('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });

0

Jika Anda telah mencoba setiap jawaban lain dan mereka tidak berfungsi, Anda dapat menghapus semua tabel dari database dan kemudian menjalankan perintah migrasi sekaligus menggunakan perintah ini:

php artisan migrate:fresh
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.