Probleme mit der Datengenauigkeit und -konsistenz können von kleinen Unannehmlichkeiten bis hin zu großen Problemen für das Unternehmen führen. Es ist wichtig, einen Code zu entwickeln, der die Daten in deiner Datenbank sicher speichert, ändert und löscht.
Das sind die Laravel-Datenbanktransaktionen.
Datenbanktransaktionen sind ein effektiver Ansatz, um die Datenintegrität zu gewährleisten.Laravel vereinfacht diese Transaktionen für eine Vielzahl von Datenbanken.
Aber was genau sind sie? Wie kannst du sie in Laravel bearbeiten?
Am Ende dieses ausführlichen Leitfadens wirst du alles über Datenbanktransaktionen in Laravel gelernt haben und wie du sie in deinem Projekt effektiv einsetzen kannst.
Was sind Laravel-Datenbanktransaktionen?
Bevor wir uns mit der technischen Seite beschäftigen, wollen wir erst einmal verstehen, was Laravel-Datenbanktransaktionen sind und wie du von ihnen profitieren kannst.
Eine Datenbanktransaktion ist eine Reihe von Vorgängen, die du sicher innerhalb der Datenbankstruktur deiner Anwendung durchführen kannst, z. B. SQL-Abfragen zur Änderung von Daten (z. B. Aktualisierungen, Löschungen und Einfügungen).
Du kannst jederzeit entscheiden, ob du alle Abfragen der Transaktion zurücknehmen willst. Außerdem werden alle Abfragen, die du machst, von der Datenbank als eine einzelne Aktion behandelt.
Schauen wir uns ein Beispiel dafür an.
Nehmen wir an, wir haben eine App, mit der Nutzer Konten erstellen können. Natürlich kann jedes Konto mit einem oder mehreren Nutzern verknüpft sein. Wenn diese App gleichzeitig ein Konto und den ersten Nutzer erstellt, musst du dich damit befassen, was passiert, wenn ein Konto richtig erstellt wird, der Nutzer aber nicht.
Sieh dir diesen Beispielcode an:
// Create Account
$newAcct = Account::create([
'accountname' => Input::get('accountname'),
]);
// Create User
$newUser = User::create([
'username' => Input::get('username'),
'account_id' => $newAcct->id,
]);
Hier gibt es zwei Szenarien, die unangenehme Probleme verursachen können:
- Konto wird nicht erstellt
- Fehler bei der Erstellung eines Benutzers
Betrachten wir die letzte Situation.
Ein Konto ohne verfügbare Benutzer führt zu Dateninkonsistenzen in der Datenbank. Um dies zu beheben, kannst du entweder eine Menge Code einsparen oder es einfach in eine Transaktion verpacken, um die Sache schnell zu erledigen.
Datenbanktransaktionen gibt es zwar in den meisten SQL-Datenbanken, sie unterscheiden sich aber vor allem in ihrer Umsetzung und Effizienz. Beliebte Systeme wie MySQL, SQLite, PostgreSQL und Oracle unterstützen Transaktionen, sodass du keine Probleme haben solltest, deine bevorzugte SQL-Datenbank einzusetzen.
Migrationen
Migration ist eine wichtige Funktion in Laravel, die es dir ermöglicht, eine Tabelle in deiner Datenbank zu erstellen, Änderungen vorzunehmen und das Datenbankschema der Anwendung zu teilen. Du kannst Laravel-Migrationen nutzen, um Tabellen zu bearbeiten, indem du neue Spalten hinzufügst oder bestehende entfernst.
Angenommen, du besprichst Ideen mit einem Team und musst Anpassungen an der Tabelle vornehmen. Die SQL-Datei muss geteilt und von jemandem im Team importiert werden. Es ist möglich, dass sie vergessen, die SQL-Datei zu importieren, was zu Problemen im Betrieb der Anwendung führt.
An dieser Stelle kommt die Laravel-Migration zur Rettung. Du kannst eine neue Spalte zu deiner Datenbank hinzufügen oder Einträge löschen, ohne dass sich das auf die bereits vorhandenen auswirkt.
Seeders
Seeding ist ein Tool, das Laravel Entwicklern zur Verfügung stellt, um das Testen verschiedener Datentypen zu erleichtern, Fehler zu beheben und die Leistung zu optimieren. Mit dem Datenbank-Seeder kannst du deiner Datenbanktabelle mit einem einzigen Befehl automatisch mehrere Zeilen mit Dummy-Daten hinzufügen.
So kannst du mit einer neuen Datenbank und Beispielwerten beginnen, anstatt sie jedes Mal manuell eingeben zu müssen, wenn die Datenbank wiederhergestellt wird.
Optionen für Laravel-Datenbanktransaktionen
Laravel bietet verschiedene Werkzeuge, um deine Daten wie Adminer zu verwalten. Für Datenbanktransaktionen gibt es auf der Datenbankseite drei Methoden, um eine Transaktion manuell zu starten und die volle Kontrolle über die Transaktionsverwaltung zu haben.
Viele Nutzer finden diese Optionen flexibler, um genau festzulegen, wann eine Transaktion bestätigt oder zurückgenommen werden soll:
- Erstelle eine Transaktion: Verwende den Befehl
DB::beginTransaction();
, um eine Transaktion zu starten. - Eine Transaktion rückgängig machen: Verwende den Befehl
DB::rollBack();
, wenn du Änderungen vornehmen oder Aktionen rückgängig machen willst. - Bestätige eine Transaktion: Wenn alles wie geplant gelaufen ist, verwende den Befehl
DB::commit();
.
Denke immer daran, jede offene Transaktion mit einer Commit- oder Rollback-Aktion abzuschließen, insbesondere bei Schleifen. Andernfalls wird diese manuelle Methode nicht mehr synchronisiert und deine Datensätze werden nicht aktualisiert.
Wie du mit deiner Laravel-Datenbank arbeitest
Migrationen und Seeder sind, wie bereits erwähnt, ausgeklügelte Lösungen für Laravel-Entwickler, um die Datenbank einer Anwendung schnell bereitzustellen, zu löschen und wiederherzustellen, indem sie Unstimmigkeiten reduzieren. Das ist besonders praktisch, wenn mehrere Entwickler an derselben Anwendung arbeiten.
In diesem Abschnitt erfährst du, wie du Migrationen und Seeder mithilfe von artisan-Befehlen ganz einfach mit deiner Laravel-Datenbank nutzen kannst.
Voraussetzungen
Das brauchst du, um loszulegen:
- Ein Nicht-Root-Benutzer mit sudo-Rechten auf einem lokalen Ubuntu 18.04-Computer oder Entwicklungsserver. Es ist ratsam, eine aktive Firewall einzurichten, wenn du einen Remote-Server verwendest.
- LEMP ist auf deinem Rechner installiert. Du kannst auch Docker und Docker Compose installieren, um deine Anwendung auszuführen, wenn du dich bei der Arbeit damit wohler fühlst.
Unser DevKinsta-Tool basiert auf Docker und wird von 60,000++ Entwicklern und Designern verwendet, um auf einfache Weise einzelne oder mehrere WordPress-Seiten zu erstellen und zu entwickeln.
Es gibt noch weitere Webentwicklungs-Tools, die du je nach deinen Fähigkeiten und Programmieranforderungen nutzen kannst.
Laravel Migrationen
Es gibt zwei Methoden in einer Migrationsklasse: up und down. Die Up-Methode wird verwendet, um neue Tabellen, Indizes oder Spalten in deiner Datenbank zu erstellen. Die Down-Methode soll die Auswirkungen der Up-Methode rückgängig machen.
Mit dem Laravel Schema-Builder kannst du in jeder dieser Methoden Tabellen frei erstellen und bearbeiten. Diese Migration erzeugt zum Beispiel eine Flugtabelle:
use IlluminateDatabaseMigrationsMigration;
use IlluminateDatabaseSchemaBlueprint;
use IlluminateSupportFacadesSchema;
class CreateFlightsTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up() {
Schema::create('flights', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->string('airline');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down() {
Schema::drop('flights');
}
Denke daran, dass die make:migration
Befehle den Namen der Tabelle klären müssen. Vergewissere dich also, dass die table_name
mit dem übereinstimmt, was du willst.
Mit den Optionen --table
und --create
kannst du den Tabellennamen angeben und festlegen, ob die Migration eine neue Tabelle erstellen soll (siehe unten):
php artisan make:migration create_users_table --create=users
php artisan make:migration add_votes_to_users_table --table=users
Dein Verzeichnis database/migrations enthält nun die neue Migration. Jeder Migrationsdateiname enthält einen Zeitstempel, den Laravel verwendet, um die Reihenfolge der Migration zu bestimmen.
Du hast auch die Möglichkeit, ein --path
zu definieren, das mit dem Stammverzeichnis deiner Installation verbunden sein sollte. Verwende den folgenden Befehl:
php artisan migrate:make foo --path=app/migrations
Migrationen ausführen
Es gibt einige hilfreiche Befehle, die du bei der Durchführung von Migrationen nutzen kannst. Sehen wir uns ein paar davon an:
php artisan migrate
: Mit diesem Befehl wird dein gesamtes Schema in der Datenbank veröffentlicht. Er erzeugt außerdem eine Tabelle in der Datenbank.php artisan migrate --path=app/foo/migrations
: Mit diesem Befehl werden alle Migrationen unter einem Verzeichnis ausgeführt. Wenn du die Fehlermeldung „Nichts zu migrieren“ erhältst, führe den Befehlphp artisan migrate --path=database/migrations/foo
ohne das App-Verzeichnis aus.php artisan migrate --package=vendor/package
: Verwende diesen Befehl, wenn du Migrationen für ein Paket ausführen willst.
Manchmal bekommst du beim Ausführen von Migrationen die Fehlermeldung „Klasse nicht gefunden“. Wenn das der Fall ist, führe den Befehl composer dump-autoload
aus.
Manche Migrationen können gefährlich sein und zum Verlust deiner Daten führen. Deshalb wird Laravel dich auffordern, die Ausführung von Befehlen zu bestätigen, um deine Daten zu schützen.
Wenn du nicht gefragt werden möchtest, kannst du die Befehle mit --force flag
wie folgt erzwingen:
php artisan migrate --force
Migrationen rückgängig machen
Verwende den Rollback-Befehl, wenn du den letzten Migrationsstapel wie folgt rückgängig machen willst:
php artisan migrate:rollback
Hier sind ein paar weitere Rollback-Befehle, die du verwenden kannst:
php artisan migrate:reset
: Dieser Befehl macht alle Migrationen rückgängig, nicht nur die letzte Operation.php artisan migrate:fresh
: Verwende diesen Befehl, wenn du eine neue Installation deiner Datenbank durchführen willst. Er löscht alle vorhandenen Tabellen und führt den Befehlmigration
aus.php artisan migrate:refresh
: Dies ist ein Zwei-in-Eins-Befehl, der die beiden:rollback and migrate
Befehle ausführt.php artisan migrate:fresh --seed
: Er führt den Befehlmigrate:fresh
aus, bevor die Datenbank gefüttert wird. Wenn du die App auf einem neuen Rechner installierst, kannst du diesen Befehl verwenden, um die Datenbank zu seeden (d.h. Daten in die Datenbank hochzuladen).
Laravel Seeding
Ein Seeder ist eine Klasse, die Datenproben (Seeds) erstellt und in einer Datenbank platziert. Laravel bietet eine einfache Methode, um deine Datenbank mit Testdaten zu füllen, indem du Seed-Klassen im Verzeichnis database/seeds verwendest.
Du kannst den Namen deiner Seed-Klassen frei wählen. Wir raten dir aber, dich an ein klares Namensmuster deiner Wahl zu halten, wie UsersTableSeeder. Danach wird standardmäßig eine DatabaseSeeder
Klasse für dich erstellt.
Hier ist ein Beispiel für eine Datenbank-Seed-Klasse in Laravel:
class DatabaseSeeder extends Seeder {
public function run() {
$this->call('UserTableSeeder');
$this->command->info('User table seeded!');
}
}
class UserTableSeeder extends Seeder {
public function run() {
DB::table('users')->delete();
User::create(array('email' => '[email protected]'));
}
}
Einen Seeder erstellen
Die Erstellung von Seedern ist kinderleicht. Du könntest es mit geschlossenen Augen machen (aber bitte nicht).
Führe den Befehl make:seeder
artisan aus, um einen Seeder zu erstellen. Das Verzeichnis database/seeds enthält nun alle Seeder, die vom Framework erstellt wurden:
php artisan make:seeder UsersTableSeeder
Die Standardmethode einer Seederklasse ist run. Der Prozess findet statt, wenn du den db:seed
artisan-Befehl anwendest. Mit der run-Funktion kannst du Daten auf jede beliebige Weise in deine Datenbank eingeben. Außerdem ist es durchaus möglich, dass du Eloquent Model Factories oder Query Builder verwendest, um Daten manuell einzufügen.
Trotzdem solltest du bedenken, dass beim Datenbank-Seeding der Schutz vor Massenzuweisungen automatisch deaktiviert wird.
Im Folgenden werden wir Änderungen an der Basisklasse DatabaseSeeder
vornehmen und eine Datenbankeinfügeanweisung in die Run-Methode einfügen:
<?php
use IlluminateDatabaseSeeder;
use IlluminateSupportFacadesDB;
use IlluminateSupportFacadesHash;
use IlluminateSupportStr;
class DatabaseSeeder extends Seeder {
/**
* Run the database seeds.
*
* @return void
*/
public function run() {
DB::table('users')->insert([
'name' => Str::random(10),
'email' => Str::random(10).'@gmail.com',
'password' => Hash::make('password'),
]);
}
}
Wenn du im Code der Run-Methode einen Hinweis auf Abhängigkeiten geben möchtest, löst der Laravel Service Container diese automatisch auf.
Außerdem kannst du die Funktion call
verwenden, um verschiedene Seed-Klassen von dieser Klasse aus auszuführen und so die Seeding-Reihenfolge anzupassen. Du kannst dein Datenbank-Seeding auf verschiedene Dateien aufteilen und so sicherstellen, dass keine einzelne Seeder-Klasse übermäßig expandiert.
Gib den Namen der Seederklasse ein, die du verwenden möchtest, wie unten gezeigt:
/**
* Run the database seeds.
*
* @return void
*/
public function run() {
$this->call([
UsersTableSeeder::class,
PostsTableSeeder::class,
CommentsTableSeeder::class,
]);
}
Ausführen von Seedern
Nachdem du deinen Seeder erstellt hast, musst du eventuell den Befehl dump-autoload
verwenden, um den Autoloader von Composer neu zu erstellen:
composer dump-autoload
Als Nächstes musst du den Befehl db:seed
artisan ausführen, um deine Datenbank zu seeden:
php artisan db:seed
Dieser Befehl führt die Klasse DatabaseSeeder
stellvertretend aus, die für die Ausführung anderer Seed-Klassen verwendet werden kann. Du kannst jedoch den Parameter --class
verwenden, um eine bestimmte Seederklasse separat auszuführen, wie folgt:
php artisan db:seed --class=UserTableSeeder
Was ist, wenn du deine Datenbank von Grund auf neu erstellen möchtest, indem du alle Tabellen löschst und alle Migrationen noch einmal ausführst? In diesem Fall verwendest du den Befehl migrate:fresh
, um deine Datenbank zu seeden.
php artisan migrate:fresh --seed
Wie bei den Migrationen können einige Seeding-Prozesse zu Datenverlusten oder unerwünschten Änderungen führen. Aus diesem Grund wirst du vor der Ausführung der Seeder zur Zustimmung aufgefordert, um dich davor zu schützen, dass du Seeding-Befehle auf deiner primären Datenbank ausführst.
Wenn du dir sicher bist und nicht durch diesen Sicherheitsschritt unterbrochen werden möchtest, kannst du das --force
Flag unten verwenden:
php artisan db:seed --force
5 Weitere Möglichkeiten, rohe Datenbankabfragen in Laravel zu verwenden
Laravel bietet zwar praktische Tools wie Eloquent und Query Builder, aber du kannst auch einfache Abfragen mit SQL durchführen. Wir haben fünf verschiedene Möglichkeiten dafür zusammengestellt.
Aber bevor du anfängst, solltest du wissen, dass rohe Abfragen nicht automatisch gesichert sind, was sie zu einem riskanten Ansatz macht. Wenn du der Abfrage Parameter mitgibst, solltest du darauf achten, dass sie das richtige Format und die richtigen Werte haben, z. B. eine Zahl und keinen Text.
Avg/Sum/Count Berechnungen
Du kannst eine rohe Abfrage verwenden, wenn du GROUP BY ()
erstellen willst, und dann MySQL-Aggregatfunktionen wie Count()
, SUM()
, AVG()
, MIN()
oder MAX()
verwenden, wie im folgenden Beispiel gezeigt:
$users = DB::table('users')
->selectRaw('count(*) as user_count, status')
->where('status', '<>', 1)
->groupBy('status')
->get();
Es ist sogar möglich, sowohl count()
als auch avg()
in der gleichen SQL-Abfrage zu erstellen:
$salaries = DB::table('salaries')
->selectRaw('companies.name as company_name, avg(salary) as avg_salary, count(*) as people_count')
->join('companies', 'salaries.company_id', '=', 'companies.id')
->groupBy('companies.id')
->orderByDesc('avg_salary')
->get();
Jahre filtern
Wenn du innerhalb von GROUP BY
oder ORDER BY
SQL-Berechnungen durchführen musst, kannst du groupByRaw()
und orderByRaw()
Abfragen verwenden. Nach der Gruppierung kannst du auch die where
Anweisung nutzen, indem du eine having
SQL-Abfrage mit havingRaw ()
verwendest.
Der folgende Befehl zeigt zum Beispiel, wie du ein Datums-/Zeitfeld nach Jahr gruppieren kannst:
$results = User::selectRaw('YEAR(birth_date) as year, COUNT(id) as amount')
->groupByRaw('YEAR(birth_date)')
->havingRaw('YEAR(birth_date) > 2000')
->orderByRaw('YEAR(birth_date)')
->get();
Berechnen eines einzelnen Feldes (Unterabfrage)
Angenommen, du möchtest eine Spalte aus einer anderen berechnen und das Ergebnis in einer SQL-Abfrage zurückgeben. Wie kannst du das machen?
Schauen wir uns das mal an:
$products = Product::select('id', 'name')
->selectRaw('price - discount_price AS discount')
->get();
Hier ist ein weiteres Beispiel für eine SQL CASE
Anweisung:
$users = DB::table('users')
->select('name', 'surname')
->selectRaw("(CASE WHEN (gender = 1) THEN 'M' ELSE 'F' END) as gender_text")
->get();
Älteres SQL konvertieren
Es kommt häufig vor, dass du eine SQL-Anweisung hast, die in Eloquent oder Query Builder konvertiert werden muss, vor allem aus einem alten Projekt, an dem du gearbeitet hast.
Das musst du aber nicht tun. Stattdessen kannst du einfach die Anweisung DB::select()
wie folgt verwenden:
$results = DB::select('select * from users where id=?', [1]);
Abfrage ohne Ergebnisse ausführen
DB::statement
kann eine SQL-Abfrage ausführen und erhält keine Ergebnisse wie INSERT
oder UPDATE
ohne Variablen.
Dies wird häufig bei der Datenbankmigration verwendet, wenn sich eine Tabellenstruktur ändert und alte Daten mit den neuen ausgetauscht werden müssen:
DB::statement('UPDATE users SET role_id = 1 WHERE role_id IS NULL AND YEAR(created_at) > 2020');
Darüber hinaus kann DB::statement()
jede SQL-Abfrage mit einem Schema ausführen, das nicht auf Werte oder Spalten beschränkt ist. Hier ist ein Beispiel:
DB::statement('DROP TABLE users');
DB::statement('ALTER TABLE projects AUTO_INCREMENT=123');
Zusammenfassung
Jetzt solltest du ein tiefes Verständnis für Datenbanktransaktionen in Laravel und deren Implementierung haben. Sie helfen nicht nur bei der Datenintegrität, sondern auch dabei, die Leistung von Laravel zu optimieren und deinen Entwicklungsprozess zu vereinfachen.