Skip to content

Laravel - 数据库操作

Laravel 提供了一种强大而优雅的方式与数据库交互。它开箱即用地支持多种数据库系统,并提供了多种执行数据库操作的方式:原生 SQL 查询(raw SQL queries)、流畅的查询构造器(Query Builder)以及 Eloquent ORM(对象关系映射器)。

支持的数据库:

  • MySQL / MariaDB
  • PostgreSQL
  • SQLite
  • SQL Server

数据库连接配置主要在 Laravel 项目根目录下的 .env 文件中管理。Laravel 的 config/database.php 文件会使用这些环境变量来设置连接。

MySQL 的 .env 配置示例:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=your_database_name
DB_USERNAME=your_username
DB_PASSWORD=your_password

请务必将 your_database_name、your_username 和 your_password 替换为您的实际数据库凭据。修改 .env 文件后,您可能需要清除配置缓存:

php artisan config:clear

在执行 CRUD 操作之前,您需要一个数据库表。Laravel 的数据库迁移(Migrations)就像是数据库的版本控制,让您可以轻松地定义和修改数据库 schema(模式)。您可以使用以下命令创建一个迁移:

php artisan make:migration create_students_table

然后,在生成的迁移文件(例如,database/migrations/xxxx_xx_xx_xxxxxx_create_students_table.php)中定义您的表结构:

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('students', function (Blueprint $table) {
$table->id(); // Auto-incrementing BIGINT primary key 'id'
$table->string('name', 100);
$table->string('email')->unique();
$table->timestamps(); // Adds 'created_at' and 'updated_at' columns
});
}
public function down(): void
{
Schema::dropIfExists('students');
}
};

运行迁移以创建表:

php artisan migrate

Laravel 允许您使用 DB Facade(外观)运行原生 SQL 查询。虽然出于安全性和可维护性的考虑,通常不建议优先使用它,但当需要时它是可用的。

警告:使用原生 SQL 时,务必始终使用参数绑定(parameter binding)来防范 SQL 注入(SQL injection)漏洞。

使用 DB::insert() 进行 INSERT 语句操作。它返回 true 或 false。

use Illuminate\Support\Facades\DB;
DB::insert('INSERT INTO students (name, email, created_at, updated_at) VALUES (?, ?, ?, ?)',
['Alice Smith', 'alice@example.com', now(), now()]
);

使用 DB::select() 进行 SELECT 语句操作。它返回一个 stdClass 对象数组。

$students = DB::select('SELECT * FROM students WHERE id = ?', [1]);
foreach ($students as $student) {
// echo $student->name;
}

使用 DB::update() 进行 UPDATE 语句操作。它返回受影响的行数。

$affectedRows = DB::update('UPDATE students SET name = ? WHERE email = ?',
['Alicia Smith', 'alice@example.com']
);

使用 DB::delete() 进行 DELETE 语句操作。它返回受影响的行数。

$deletedRows = DB::delete('DELETE FROM students WHERE id = ?', [1]);

对于其他类型的语句(例如,如果不使用迁移,可以使用 CREATE TABLE、DROP TABLE),请使用 DB::statement():

DB::statement('DROP TABLE IF EXISTS old_table');

Laravel 的数据库查询构造器(Query Builder)提供了一个方便、流畅的接口来创建和运行数据库查询。它可用于在应用程序中执行大多数数据库操作,并且适用于所有支持的数据库系统。

它提供了更好的安全性(自动 PDO 参数绑定),并且比原生 SQL 查询更具表现力。

DB::table('students')->insert([
'name' => 'Bob Johnson',
'email' => 'bob@example.com',
'created_at' => now(),
'updated_at' => now()
]);
// Insert multiple records
DB::table('students')->insert([
['name' => 'Charlie Brown', 'email' => 'charlie@example.com', 'created_at' => now(), 'updated_at' => now()],
['name' => 'Diana Prince', 'email' => 'diana@example.com', 'created_at' => now(), 'updated_at' => now()]
]);
// Get all students
$allStudents = DB::table('students')->get();
// Get a single student by ID
$student = DB::table('students')->where('id', 2)->first();
// Get students matching a condition
$activeStudents = DB::table('students')->where('name', 'like', 'A%')->get();
// Pluck a single column's values
$studentNames = DB::table('students')->pluck('name');
$affected = DB::table('students')
->where('id', 2)
->update(['name' => 'Robert Johnson']);
$deleted = DB::table('students')->where('id', 3)->delete();
// Delete all records (use with caution!)
// DB::table('students')->delete();
// Better way to truncate a table (resets auto-incrementing ID)
// DB::table('students')->truncate();

Laravel 的 Eloquent ORM 是一个优雅的 ActiveRecord 实现,用于与数据库交互。每个数据库表都有一个对应的“模型”(Model),用于与该表进行交互。模型允许您查询表中的数据,以及向表中插入新记录。

虽然查询构造器功能强大,但 Eloquent 添加了一个面向对象的层,使得交互更加直观,特别是在处理表之间的关系时。这个主题内容广泛,通常会在单独的章节中介绍。

让我们概述如何在控制器中使用查询构造器实现“学生”实体的 CRUD(创建、读取、更新、删除)操作。首先,确保您有一个 students 表(参见上面的“数据库迁移”部分)。

创建一个 StudentController:

php artisan make:controller StudentController

然后,将方法添加到 app/Http/Controllers/StudentController.php 中(这些是简化示例):

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\View\View;
use Illuminate\Http\RedirectResponse;
class StudentController extends Controller
{
// Display a list of students
public function index(): View
{
$students = DB::table('students')->orderBy('name')->get();
return view('students.index', ['students' => $students]);
}
// Show the form for creating a new student
public function create(): View
{
return view('students.create');
}
// Store a newly created student in storage
public function store(Request $request): RedirectResponse
{
$validated = $request->validate([
'name' => 'required|string|max:100',
'email' => 'required|email|unique:students,email',
]);
DB::table('students')->insert([
'name' => $validated['name'],
'email' => $validated['email'],
'created_at' => now(),
'updated_at' => now(),
]);
return redirect()->route('students.index')->with('success', 'Student created successfully.');
}
// Show the form for editing the specified student
public function edit(int $id): View
{
$student = DB::table('students')->where('id', $id)->first();
if (!$student) {
abort(404);
}
return view('students.edit', ['student' => $student]);
}
// Update the specified student in storage
public function update(Request $request, int $id): RedirectResponse
{
$validated = $request->validate([
'name' => 'required|string|max:100',
'email' => 'required|email|unique:students,email,' . $id, // Ignore current student's email for unique check
]);
$affected = DB::table('students')
->where('id', $id)
->update([
'name' => $validated['name'],
'email' => $validated['email'],
'updated_at' => now(),
]);
if ($affected) {
return redirect()->route('students.index')->with('success', 'Student updated successfully.');
}
return redirect()->route('students.index')->with('error', 'Student not found or no changes made.');
}
// Remove the specified student from storage
public function destroy(int $id): RedirectResponse
{
$deleted = DB::table('students')->where('id', $id)->delete();
if ($deleted) {
return redirect()->route('students.index')->with('success', 'Student deleted successfully.');
}
return redirect()->route('students.index')->with('error', 'Student not found.');
}
}

然后,您需要在 routes/web.php 中定义路由(Routes),将 URL 映射到这些控制器操作,并创建相应的 Blade 视图(Views)(students/index.blade.php、students/create.blade.php 等)。

常见学习障碍:忘记参数绑定

在使用原生 SQL(DB::select、DB::insert 等)时,一个常见的错误是直接将用户输入嵌入到查询字符串中。这会使您的应用程序容易受到 SQL 注入攻击。务必始终使用 ? 占位符,并将值作为数组传递给第二个参数。查询构造器和 Eloquent 会自动为您处理此问题。