- Wprowadzenie
- Wykonywanie zapytań SQL
- Transakcje bazodanowe
- Łączenie z CLI bazy danych
- Inspekcja baz danych
- Monitorowanie baz danych
Prawie każda nowoczesna aplikacja webowa współpracuje z bazą danych. Laravel sprawia, że interakcja z bazami danych jest niezwykle prosta w przypadku różnych obsługiwanych baz danych, używając surowego SQL, płynnego kreatora zapytań oraz Eloquent ORM. Obecnie Laravel zapewnia natywne wsparcie dla pięciu baz danych:
- MariaDB 10.3+ (Version Policy)
- MySQL 5.7+ (Version Policy)
- PostgreSQL 10.0+ (Version Policy)
- SQLite 3.26.0+
- SQL Server 2017+ (Version Policy)
Dodatkowo MongoDB jest obsługiwany przez pakiet mongodb/laravel-mongodb, który jest oficjalnie utrzymywany przez MongoDB. Sprawdź dokumentację Laravel MongoDB po więcej informacji.
Konfiguracja usług bazy danych Laravel znajduje się w pliku konfiguracyjnym config/database.php Twojej aplikacji. W tym pliku możesz zdefiniować wszystkie swoje połączenia z bazą danych, a także określić, które połączenie powinno być używane domyślnie. Większość opcji konfiguracji w tym pliku jest sterowana przez wartości zmiennych środowiskowych Twojej aplikacji. W tym pliku znajdują się przykłady dla większości systemów baz danych obsługiwanych przez Laravel.
Domyślnie przykładowa konfiguracja środowiskowa Laravel jest gotowa do użycia z Laravel Sail, który jest konfiguracją Docker do tworzenia aplikacji Laravel na lokalnej maszynie. Możesz jednak dowolnie modyfikować konfigurację swojej bazy danych zgodnie z potrzebami Twojej lokalnej bazy danych.
Bazy danych SQLite są zawarte w pojedynczym pliku w Twoim systemie plików. Możesz utworzyć nową bazę danych SQLite używając polecenia touch w terminalu: touch database/database.sqlite. Po utworzeniu bazy danych możesz łatwo skonfigurować swoje zmienne środowiskowe, aby wskazywały na tę bazę danych, umieszczając bezwzględną ścieżkę do bazy danych w zmiennej środowiskowej DB_DATABASE:
DB_CONNECTION=sqlite
DB_DATABASE=/absolute/path/to/database.sqliteDomyślnie ograniczenia klucza obcego są włączone dla połączeń SQLite. Jeśli chcesz je wyłączyć, powinieneś ustawić zmienną środowiskową DB_FOREIGN_KEYS na false:
DB_FOREIGN_KEYS=falseNote
Jeśli używasz instalatora Laravel do utworzenia swojej aplikacji Laravel i wybierzesz SQLite jako swoją bazę danych, Laravel automatycznie utworzy plik database/database.sqlite i uruchomi domyślne migracje bazy danych za Ciebie.
Aby użyć bazy danych Microsoft SQL Server, powinieneś upewnić się, że masz zainstalowane rozszerzenia PHP sqlsrv i pdo_sqlsrv, a także wszelkie zależności, których mogą wymagać, takie jak sterownik Microsoft SQL ODBC.
Zazwyczaj połączenia z bazą danych są konfigurowane przy użyciu wielu wartości konfiguracji, takich jak host, database, username, password itp. Każda z tych wartości konfiguracji ma swoją odpowiednią zmienną środowiskową. Oznacza to, że podczas konfigurowania informacji o połączeniu z bazą danych na serwerze produkcyjnym musisz zarządzać kilkoma zmiennymi środowiskowymi.
Niektórzy zarządzani dostawcy baz danych, tacy jak AWS i Heroku, udostępniają pojedynczy "URL" bazy danych, który zawiera wszystkie informacje o połączeniu dla bazy danych w jednym ciągu. Przykładowy adres URL bazy danych może wyglądać następująco:
mysql://root:password@127.0.0.1/forge?charset=UTF-8Te adresy URL zazwyczaj podlegają standardowej konwencji schematu:
driver://username:password@host:port/database?optionsDla wygody Laravel obsługuje te adresy URL jako alternatywę dla konfigurowania bazy danych za pomocą wielu opcji konfiguracji. Jeśli opcja konfiguracyjna url (lub odpowiadająca jej zmienna środowiskowa DB_URL) jest obecna, zostanie użyta do wyodrębnienia informacji o połączeniu z bazą danych i poświadczeń.
Czasami możesz chcieć użyć jednego połączenia z bazą danych dla instrukcji SELECT, a innego dla instrukcji INSERT, UPDATE i DELETE. Laravel sprawia, że jest to dziecinnie proste, a odpowiednie połączenia będą zawsze używane, niezależnie od tego, czy używasz surowych zapytań, kreatora zapytań czy Eloquent ORM.
Aby zobaczyć, jak należy skonfigurować połączenia odczytu/zapisu, spójrzmy na ten przykład:
'mysql' => [
'driver' => 'mysql',
'read' => [
'host' => [
'192.168.1.1',
'196.168.1.2',
],
],
'write' => [
'host' => [
'192.168.1.3',
],
],
'sticky' => true,
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'laravel'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => env('DB_CHARSET', 'utf8mb4'),
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
(PHP_VERSION_ID >= 80500 ? \Pdo\Mysql::ATTR_SSL_CA : \PDO::MYSQL_ATTR_SSL_CA) => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],Zauważ, że trzy klucze zostały dodane do tablicy konfiguracji: read, write i sticky. Klucze read i write mają wartości tablicowe zawierające pojedynczy klucz: host. Pozostałe opcje bazy danych dla połączeń read i write zostaną scalone z głównej tablicy konfiguracji mysql.
Musisz umieścić elementy w tablicach read i write tylko wtedy, gdy chcesz nadpisać wartości z głównej tablicy mysql. Więc w tym przypadku 192.168.1.1 będzie używany jako host dla połączenia "read", podczas gdy 192.168.1.3 będzie używany dla połączenia "write". Poświadczenia bazy danych, prefiks, zestaw znaków i wszystkie inne opcje w głównej tablicy mysql będą współdzielone przez oba połączenia. Gdy w tablicy konfiguracji host istnieje wiele wartości, host bazy danych będzie losowo wybierany dla każdego żądania.
Opcja sticky jest opcjonalną wartością, która może być użyta do umożliwienia natychmiastowego odczytu rekordów, które zostały zapisane w bazie danych podczas bieżącego cyklu żądania. Jeśli opcja sticky jest włączona i podczas bieżącego cyklu żądania wykonana została operacja "write" w bazie danych, wszelkie dalsze operacje "read" będą używać połączenia "write". Zapewnia to, że wszelkie dane zapisane podczas cyklu żądania mogą być natychmiast odczytane z bazy danych podczas tego samego żądania. To od Ciebie zależy, czy jest to pożądane zachowanie dla Twojej aplikacji.
Po skonfigurowaniu połączenia z bazą danych możesz uruchamiać zapytania przy użyciu fasady DB. Fasada DB dostarcza metody dla każdego typu zapytania: select, update, insert, delete i statement.
Aby uruchomić podstawowe zapytanie SELECT, możesz użyć metody select na fasadzie DB:
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\DB;
use Illuminate\View\View;
class UserController extends Controller
{
/**
* Pokaż listę wszystkich użytkowników aplikacji.
*/
public function index(): View
{
$users = DB::select('select * from users where active = ?', [1]);
return view('user.index', ['users' => $users]);
}
}Pierwszy argument przekazany do metody select to zapytanie SQL, podczas gdy drugi argument to wszelkie powiązania parametrów, które muszą być powiązane z zapytaniem. Zazwyczaj są to wartości ograniczeń klauzuli where. Wiązanie parametrów zapewnia ochronę przed atakami typu SQL injection.
Metoda select zawsze zwróci array wyników. Każdy wynik w tablicy będzie obiektem PHP stdClass reprezentującym rekord z bazy danych:
use Illuminate\Support\Facades\DB;
$users = DB::select('select * from users');
foreach ($users as $user) {
echo $user->name;
}Czasami Twoje zapytanie do bazy danych może zwrócić pojedynczą wartość skalarną. Zamiast być zmuszonym do pobierania skalarnego wyniku zapytania z obiektu rekordu, Laravel pozwala Ci pobrać tę wartość bezpośrednio, używając metody scalar:
$burgers = DB::scalar(
"select count(case when food = 'burger' then 1 end) as burgers from menu"
);Jeśli Twoja aplikacja wywołuje procedury składowane, które zwracają wiele zestawów wyników, możesz użyć metody selectResultSets, aby pobrać wszystkie zestawy wyników zwrócone przez procedurę składowaną:
[$options, $notifications] = DB::selectResultSets(
"CALL get_user_options_and_notifications(?)", $request->user()->id
);Zamiast używać ? do reprezentowania wiązań parametrów, możesz wykonać zapytanie używając nazwanych powiązań:
$results = DB::select('select * from users where id = :id', ['id' => 1]);Aby wykonać instrukcję insert, możesz użyć metody insert na fasadzie DB. Podobnie jak select, ta metoda przyjmuje zapytanie SQL jako pierwszy argument i powiązania jako drugi argument:
use Illuminate\Support\Facades\DB;
DB::insert('insert into users (id, name) values (?, ?)', [1, 'Marc']);Metoda update powinna być używana do aktualizacji istniejących rekordów w bazie danych. Liczba wierszy dotkniętych przez instrukcję jest zwracana przez metodę:
use Illuminate\Support\Facades\DB;
$affected = DB::update(
'update users set votes = 100 where name = ?',
['Anita']
);Metoda delete powinna być używana do usuwania rekordów z bazy danych. Podobnie jak update, liczba dotkniętych wierszy zostanie zwrócona przez metodę:
use Illuminate\Support\Facades\DB;
$deleted = DB::delete('delete from users');Niektóre instrukcje bazy danych nie zwracają żadnej wartości. Dla tego typu operacji możesz użyć metody statement na fasadzie DB:
DB::statement('drop table users');Czasami możesz chcieć wykonać instrukcję SQL bez wiązania żadnych wartości. Możesz użyć metody unprepared fasady DB, aby to osiągnąć:
DB::unprepared('update users set votes = 100 where name = "Dries"');Warning
Ponieważ nieprzygotowane instrukcje nie wiążą parametrów, mogą być podatne na ataki SQL injection. Nigdy nie powinieneś zezwalać na wartości kontrolowane przez użytkownika w nieprzygotowanej instrukcji.
Podczas używania metod statement i unprepared fasady DB w transakcjach musisz uważać, aby unikać instrukcji, które powodują niejawne zatwierdzenia. Te instrukcje spowodują, że silnik bazy danych pośrednio zatwierdzi całą transakcję, pozostawiając Laravel nieświadomy poziomu transakcji bazy danych. Przykładem takiej instrukcji jest utworzenie tabeli bazy danych:
DB::unprepared('create table a (col varchar(1) null)');Sprawdź w podręczniku MySQL listę wszystkich instrukcji, które wyzwalają niejawne zatwierdzenia.
Jeśli Twoja aplikacja definiuje wiele połączeń w pliku konfiguracyjnym config/database.php, możesz uzyskać dostęp do każdego połączenia za pomocą metody connection dostarczonej przez fasadę DB. Nazwa połączenia przekazana do metody connection powinna odpowiadać jednemu z połączeń wymienionych w pliku konfiguracyjnym config/database.php lub skonfigurowanemu w czasie wykonywania za pomocą helpera config:
use Illuminate\Support\Facades\DB;
$users = DB::connection('sqlite')->select(/* ... */);Możesz uzyskać dostęp do surowej, podstawowej instancji PDO połączenia, używając metody getPdo na instancji połączenia:
$pdo = DB::connection()->getPdo();Jeśli chcesz określić zamknięcie, które jest wywoływane dla każdego zapytania SQL wykonanego przez Twoją aplikację, możesz użyć metody listen fasady DB. Ta metoda może być przydatna do rejestrowania zapytań lub debugowania. Możesz zarejestrować swoje zamknięcie nasłuchujące zapytania w metodzie boot dostawcy usług:
<?php
namespace App\Providers;
use Illuminate\Database\Events\QueryExecuted;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Zarejestruj wszelkie usługi aplikacji.
*/
public function register(): void
{
// ...
}
/**
* Uruchom wszelkie usługi aplikacji.
*/
public function boot(): void
{
DB::listen(function (QueryExecuted $query) {
// $query->sql;
// $query->bindings;
// $query->time;
// $query->toRawSql();
});
}
}Częstym wąskim gardłem wydajności nowoczesnych aplikacji webowych jest czas, który spędzają na odpytywaniu baz danych. Na szczęście Laravel może wywołać zamknięcie lub callback Twojego wyboru, gdy spędza zbyt dużo czasu na odpytywaniu bazy danych podczas pojedynczego żądania. Aby rozpocząć, podaj próg czasu zapytania (w milisekundach) i zamknięcie do metody whenQueryingForLongerThan. Możesz wywołać tę metodę w metodzie boot dostawcy usług:
<?php
namespace App\Providers;
use Illuminate\Database\Connection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\ServiceProvider;
use Illuminate\Database\Events\QueryExecuted;
class AppServiceProvider extends ServiceProvider
{
/**
* Zarejestruj wszelkie usługi aplikacji.
*/
public function register(): void
{
// ...
}
/**
* Uruchom wszelkie usługi aplikacji.
*/
public function boot(): void
{
DB::whenQueryingForLongerThan(500, function (Connection $connection, QueryExecuted $event) {
// Powiadom zespół deweloperski...
});
}
}Możesz użyć metody transaction dostarczonej przez fasadę DB, aby uruchomić zestaw operacji w ramach transakcji bazodanowej. Jeśli w zamknięciu transakcji zostanie zgłoszony wyjątek, transakcja zostanie automatycznie wycofana, a wyjątek zostanie ponownie zgłoszony. Jeśli zamknięcie zostanie wykonane pomyślnie, transakcja zostanie automatycznie zatwierdzona. Nie musisz martwić się o ręczne wycofywanie lub zatwierdzanie podczas korzystania z metody transaction:
use Illuminate\Support\Facades\DB;
DB::transaction(function () {
DB::update('update users set votes = 1');
DB::delete('delete from posts');
});Metoda transaction przyjmuje opcjonalny drugi argument, który definiuje, ile razy transakcja powinna być ponawiana, gdy wystąpi zakleszczenie. Po wyczerpaniu tych prób zostanie zgłoszony wyjątek:
use Illuminate\Support\Facades\DB;
DB::transaction(function () {
DB::update('update users set votes = 1');
DB::delete('delete from posts');
}, attempts: 5);Jeśli chcesz rozpocząć transakcję ręcznie i mieć pełną kontrolę nad wycofywaniem i zatwierdzaniem, możesz użyć metody beginTransaction dostarczonej przez fasadę DB:
use Illuminate\Support\Facades\DB;
DB::beginTransaction();Możesz wycofać transakcję za pomocą metody rollBack:
DB::rollBack();Na koniec możesz zatwierdzić transakcję za pomocą metody commit:
DB::commit();Note
Metody transakcji fasady DB kontrolują transakcje zarówno dla kreatora zapytań, jak i Eloquent ORM.
Jeśli chcesz połączyć się z CLI swojej bazy danych, możesz użyć polecenia Artisan db:
php artisan dbW razie potrzeby możesz określić nazwę połączenia z bazą danych, aby połączyć się z połączeniem z bazą danych, które nie jest połączeniem domyślnym:
php artisan db mysqlZa pomocą poleceń Artisan db:show i db:table możesz uzyskać cenny wgląd w swoją bazę danych i powiązane z nią tabele. Aby zobaczyć przegląd swojej bazy danych, w tym jej rozmiar, typ, liczbę otwartych połączeń i podsumowanie jej tabel, możesz użyć polecenia db:show:
php artisan db:showMożesz określić, które połączenie z bazą danych powinno być sprawdzone, podając nazwę połączenia z bazą danych do polecenia za pomocą opcji --database:
php artisan db:show --database=pgsqlJeśli chcesz uwzględnić liczbę wierszy tabeli i szczegóły widoków bazy danych w danych wyjściowych polecenia, możesz podać odpowiednio opcje --counts i --views. W dużych bazach danych pobieranie liczby wierszy i szczegółów widoków może być wolne:
php artisan db:show --counts --viewsPonadto możesz użyć następujących metod Schema do inspekcji swojej bazy danych:
use Illuminate\Support\Facades\Schema;
$tables = Schema::getTables();
$views = Schema::getViews();
$columns = Schema::getColumns('users');
$indexes = Schema::getIndexes('users');
$foreignKeys = Schema::getForeignKeys('users');Jeśli chcesz sprawdzić połączenie z bazą danych, które nie jest domyślnym połączeniem Twojej aplikacji, możesz użyć metody connection:
$columns = Schema::connection('sqlite')->getColumns('users');Jeśli chcesz uzyskać przegląd pojedynczej tabeli w swojej bazie danych, możesz wykonać polecenie Artisan db:table. To polecenie zapewnia ogólny przegląd tabeli bazy danych, w tym jej kolumny, typy, atrybuty, klucze i indeksy:
php artisan db:table usersZa pomocą polecenia Artisan db:monitor możesz nakazać Laravel wysłanie zdarzenia Illuminate\Database\Events\DatabaseBusy, jeśli Twoja baza danych zarządza więcej niż określoną liczbą otwartych połączeń.
Aby rozpocząć, powinieneś zaplanować uruchamianie polecenia db:monitor co minutę. Polecenie przyjmuje nazwy konfiguracji połączeń z bazą danych, które chcesz monitorować, a także maksymalną liczbę otwartych połączeń, która powinna być tolerowana przed wysłaniem zdarzenia:
php artisan db:monitor --databases=mysql,pgsql --max=100Samo zaplanowanie tego polecenia nie wystarcza, aby wywołać powiadomienie informujące o liczbie otwartych połączeń. Gdy polecenie napotka bazę danych, która ma liczbę otwartych połączeń przekraczającą Twój próg, zostanie wysłane zdarzenie DatabaseBusy. Powinieneś nasłuchiwać tego zdarzenia w AppServiceProvider swojej aplikacji, aby wysłać powiadomienie do Ciebie lub Twojego zespołu deweloperskiego:
use App\Notifications\DatabaseApproachingMaxConnections;
use Illuminate\Database\Events\DatabaseBusy;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Notification;
/**
* Uruchom wszelkie usługi aplikacji.
*/
public function boot(): void
{
Event::listen(function (DatabaseBusy $event) {
Notification::route('mail', 'dev@example.com')
->notify(new DatabaseApproachingMaxConnections(
$event->connectionName,
$event->connections
));
});
}