> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# 資料庫設定

> 說明 Laravel 的資料庫連線設定、read/write 分離、多重連線、SQL 執行、查詢監聽與 transaction 的基本概念。

## 簡介

Laravel 官方支援下列資料庫：

* MySQL / MariaDB
* PostgreSQL
* SQLite
* SQL Server

無論你使用原生 SQL、Query Builder 或 Eloquent ORM，都可以共用相同的連線設定。

<Info>
  本頁著重於資料庫連線的前提。實務查詢請參閱 [Query Builder](/zh-TW/query-builder)，Schema 管理請見 [Migrations](/zh-TW/migrations)，資料初始化請見 [Seeding](/zh-TW/seeding)。
</Info>

## 設定

資料庫設定集中在 `config/database.php`。
你可以在 `default` 選擇預設連線名稱，並在 `connections` 中定義各連線的細節。

```mermaid theme={null}
flowchart TD
    A[".env"] --> B["config/database.php"]
    B --> C["default connection"]
    B --> D["connections.mysql"]
    B --> E["connections.pgsql"]
    B --> F["connections.sqlite"]
    C --> G["DB facade / Query Builder / Eloquent"]
```

```php theme={null}
// config/database.php
'default' => env('DB_CONNECTION', 'sqlite'),

'connections' => [
    'mysql' => [
        'driver' => 'mysql',
        'host' => env('DB_HOST', '127.0.0.1'),
        'port' => env('DB_PORT', '3306'),
        'database' => env('DB_DATABASE', 'laravel'),
        'username' => env('DB_USERNAME', 'root'),
        'password' => env('DB_PASSWORD', ''),
    ],
],
```

`.env` 至少設定以下項目：

```ini theme={null}
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=app
DB_USERNAME=app_user
DB_PASSWORD=secret
```

若使用 SQLite，請設定 `DB_CONNECTION=sqlite` 與 `DB_DATABASE` 的檔案路徑。

## 讀寫連線分離

若要將讀取（`SELECT`）與寫入（`INSERT` / `UPDATE` / `DELETE`）分別放到不同主機，可在同一連線內設定 `read` 與 `write`。

```php theme={null}
'mysql' => [
    'driver' => 'mysql',
    'read' => [
        'host' => ['10.0.0.10', '10.0.0.11'],
    ],
    'write' => [
        'host' => ['10.0.0.20'],
    ],
    'sticky' => true,

    'port' => env('DB_PORT', '3306'),
    'database' => env('DB_DATABASE', 'laravel'),
    'username' => env('DB_USERNAME', 'root'),
    'password' => env('DB_PASSWORD', ''),
],
```

將 `sticky` 設為 `true` 時，同一次請求內於寫入後的讀取都會固定到 write 連線。

<Tip>
  若有 replica 延遲，啟用 `sticky` 可以降低寫入後立刻讀到舊資料的風險。
</Tip>

## Pooled PostgreSQL 連線

當你使用如 PgBouncer 等提供交易模式連線池的託管 PostgreSQL 服務時，可以設定 `pooled` 與 `direct` 選項。

```php theme={null}
'pgsql' => [
    'driver' => 'pgsql',
    // ...
    'pooled' => env('DB_POOLED', false),
    'direct' => array_filter([
        'host' => env('DB_DIRECT_HOST'),
        'port' => env('DB_DIRECT_PORT'),
        'username' => env('DB_DIRECT_USERNAME'),
        'password' => env('DB_DIRECT_PASSWORD'),
        'sslmode' => env('DB_DIRECT_SSLMODE'),
    ]),
],
```

啟用 `pooled` 後，Laravel 會自動分派：

| 操作                                             | 使用的連線                             |
| ---------------------------------------------- | --------------------------------- |
| 應用程式查詢                                         | pooled（會自動啟用 emulated prepared）   |
| Migration / `db:wipe` / `db:show` / `db:table` | direct（自動）                        |
| `php artisan db`                               | direct（預設）；加 `--pooled` 切至 pooled |

若想在應用程式碼中明確使用 direct 連線，可在連線名稱後加上 `::direct` 後綴。

```php theme={null}
DB::connection('pgsql::direct')->statement('create extension if not exists "uuid-ossp"');
```

## 多重資料庫連線

你可以在 `config/database.php` 定義多個連線，並透過 `DB::connection()` 切換。

```php theme={null}
use Illuminate\Support\Facades\DB;

$users = DB::connection('sqlite')->select('select * from users');
$pdo = DB::connection('pgsql')->getPdo();
```

```mermaid theme={null}
flowchart LR
    A["DB::connection('mysql')"] --> B["Primary DB"]
    C["DB::connection('pgsql')"] --> D["Analytics DB"]
    E["DB::connection('sqlite')"] --> F["Local file DB"]
```

## 執行 SQL 查詢

`DB` Facade 依照查詢類型提供對應的方法。

```php theme={null}
use Illuminate\Support\Facades\DB;

$users = DB::select('select * from users where active = ?', [1]);

DB::insert('insert into users (name, email) values (?, ?)', ['Taylor', 'taylor@example.com']);

$affected = DB::update('update users set votes = 100 where name = ?', ['Taylor']);

$deleted = DB::delete('delete from sessions where user_id = ?', [1]);

DB::statement('drop table temporary_imports');
```

<Warning>
  切勿將使用者輸入直接串接到 SQL 字串中。務必使用參數繫結以防止 SQL injection。
</Warning>

## 查詢監聽

若想追蹤已執行的 SQL，可在 Service Provider 的 `boot()` 中註冊 `DB::listen()`。

```php theme={null}
use Illuminate\Database\Events\QueryExecuted;
use Illuminate\Support\Facades\DB;

public function boot(): void
{
    DB::listen(function (QueryExecuted $query) {
        logger()->debug('SQL executed', [
            'sql' => $query->toRawSql(),
            'time_ms' => $query->time,
        ]);
    });
}
```

## Transaction

若要把多個更新視為一個單元，可使用 `DB::transaction()`。
發生例外時 Laravel 會自動 rollback。

```php theme={null}
use Illuminate\Support\Facades\DB;

DB::transaction(function () {
    DB::update('update users set votes = 1');
    DB::delete('delete from posts where archived = 1');
});
```

若需要死鎖重試，可以指定 `attempts`。

```php theme={null}
DB::transaction(function () {
    // ...
}, attempts: 5);
```

若想手動控制，可使用 `beginTransaction` / `rollBack` / `commit`。

```php theme={null}
DB::beginTransaction();

try {
    DB::update('update accounts set balance = balance - 100 where id = ?', [1]);
    DB::update('update accounts set balance = balance + 100 where id = ?', [2]);

    DB::commit();
} catch (\Throwable $e) {
    DB::rollBack();
    throw $e;
}
```

## 下一步

<Card title="Query Builder" icon="table" href="/zh-TW/query-builder">
  學習如何在連線設定之上安全地組建查詢。
</Card>

<Card title="Migrations" icon="hammer" href="/zh-TW/migrations">
  學習如何對已連線的資料庫 schema 進行版本控管。
</Card>

<Card title="Seeding" icon="seedling" href="/zh-TW/seeding">
  學習如何以可重現的方式匯入開發 / 測試用資料。
</Card>


## Related topics

- [Socialite - Laravel Bluesky](/zh-TW/packages/laravel-bluesky/socialite.md)
- [MongoDB](/zh-TW/mongodb.md)
- [資料庫 Seeding](/zh-TW/seeding.md)
- [設定](/zh-TW/configuration.md)
- [起始套件（Starter Kit）](/zh-TW/starter-kits.md)
