ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
| この記事の要点 |
|
トランザクションとは
「複数の DB 操作を 1 つの不可分な単位として扱う」ための仕組みです。全部成功 or 全部失敗(ロールバック)の二択しかなく、中途半端な状態を残しません。古典的な銀行送金の例:
-- 送金: A から B へ 1000 円
BEGIN;
UPDATE accounts SET balance = balance - 1000 WHERE id = 'A';
-- ← ここでサーバが落ちたら?
UPDATE accounts SET balance = balance + 1000 WHERE id = 'B';
COMMIT;
トランザクション無しだと、A から引かれたが B に振り込まれない状態で固まります。トランザクションで囲めば、サーバ落ち時に DB が自動で ROLLBACK し、A の残高は元に戻ります。
ACID 特性
| 特性 | 意味 |
|---|---|
| Atomicity(原子性) | 全成功 or 全失敗 |
| Consistency(一貫性) | 制約を満たした状態を維持 |
| Isolation(分離性) | 並行トランザクションの干渉を防ぐ |
| Durability(永続性) | COMMIT 後はクラッシュしても残る |
素の SQL でのトランザクション
-- 標準 SQL
BEGIN;
INSERT INTO orders (user_id, total) VALUES (1, 5000);
-- SELECT LAST_INSERT_ID() を使って order_id を取得
INSERT INTO order_items (order_id, product_id, qty) VALUES (LAST_INSERT_ID(), 10, 2);
COMMIT;
-- 失敗時
BEGIN;
UPDATE accounts SET balance = balance - 1000 WHERE id = 'A';
-- 残高不足を検知
ROLLBACK;
-- MySQL は START TRANSACTION でも同じ
START TRANSACTION;
-- ...
COMMIT;
-- PostgreSQL も BEGIN / COMMIT / ROLLBACK
-- SQL Server は BEGIN TRANSACTION / COMMIT TRANSACTION
Laravel でのトランザクション
Laravel は 2 種類の書き方があります。クロージャ版が推奨です:
use Illuminate\Support\Facades\DB;
// ✅ 推奨: クロージャ版(例外時に自動ロールバック)
DB::transaction(function () use ($request) {
$order = Order::create($request->validated());
foreach ($request->items as $item) {
$order->items()->create($item);
}
$order->user->notify(new OrderPlaced($order));
}, 3); // ← 2 引数目はデッドロック時のリトライ回数
// 手動制御版(細かく制御したいとき)
DB::beginTransaction();
try {
$order = Order::create($request->validated());
foreach ($request->items as $item) {
$order->items()->create($item);
}
DB::commit();
} catch (\Throwable $e) {
DB::rollBack();
throw $e;
}
Spring Boot でのトランザクション
import org.springframework.transaction.annotation.Transactional;
@Service
public class OrderService {
@Transactional
public Order placeOrder(OrderRequest req) {
Order order = orderRepo.save(new Order(req));
for (Item item : req.getItems()) {
itemRepo.save(new OrderItem(order, item));
}
return order;
}
// 読み取り専用
@Transactional(readOnly = true)
public List listOrders() { return orderRepo.findAll(); }
// 分離レベルとロールバック対象指定
@Transactional(
isolation = Isolation.REPEATABLE_READ,
rollbackFor = { Exception.class },
timeout = 30
)
public void complex() { /* ... */ }
}
Spring のデフォルトでは RuntimeException でのみロールバック、検査例外(Checked Exception)はロールバックしません。それを変えるには rollbackFor = Exception.class を指定します。
分離レベル(Isolation Level)
| 分離レベル | ダーティリード | 非再現リード | ファントムリード | 性能 |
|---|---|---|---|---|
| READ UNCOMMITTED | あり | あり | あり | 最速 |
| READ COMMITTED | 無し | あり | あり | 速 |
| REPEATABLE READ(MySQL 既定) | 無し | 無し | あり* | 普通 |
| SERIALIZABLE | 無し | 無し | 無し | 遅 |
* MySQL InnoDB の REPEATABLE READ は MVCC + ギャップロックで実質ファントム無し
-- MySQL で分離レベル設定
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN;
-- ...
COMMIT;
-- セッション単位
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- グローバル
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 現在のレベル確認
SELECT @@transaction_isolation;
デッドロック
2 つ以上のトランザクションが、お互いがロックしているリソースを待つ状態。DB は片方を強制 ABORT します:
SQLSTATE[40001]: Serialization failure: 1213 Deadlock found
when trying to get lock; try restarting transaction
対策:
- ロック順を統一: 必ず ID 昇順で UPDATE する等の規約
- リトライ: Laravel の
DB::transaction($fn, 3)で 3 回まで自動リトライ - トランザクションを短くする: ユーザ入力待ちを挟まない
- 適切なインデックス: 不要なテーブル全行ロックを防ぐ
// Laravel でのリトライ
DB::transaction(function () {
$user = User::lockForUpdate()->find(1); // SELECT ... FOR UPDATE
$user->balance -= 1000;
$user->save();
}, $attempts = 3);
ネスト(セーブポイント)
多くの DB(MySQL InnoDB / PostgreSQL)はトランザクションのネストをセーブポイントで実現します:
BEGIN;
INSERT INTO orders ...;
SAVEPOINT sp1;
UPDATE inventory SET qty = qty - 1 WHERE id = 10;
-- 在庫不足を検知
ROLLBACK TO SAVEPOINT sp1; -- sp1 までロールバック
-- orders の INSERT は残る
COMMIT;
Laravel もネストすると内部的にセーブポイントを使います:
DB::transaction(function () {
User::create([...]); // 外側
try {
DB::transaction(function () {
Order::create([...]); // 内側(SAVEPOINT)
throw new \Exception();
});
} catch (\Throwable $e) {
// 内側だけ ROLLBACK TO SAVEPOINT
// User の create は残る
}
}); // 外側 COMMIT
FOR UPDATE / 共有ロック
-- 排他ロック(UPDATE / DELETE 想定)
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;
-- 共有ロック(読み取りだけ整合性が欲しい)
SELECT * FROM accounts WHERE id = 1 LOCK IN SHARE MODE; -- MySQL
SELECT * FROM accounts WHERE id = 1 FOR SHARE; -- PostgreSQL
-- NOWAIT / SKIP LOCKED(待たない)
SELECT * FROM jobs WHERE status = 'pending' FOR UPDATE SKIP LOCKED LIMIT 1;
FAQ
Q: SELECT 文だけのときもトランザクションは要る?
A: 複数 SELECT で整合性のあるスナップショットが欲しい場合は必要です(REPEATABLE READ)。単発 SELECT なら不要。
Q: 自動コミットモードとは
A: MySQL / PostgreSQL は既定で1 文 = 1 トランザクションで自動 COMMIT します。BEGIN を打つとそれが解除され、明示的に COMMIT/ROLLBACK が必要になります。
Q: トランザクション中の例外で何もしないとどうなる?
A: コネクションが切れるとサーバ側で自動 ROLLBACK されます。ただし明示的にロールバックするのが事故防止上の鉄則です。
Q: 長時間のトランザクションは何が問題?
A: ロック保持時間が長くなるためデッドロック・待ち時間が増え、レプリケーション遅延も発生します。トランザクションは秒オーダーで終わらせる設計が原則です。
ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
子ページはありません
- config/database.phpファイル
- .env
- 複数のデータベースに接続する方法
- DBトランザクション
- DBの悲観ロック
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript base URL 取得方法|window.location.origin と SSR/Node.js 対応
- 4 YouTube Data API v3 エラー一覧|403/400/404 の主要原因と切り分け
- 5 Spring Frameworkのアノテーション一覧
- 6 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 7 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- Laravel キャッシュクリア完全ガイド(cache:clear / config:clear / 2026-05-18 07:42:07
- プロジェクトの作成と削除 2026-05-18 07:42:07
- インストール直後にNetbeansが反応しない 2026-05-18 07:42:07
- 動画やチャンネルの検索 2026-05-18 07:42:07
- APIキー取得方法 2026-05-18 07:42:07
- チャンネル情報の取得 2026-05-18 07:42:07
- API 入門 — Web API(REST / GraphQL / gRPC / 2026-05-18 07:42:07
- インストール(eclipseプラグイン) 2026-05-18 07:42:07
- Laravel「Dotenv values containing spaces must be surrounded 2026-05-18 07:42:07
- エラー一覧 2026-05-18 07:42:07
- curl: (51) SSL: certificate subject name '~' does not match 2026-05-18 07:42:07
- インストール方法(Windows版) 2026-05-18 07:42:07
- JSONから配列に変換 2026-05-18 07:42:07
- 処理を一定時間待つ 2026-05-18 07:42:07
- A non well formed numeric value encountered 2026-05-18 07:42:07
コメントを削除してもよろしいでしょうか?