Lỗi di chuyển của Laravel: Lỗi cú pháp hoặc vi phạm truy cập: 1071 Khóa được chỉ định quá dài; độ dài khóa tối đa là 767 byte


177

Lỗi di chuyển trên Laravel 5.4 với php artisan make:auth

[Illuminate \ Database \ QueryException] SQLSTATE [42000]: Lỗi cú pháp hoặc vi phạm truy cập: 1071 Khóa được chỉ định quá dài; độ dài khóa tối đa là 767 byte (SQL: thay đổi tabl e usersadd unique users_email_unique( email))

[PDOException] SQLSTATE [42000]: Lỗi cú pháp hoặc vi phạm truy cập: 1071 Khóa được chỉ định quá dài; độ dài khóa tối đa là 767 byte


3
Bạn nên trả lời câu hỏi của bạn trong một câu trả lời. Không có trong câu hỏi. stackoverflow.com/help/elf-answer
Can Vural

Cảm ơn lời đề nghị @ can-vural, tôi đã làm.
absiddiqueLive

Câu trả lời:


283

Theo tài liệu chính thức , bạn có thể giải quyết điều này khá dễ dàng.

Thêm hai dòng mã sau vào AppServiceProvider.php (/app/Providers/AppServiceProvider.php)

use Illuminate\Database\Schema\Builder; // Import Builder where defaultStringLength method is defined

function boot()
{
    Builder::defaultStringLength(191); // Update defaultStringLength
}

MySQL luôn dự trữ số tiền tối đa cho trường UTF8 là 4 byte, vì vậy với 255 + 255 với DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; bạn vượt quá giới hạn chiều dài khóa tối đa 767. Bởi @scaisedge


3
Hãy cẩn thận về giải pháp này. Nếu bạn lập chỉ mục các trường email chẳng hạn, các email được lưu trữ chỉ có thể có độ dài tối đa là 191 ký tự. Điều này ít hơn các quốc gia RFC chính thức.
shock_gone_wild 16/2/2017


Nó đang hoạt động và là một giải pháp hợp lệ, nhưng tôi chỉ muốn chỉ ra rằng, có những cạm bẫy có thể xảy ra khi sử dụng phương pháp này.
shock_gone_wild 17/2/2017

Tôi hy vọng giải pháp này sẽ không cắn vào mông tôi trong tương lai, nhưng bây giờ, cách này hiệu quả. Tôi sẽ phải cẩn thận với cách tôi lập chỉ mục email.
deusofnull

4
tại sao chính xác là 191 ký tự @absiddiqueLive
PseudoAj

121

Tôi không biết tại sao giải pháp trên và giải pháp chính thức được thêm vào

Schema::defaultStringLength(191);

trong AppServiceProviderkhông làm việc cho tôi. Những gì làm việc là chỉnh sửa các database.phptập tin trong configthư mục. Chỉ cần chỉnh sửa

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

đến

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

và nó sẽ hoạt động, mặc dù bạn sẽ không thể lưu trữ các ký tự đa nhân mở rộng như biểu tượng cảm xúc .

Tôi đã làm điều đó với Laravel 5.7. Hy vọng nó giúp.


5
Sử dụng bộ ký tự này sẽ chỉ cho phép bạn lưu ASCII tiêu chuẩn chứ không phải các ký tự đặc biệt đa dòng như các ký tự từ tiếng Ả Rập, tiếng Do Thái, hầu hết các chữ viết châu Âu và tất nhiên là cả biểu tượng cảm xúc. xem thêm stackoverflow.com/a/15128103/4233593
Jeff Puckett

7
Tôi nghĩ rằng bạn đã bỏ lỡ phần này use Illuminate\Support\Facades\Schema;ở đầu.
ma cô

@KoushikBạn đang sử dụng phiên bản nào của Laravel?
ma cô

Bây giờ tôi đang trên 6.0. Tôi nghĩ rằng tôi đã làm nó ban đầu với 5,7 hoặc 5,6 có thể.
Koushik Das

2
Đối utf8mb4chiếu là có lý do, tôi khuyên bạn nên sử dụng nó nếu bạn có thể.
Ngọn lửa

85

Tôi chỉ thêm câu trả lời này vào đây vì đây là quickestgiải pháp cho tôi. Chỉ cần đặt công cụ cơ sở dữ liệu mặc định thành 'InnoDB'bật

/config/database.php

'mysql' => [
    ...,
    ...,
    'engine' => 'InnoDB',
 ]

sau đó chạy php artisan config:cacheđể xóa và làm mới bộ đệm cấu hình


1
Đây phải là câu trả lời / giải pháp chính thức cho câu hỏi này ... Cảm ơn
Syamsoul Azrien 20/03/19

1
Đây là giải pháp thực tế, những giải pháp khác là cách giải quyết
Luís Cunha

3
nhưng logic đằng sau điều này
Zulfiqar Tariq

1
Đó là giải pháp chính xác. Nhưng tại sao nó không được bao gồm trong cài đặt mặc định.
Ankit Chauhan

38

Trong AppServiceProvider.php, bạn bao gồm mã này trên cùng của tệp.

use Illuminate\Support\Facades\Schema;

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

Cảm ơn đã giúp tôi ra ngoài
Người chết

24

Vấn đề này được gây ra trong Laravel 5.4 bởi phiên bản cơ sở dữ liệu.

Theo các tài liệu (trong Index Lengths & MySQL / MariaDBphần):

Laravel sử dụng bộ utf8mb4ký tự theo mặc định, bao gồm hỗ trợ lưu trữ "biểu tượng cảm xúc" trong cơ sở dữ liệu. Nếu bạn đang chạy phiên bản MySQL cũ hơn bản phát hành 5.7.7 hoặc MariaDB cũ hơn bản phát hành 10.2.2, bạn có thể cần phải định cấu hình thủ công độ dài chuỗi mặc định được tạo bởi di chuyển để MySQL tạo chỉ mục cho chúng. Bạn có thể cấu hình điều này bằng cách gọi Schema::defaultStringLengthphương thức trong của bạn AppServiceProvider.

Nói cách khác, trong <ROOT>/app/Providers/AppServiceProvider.php:

// Import Schema
use Illuminate\Support\Facades\Schema;
// ...

class AppServiceProvider extends ServiceProvider
{

public function boot()
{
    // Add the following line
    Schema::defaultStringLength(191);
}

// ...

}

Nhưng như nhận xét về câu trả lời khác nói:

Hãy cẩn thận về giải pháp này. Nếu bạn lập chỉ mục các trường email chẳng hạn, các email được lưu trữ chỉ có thể có độ dài tối đa là 191 ký tự. Điều này ít hơn các quốc gia RFC chính thức.

Vì vậy, tài liệu cũng đề xuất một giải pháp khác:

Ngoài ra, bạn có thể kích hoạt innodb_large_prefixtùy chọn cho cơ sở dữ liệu của bạn. Tham khảo tài liệu của cơ sở dữ liệu của bạn để biết hướng dẫn về cách bật tùy chọn này.


16

Đối với một người không muốn thay đổi AppServiceProvider.php. (Theo tôi, đó là ý tưởng tồi để thay đổi AppServiceProvider.phpchỉ để di chuyển)

Bạn có thể thêm lại chiều dài dữ liệu vào tệp di chuyển database/migrations/như bên dưới:

create_users_table.php

$table->string('name',64);
$table->string('email',128)->unique();

create_password_resets_table.php

$table->string('email',128)->index();

Đây có thể là một vấn đề vì email có thể lên tới 255 (ish) ký tự
Half Crazing

Bạn nói đúng @HalfCraened, nhưng tôi đề nghị câu trả lời này stackoverflow.com/questions/1297272
helloroy

vấn đề của tôi chính xác đã được giải quyết bằng giải pháp này. Lĩnh vực của tôi không phải là email.
Tharaka Devinda

11

Nếu bạn gặp phải lỗi này trong khi làm việc trên laravel trong khi sử dụng lệnh: php artisan migrate thì bạn chỉ cần thêm 2 dòng trong tệp: app-> Providers-> AppServiceProvider.php

  1. use Schema;
  2. Schema::defaultStringLength(191);

hãy kiểm tra hình ảnh này . sau đó chạy php artisan migratelại lệnh.


1
rất quan trọng để thêm 'sử dụng Schema;'. Vì vậy, đây là câu trả lời tốt nhất
hxwtch

Bạn cũng có thể thực hiện việc này trong một dòng bằng cách thêm dấu gạch chéo ngược '\' trước dòng thứ 2 như thế này\Schema::defaultStringLength(191);
Tahir Afridi

10

Tôi thêm hai sollution rằng công việc cho tôi.

Giải pháp đầu tiên là :

  1. Mở cơ sở dữ liệu tập tin ins.php cấu hình thư mục / thư mục.
  2. Chỉnh sửa 'engine' => null,thành'engine' => 'InnoDB',

    Điều này làm việc cho tôi.

Giải pháp thứ 2 là:

  1. Mở database.php tập tin insde cấu hình dir / thư mục.
    2. Chỉnh sửa
    'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci',
    thành

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


Chúc may mắn


10

cập nhật và chèn các dòng này trong ứng dụng / Nhà cung cấp / AppServiceProvider.php

use Illuminate\Support\Facades\Schema;  // add this line at top of file

public function boot()
{
    Schema::defaultStringLength(191); // add this line in boot method
}

8

Tôi đã giải quyết vấn đề này và chỉnh sửa tệp config-> database.php để thích cơ sở dữ liệu của tôi ('charset' => 'utf8')('collation' => 'utf8_general_ci') , vì vậy vấn đề của tôi được giải quyết bằng mã theo:

'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' => 'utf8',
        'collation' => 'utf8_general_ci',
        'prefix' => '',
        'strict' => true,
        'engine' => null,
    ],

8

Tôi đã tìm thấy hai giải pháp cho lỗi này

LỰA CHỌN 1:

Mở bảng người dùngpassword_reset của bạn trong thư mục cơ sở dữ liệu / di chuyển

Và chỉ cần thay đổi độ dài của email:

$table->string('email',191)->unique();

LỰA CHỌN 2:

Mở app/Providers/AppServiceProvider.phptệp của bạn và bên trong boot()phương thức đặt độ dài chuỗi mặc định:

use Illuminate\Support\Facades\Schema;

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

7

1- Đi /config/database.phpvà tìm những dòng này

'mysql' => [
    ...,
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    ...,
    'engine' => null,
 ]

và thay đổi chúng thành:

'mysql' => [
    ...,
    'charset' => 'utf8',
    'collation' => 'utf8_unicode_ci',
    ...,
    'engine' => 'InnoDB',
 ]

2- Chạy php artisan config:cacheđể cấu hình lại laravel

3- Xóa các bảng hiện có trong cơ sở dữ liệu của bạn và sau đó chạy php artisan migratelại


1
đây là câu trả lời tốt nhất cho laravel 5.8. Nhưng xóa các bảng đã được tạo
Magige Daniel

Nhưng theo tài liệu "utf8" sẽ sử dụng chế độ utf8 không dùng nữa?
NoBugs

5

Trong tệp AppServiceProvider.php :

 use Illuminate\Support\Facades\Schema;

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

5

Thay vì đặt giới hạn về độ dài, tôi sẽ đề xuất những điều sau đây, điều này có hiệu quả với tôi.

Phía trong:

cấu hình / cơ sở dữ liệu.php

thay thế dòng này cho mysql:

'engine' => 'InnoDB ROW_FORMAT=DYNAMIC',

với:

'engine' => null,

4

Như được nêu trong hướng dẫn Di chuyển để khắc phục điều này, tất cả những gì bạn phải làm là chỉnh sửa app/Providers/AppServiceProvider.phptệp của mình và bên trong phương thức khởi động đặt độ dài chuỗi mặc định:

use Illuminate\Support\Facades\Schema;

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

Lưu ý: trước tiên, bạn phải xóa (nếu bạn có) bảng người dùng , bảng password_resets khỏi cơ sở dữ liệu và xóa các mục nhập của người dùng và password_resets khỏi bảng di chuyển .

Để chạy tất cả các lần di chuyển nổi bật của bạn, hãy thực hiện migratelệnh Artisan:

php artisan migrate

Sau đó mọi thứ sẽ hoạt động như bình thường.


4

Như đã chỉ định, chúng tôi thêm vào AppServiceProvider.php trong App / Providers

use Illuminate\Support\Facades\Schema;  // add this

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

bạn có thể xem thêm chi tiết trong liên kết dưới đây (tìm kiếm "Độ dài chỉ mục & MySQL / MariaDB") https://laravel.com/docs/5.5/migations

NHƯNG R THNG đó không phải là những gì tôi đã xuất bản tất cả về! Vấn đề là ngay cả khi thực hiện các thao tác trên, bạn có thể sẽ gặp một lỗi khác (đó là khi bạn chạy php artisan migratelệnh và do vấn đề về độ dài, thao tác có thể sẽ bị kẹt ở giữa. Giải pháp bên dưới và bảng người dùng có thể được tạo không có phần còn lại hoặc không hoàn toàn chính xác) chúng ta cần quay lại . cuộn lại mặc định sẽ không hoạt động. bởi vì hoạt động di chuyển không giống như kết thúc. bạn cần xóa các bảng được tạo mới trong cơ sở dữ liệu theo cách thủ công.

chúng ta có thể làm điều đó bằng cách sử dụng tinker như dưới đây:

L:\todos> php artisan tinker

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

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

=> null

Bản thân tôi đã có một vấn đề với bảng người dùng.

sau đó bạn tốt để đi

php artisan migrate:rollback

php artisan migrate


4

Giải pháp không ai nói là trong Mysql v5.5 trở lên, InnoDB là công cụ lưu trữ mặc định không có vấn đề này, nhưng trong nhiều trường hợp như của tôi, có một số tệp cấu hình mysql cũ đang sử dụng công cụ lưu trữ MYISAM cũ như bên dưới.

default-storage-engine=MYISAM

đang tạo ra tất cả những vấn đề này và giải pháp là thay đổi công cụ lưu trữ mặc định thành InnoDB trong tệp cấu hình ini của Mysql một lần và mãi mãi thay vì thực hiện các bản hack tạm thời.

default-storage-engine=InnoDB

Và nếu bạn đang sử dụng MySql v5.5 trở lên thì InnoDB là công cụ mặc định, do đó bạn không cần phải thiết lập rõ ràng như trên, chỉ cần xóa default-storage-engine=MYISAMnếu nó tồn tại khỏi initệp của bạn và bạn sẽ ổn.


Cảm ơn! Tôi đã phải sử dụng đề xuất này kết hợp với độ dài chuỗi, bộ ký tự và thay đổi đối chiếu để làm cho nó hoạt động với laravel 6 và mysql 5.6. Hy vọng điều này sẽ giúp những người khác trong tương lai.
Casper Wilkes

@CasperWilkes bạn không phải thực hiện bất kỳ độ dài chuỗi nào, công cụ bảng mã. Kiểm tra biến hệ thống Mysql của bạn như thế này show global variables like 'innodb_large_prefix';nó sẽ BẬT . Nếu nó TẮT thì bạn có thể kiểm tra câu trả lời này về cách bật nó lên. Và đây là thông tin thêm về innodb_large_prefix trên dev.mysql.com.
Ali A. Dhillon

3

Nếu bạn muốn thay đổi trong AppServiceProvider thì bạn cần xác định độ dài của trường email khi di chuyển. chỉ cần thay thế dòng mã đầu tiên thành dòng thứ hai.

created_users_table

$table->string('email')->unique();
$table->string('email', 50)->unique();

created_password_resets_table

$table->string('email')->index();
$table->string('email', 50)->index();

Sau khi thay đổi thành công, bạn có thể chạy di chuyển.
Lưu ý: trước tiên, bạn phải xóa (nếu bạn có) bảng người dùng , bảng password_resets khỏi cơ sở dữ liệu và xóa các mục nhập của người dùng và password_resets khỏi bảng di chuyển.


3

Schema::defaultStringLength(191);sẽ xác định độ dài của tất cả các chuỗi 191 theo mặc định có thể làm hỏng cơ sở dữ liệu của bạn. Bạn không được đi theo con đường này.

Chỉ cần định nghĩa độ dài của bất kỳ cột cụ thể nào trong lớp di chuyển cơ sở dữ liệu. Ví dụ: tôi đang xác định "tên", "tên người dùng" và "email" trong CreateUsersTablelớp như dưới đây:

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

1
Điều này là thích hợp nhất đối với tôi vì tôi không muốn điều chỉnh bất kỳ mã cốt lõi nào của Laravel.
Okiemute Omuta

2

Điều này là phổ biến vì Laravel 5.4 đã thay đổi charater cơ sở dữ liệu mặc định thành utf8mb4. Những gì bạn phải làm là: chỉnh sửa App \ Providers.php của bạn bằng cách đặt mã này trước khi khai báo lớp

use Illuminate\Support\Facades\Schema;

Ngoài ra, thêm chức năng này vào chức năng 'khởi động' Schema::defaultStringLength(191);


2

Nếu bạn chưa có bất kỳ dữ liệu nào được gán cho cơ sở dữ liệu của bạn, hãy làm như sau:

  1. Truy cập ứng dụng / Nhà cung cấp / AppServiceProvide.php và thêm

sử dụng Illuminate \ Support \ ServiceProvider;

và bên trong phương thức boot ();

Lược đồ :: defaultStringLpm (191);

  1. Bây giờ xóa các bản ghi trong cơ sở dữ liệu của bạn, bảng người dùng cho ex.

  2. chạy như sau

Cấu hình nghệ nhân php: bộ đệm

Nghệ nhân php di cư


Nó đã làm việc nhưng cần thêm use Illuminate\Support\Facades\Schema; use Illuminate\Support\ServiceProvider;là đã có. Hy vọng bạn sửa nó
Jimish Gamit

2

Như được nêu trong hướng dẫn Di chuyển để khắc phục điều này, tất cả những gì bạn phải làm là chỉnh sửa tệp AppServiceProvider.php và bên trong phương thức khởi động đặt độ dài chuỗi mặc định:

//edit your AppServiceProvider.php file contains in providers folder
use Illuminate\Support\Facades\Schema;

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

Hy vọng điều này sẽ giúp bạn..cheers ..


2

Tôi vừa sửa đổi dòng sau userspassword_resetstập tin di chuyển.

Cũ : $table->string('email')->unique();

Mới : $table->string('email', 128)->unique();



1

Tôi nghĩ rằng buộc StringLenght lên 191 là một ý tưởng thực sự tồi tệ. Vì vậy, tôi điều tra để hiểu những gì đang xảy ra.

Tôi nhận thấy rằng thông báo lỗi này:

SQLSTATE [42000]: Lỗi cú pháp hoặc vi phạm truy cập: 1071 Khóa được chỉ định quá dài; độ dài khóa tối đa là 767 byte

Bắt đầu hiển thị sau khi tôi cập nhật phiên bản MySQL của mình. Vì vậy, tôi đã kiểm tra các bảng bằng PHPMyAdmin và tôi nhận thấy rằng tất cả các bảng mới được tạo đều có đối chiếu utf8mb4_unicode_ci thay vì utf8_unicode_ci cho các bảng cũ.

Trong tệp cấu hình học thuyết của tôi, tôi nhận thấy rằng bộ ký tự được đặt thành utf8mb4, nhưng tất cả các bảng trước đó của tôi đã được tạo trong utf8, vì vậy tôi đoán đây là một số phép thuật cập nhật mà nó bắt đầu hoạt động trên utf8mb4.

Bây giờ cách khắc phục dễ dàng là thay đổi bộ ký tự dòng trong tệp cấu hình ORM của bạn. Sau đó, bỏ các bảng bằng utf8mb4_unicode_ci nếu bạn đang ở chế độ dev hoặc sửa bảng mã nếu bạn không thể thả chúng.

Dành cho Symfony 4

thay đổi bộ ký tự: utf8mb4 thành bộ ký tự: utf8 trong cấu hình / gói / doctrine.yaml

Bây giờ việc di chuyển học thuyết của tôi đang hoạt động tốt trở lại.


1

Giải pháp được đề xuất là kích hoạt innodb_large_prefixtùy chọn của MySQL để bạn không gặp phải các vấn đề tiếp theo. Và đây là cách để làm điều đó:

Mở my.initệp cấu hình MySQL và thêm các dòng dưới đây dưới [mysqld]dòng như thế này.

[mysqld]
innodb_file_format = Barracuda
innodb_large_prefix = 1
innodb_file_per_table = ON

Sau đó, lưu các thay đổi của bạn và khởi động lại dịch vụ MySQL của bạn.

Phục hồi nếu bạn cần và sau đó chạy lại di chuyển của bạn.


Chỉ trong trường hợp vấn đề của bạn vẫn còn, hãy truy cập tệp cấu hình cơ sở dữ liệu của bạn và đặt

'engine' => null, đến 'engine' => 'innodb row_format=dynamic'

Hy vọng nó giúp!


1

đầu tiên xóa tất cả các bảng của cơ sở dữ liệu trong localhost

Thay đổi thuộc tính cơ sở dữ liệu mặc định (utf8mb4) của Laravel trong tệp config / database.php thành:

'bộ ký tự' => 'utf8', 'đối chiếu' => 'utf8_unicode_ci',

sau đó Thay đổi thuộc tính cơ sở dữ liệu cục bộ của tôi utf8_unicode_ci. Nghệ nhân php di chuyển nó là ok.


0

Đối với bất kỳ ai khác có thể gặp phải vấn đề này, vấn đề của tôi là tôi đã tạo một cột kiểu stringvà cố gắng làm cho nó ->unsigned()khi tôi muốn nó là một số nguyên.


0

Công việc được tiếp cận ở đây đã vượt qua một thông số thứ hai với tên khóa (một tên ngắn):

$table->string('my_field_name')->unique(null,'key_name');

0

Tôi đã nhận được lỗi này mặc dù tôi đã có (thực sự tôi đã có) Schema :: defaultStringL wavel (191); trong tệp AppServiceProvider.php của tôi.

Lý do là bởi vì tôi đã cố gắng đặt giá trị chuỗi trong một trong những lần di chuyển của mình thành giá trị cao hơn 191:

Schema::create('order_items', function (Blueprint $table) {
    $table->primary(['order_id', 'product_id', 'attributes']);
    $table->unsignedBigInteger('order_id');
    $table->unsignedBigInteger('product_id');
    $table->string('attributes', 1000); // This line right here
    $table->timestamps();
});

Loại bỏ 1000 hoặc đặt nó thành 191 đã giải quyết vấn đề của tôi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.