sql >> データベース >  >> RDS >> Database

SQLでのトランザクションを理解する

    SQLのトランザクションは、1つ以上のタスクをグループ化する実行単位です。トランザクション内のすべてのタスクがエラーなしで実行された場合、トランザクションは成功したと見なされます。

    ただし、トランザクション内のタスクのいずれかが実行に失敗すると、トランザクション全体が失敗します。トランザクションの結果は、成功または失敗の2つだけです。

    実用的なシナリオ

    ATM(現金自動預け払い機)の実際的な例を考えてみましょう。あなたはATMに行き、それはあなたのカードを要求します。カードが有効かどうかを確認するためのクエリを実行します。次に、ピンコードを尋ねられます。ここでも、ピンコードに一致するクエリを実行します。次に、ATMは引き出したい金額を尋ね、希望する金額を入力します。 ATMは別のクエリを実行してアカウントからその金額を差し引き、その金額をあなたに分配します。

    アカウントから金額が差し引かれ、その後、メモを出さずに停電が原因でシステムがクラッシュした場合はどうなりますか?

    これは、顧客がお金を受け取らずに資金を差し引いているため、問題があります。これは、トランザクションが便利な場所です。

    システムクラッシュまたはその他のエラーが発生した場合、トランザクション内のすべてのタスクがロールバックされます。そのため、ATMの場合、なんらかの理由で出金できない場合は、口座に返金されます。

    トランザクションとは何ですか?

    最も単純な場合、データベーステーブルの変更はトランザクションです。したがって、INSERT、UPDATE、およびDELETEステートメントはすべてトランザクションステートメントです。クエリを作成すると、トランザクションが実行されます。ただし、このトランザクションを元に戻すことはできません。トランザクションがどのように作成され、コミットされ、ロールバックされるかを以下で確認しますが、最初に、使用するダミーデータを作成しましょう。

    データの準備 データベースサーバーで次のスクリプトを実行します。

    CREATE DATABASE schooldb
    
    CREATE TABLE student
    (
        id INT PRIMARY KEY,
        name VARCHAR(50) NOT NULL,
        gender VARCHAR(50) NOT NULL,
        age INT NOT NULL,
        total_score INT NOT NULL,
        
     )
    
    INSERT INTO student 
    
    VALUES (1, 'Jolly', 'Female', 20, 500), 
    (2, 'Jon', 'Male', 22, 545), 
    (3, 'Sara', 'Female', 25, 600), 
    (4, 'Laura', 'Female', 18, 400), 
    (5, 'Alan', 'Male', 20, 500)

    上記のSQLスクリプトは、データベースschooldbを作成します。このデータベースでは、テーブルの学生が作成され、いくつかのダミーデータがそのテーブルに追加されます。

    トランザクションなしでクエリを実行する

    3つの標準クエリを実行してみましょう。現在、トランザクションは使用していません。

    INSERT INTO student 
    VALUES (6, 'Suzi', 'Female', 25, 395)
    
    UPDATE student
    SET age = 'Six' WHERE id= 6
    
    DELETE from student
    WHERE id = 6

    ここで、最初のクエリは学生レコードをデータベースに挿入します。 2番目のクエリは学生の年齢を更新し、3番目のクエリは新しく挿入されたレコードを削除します。

    上記のスクリプトを実行すると、レコードがデータベースに挿入され、2番目のクエリの実行中にエラーが発生することがわかります。

    2番目のクエリを見ると、整数型のデータを格納できる年齢列に文字列値を格納することで、年齢を更新しています。したがって、エラーがスローされます。ただし、最初のクエリは引き続き正常に完了します。これは、学生テーブルからすべてのレコードを選択すると、新しく挿入されたレコードが表示されることを意味します。

    [table id =23 /]

    id=6で名前が「Suzi」のレコードがデータベースに挿入されていることがわかります。しかし、年齢を更新できず、2番目のクエリは失敗しました。

    これが不要な場合はどうなりますか?すべてのクエリが正常に実行されること、またはどのクエリもまったく実行されないことを確認したい場合はどうなりますか?ここでトランザクションが便利になります。

    トランザクションを使用したクエリの実行

    次に、トランザクション内で上記の3つのクエリを実行しましょう。

    まず、トランザクションを作成してコミットする方法を見てみましょう。

    トランザクションの作成

    クエリをトランザクションとして実行するには、クエリをBEGINTRANSACTIONキーワードとCOMMITTRANSACTIONキーワードでラップするだけです。 BEGIN TRANSACTIONはトランザクションの開始を宣言し、COMMITTRANSACTIONはトランザクションが完了したことを示します。

    以前にトランザクションとして作成したデータベースに対して、3つの新しいクエリを実行してみましょう。 ID7の新入生の新しいレコードを追加します。

    BEGIN TRANSACTION
    
    	INSERT INTO student 
    	VALUES (7, 'Jena', 'Female', 22, 456)
    
    	UPDATE student
    	SET age = 'Twenty Three' WHERE id= 7
    
    	DELETE from student
    	WHERE id = 7
    
    COMMIT TRANSACTION

    上記のトランザクションを実行すると、整数型のデータのみを格納するage列に文字列型の値が格納されているため、2番目のクエリでエラーが発生します。

    ただし、エラーはトランザクション内で発生するため、このエラーが発生する前に正常に実行されたすべてのクエリは自動的にロールバックされます。したがって、id=7で名前が「Jena」の新しい学生レコードを挿入する最初のクエリもロールバックされます。

    これで、生徒のテーブルからすべてのレコードを選択すると、「イエナ」の新しいレコードが挿入されていないことがわかります。

    手動トランザクションロールバック

    クエリがトランザクション内でエラーをスローした場合、すでに実行されたすべてのクエリを含むトランザクション全体が自動的にロールバックされます。ただし、必要に応じていつでも手動でトランザクションを手動でロールバックすることもできます。

    トランザクションをロールバックするには、キーワードROLLBACKを使用し、その後にトランザクションの名前を続けます。トランザクションに名前を付けるには、次の構文が使用されます。

    BEGIN TRANSACTION Transaction_name

    学生テーブルに、重複する学生名を含むレコードがないようにしたいとします。新入生のレコードを追加します。次に、新しく挿入された学生の名前と同じ名前の学生がデータベースに存在するかどうかを確認します。その名前の学生がまだ存在しない場合は、トランザクションをコミットします。その名前の学生が存在する場合は、トランザクションをロールバックします。クエリで条件ステートメントを使用します。

    次のトランザクションを確認してください:

    DECLARE @NameCount int
    
    BEGIN TRANSACTION AddStudent
    
    	INSERT INTO student 
    	VALUES (8, 'Jacob', 'Male', 21, 600)
    
    	SELECT @NameCount = COUNT(*) FROM student WHERE name = 'Jacob'
    
    	IF @NameCount > 1
    		BEGIN 
    			ROLLBACK TRANSACTION AddStudent
    			PRINT 'A student with this name already exists'
    		END
    	ELSE
    		BEGIN
    			COMMIT TRANSACTION AddStudent
    			PRINT 'New record added successfully'
    		END
    上記のスクリプトを注意深く見てください。ここではたくさんのことが起こっています。

    最初の行で、整数型のSQL変数NameCountを作成します。

    次に、「AddStudent」という名前のトランザクションを開始します。トランザクションには任意の名前を付けることができます。

    トランザクション内に、ID=8で名前が「Jacob」の学生の新しいレコードを挿入しました。

    次に、COUNT集計関数を使用して、名前が「Jacob」である学生レコードの数をカウントし、その結果を「NameCount」変数に格納します。

    変数の値が1より大きい場合は、「Jacob」という名前の学生がデータベースにすでに存在していることを意味します。その場合、トランザクションをロールバックし、「この名前の学生はすでに存在します」というメッセージを画面に印刷します。

    そうでない場合は、トランザクションをコミットし、「新しいレコードが正常に追加されました」というメッセージを表示します。

    上記のトランザクションを初めて実行するとき、「Jacob」という名前の学生レコードはありません。したがって、トランザクションがコミットされ、次のメッセージが出力されます。

    次に、サーバーで次のSQLスクリプトを実行してみます。

    DECLARE @NameCount int
    
    BEGIN TRANSACTION AddStudent
    
    	INSERT INTO student 
    	VALUES (9, 'Jacob', 'Male', 22, 400)
    
    	SELECT @NameCount = COUNT(*) FROM student WHERE name = 'Jacob'
    
    	IF @NameCount > 1
    		BEGIN 
    			ROLLBACK TRANSACTION AddStudent
    			PRINT 'A student with this name already exists'
    		END
    	ELSE
    		BEGIN
    			COMMIT TRANSACTION
    			PRINT 'New record added successfully'
    		END

    ここでも、id=9で名前が「Jacob」の学生レコードを挿入しています。 「Jacob」という名前の学生レコードがデータベースにすでに存在するため、トランザクションはロールバックされ、次のメッセージが出力されます。

    便利なリンク

    • SQLトランザクションのクラス

    1. Oracleで日付から世紀を取得する方法

    2. PostgreSQLでのAtan2()のしくみ

    3. MYSQLで7日より古い行を自動的に削除するストアドプロシージャ

    4. 1から100までの数値のリストを生成するSQL