こんにちは!
オズビジョン開発グループのShoです。
2019年9月~29歳で未経験から営業→エンジニアになった私が、
脱未経験エンジニアを目指して、業務の中で学んだこと、会社の業務について書いて行きます。
私の現状については前回の投稿をご参照ください。
[前回の投稿]
今回は、SQLのトランザクション処理の制御について書いて行きます。
対象読者
私と同じように、異職種からwebエンジニア(バックエンド、フロントエンド)に転職された方。
経験1年未満で毎日分からないことだらけの方。
トランザクションって何?という方。
これから人生で初めて本番環境のDBを触る方。
#今回の投稿の背景
自社のwebサービスにて新機能の追加を担当しており、
実装、テストを終え、本番環境へのリリース手順の作成を任されました。
その際にデータベースへのレコード追加の手順があり、
対象のDBとSQL文を下記のように手順に加えました。
対象DB:hoge
insert into hoges(hoge,fuga) values('qiita','キータ',now());
そして完成したリリース手順をレビュー依頼に出し、
考慮が足りない点、不足している手順、質問などレビューが返ってきました。
その中で、
トランザクションの設定を行って下さい。
本番環境でDBを操作する場合は、ロールバックの余地を残してください。
というコメントを頂きました。
・・・指摘の内容が分からない!!!
トランザクションの意味は理解していましたが、その設定とはどういうこと??
と頭の中が??になりました。
という訳で、今回はSQLでのトランザクションの設定、制御について簡単にまとめました。
#トランザクションとは
ざっくり説明すると、
- **「複数の処理」**のまとまり。
- 処理1 → 処理2 → 処理3 = 1つのトランザクション
- 1つのトランザクションに於いては、複数の処理は分離できない。
- 上記のトランザクションでは、処理1が組み込まれてるので、処理1だけ切り離して独立させることはできない。
- トランザクションは「成功」か「失敗」のいずれかの結果となる。
よく銀行の振込み処理などが例で使用されます。
AさんからBさんの口座へ1,000円の振込みをする
処理1: Aさんの口座から1,000円を差し引き、残高10,000円-1,000円=9,000円にする。
処理2: Bさんの口座へ1,000円プラスして、残高20,000円+1,000円=21,000円にする。
上記のトランザクションでは、
Aさんの残高が9,000円、Bさんの残高が21,000円となったので**「成功」**です!
もし、処理2で何かしらのエラーで起きた場合は、
処理1でAさんの口座から1,000円が引かれているので、
振込み前の状態に戻す必要があります。
Aさんの1,000円どこ行った!!となってしまったら大変です。
これはトランザクションの**「失敗」**です。
このような複数の処理のまとまりによる、一連の処理がトランザクションです。
SQLでもテーブル作成やカラムの追加、レコードの追加の流れもトランザクションです。
この際にどこかの処理で、エラーが起きた際にロールバックできるようにしてね!!!
というのが私が受けたレビューでの指摘です。
本番環境のDBでエラーが起きて最初の状態に戻れなかったら厄介です。
(考えただけで怖い)
#SQLでのトランザクションの制御、設定
では、私はどのように修正すべきでしょうか。
結果のSQL文から書きます。
begin;
select * from hoges where hoge = 'Qiita';
# 検索して0件
insert into hoges(hoge,fuga) values('Qiita','キータ',now());
select * from hoges where hoge = 'Qiita';
#検索して1件
commit;
-
begin;
でここからトランザクションの開始です!という開始の宣言。 -
Qiita
が新しく追加するものなので、追加前に存在しないかの確認 - レコードの追加
- レコードが本当に追加されたかの確認。
-
commit;
で処理の確定(この場合はinsert)
上記のようにbegin;
からcommit;
で処理の確定が行われるまでが、一連のトランザクションとして扱われます。
今回の処理でエラーが起きた際にはrollback;
で処理前の状態に戻すことができます。
今回は一つのトランザクションなので省略していますが、
複数のトランザクションがある場合は、トランザクション毎に名前をつければ、指定した処理をロールバックすることが可能です。
begin transaction [トランザクション名];
rollback transaction [トランザクション名];
途中のselect
は実際の処理ではなく、確認の為に挟んでいます。
本番環境ともなれば随時確認しながら進めて行くことが重要、ということも勉強になりました。
レビューがなかったら、本番DBに直でinsertしてました。
今考えると危なすぎです...。
もし、初めて本番環境でDBを操作することがある方は頭に入れておくと良いと思います。
誰かの参考になれば幸いです。
#余談
手順のレビューをもらい、手順にトランザクションの制御を入れ上述のように修正しました。
実はOKをもらう前にもう一回修正をしております。
"Qiitaで検索して0件"
"Qiitaで検索して1件"
という項目も入れた方がいいよ!と言われ、
手順に上記の文章をそのまま書きました。
そしてレビューで
...いやそこはSQL文で書いてよ!笑
と突っ込まれ、上記のselect文にするんだ!と気づきました。
そりゃそうですよね。当たり前です...。
恥ずかしい...。
エンジニア力のなさを実感した瞬間です。笑