1 つのトランザクションとしてのデータ操作の実行
Apex トランザクションとは?
Apex トランザクションは、1 つの単位として実行される一連の操作を表します。トランザクションの実行には、すべての DML 操作が正常に完了することが求められます。いずれかの操作でエラーが発生した場合はトランザクション全体がロールバックされます。この場合、データは一切データベースにコミットされません。トランザクションの境界は、トリガ、クラスメソッド、匿名のコードブロック、Visualforce ページ、カスタム Web サービスメソッドのいずれかにすることができます。
トランザクション境界内部で発生するすべての操作は、操作の 1 つの単位に相当します。これは、トランザクション境界内で実行されたコードの結果として起動されたクラスやトリガなど、トランザクション境界から外部コードへのコールにも適用されます。たとえば、カスタム Apex Web サービスメソッドによってトリガが起動し、そのトリガがクラスのメソッドをコールするという連続した操作があるとします。この場合、トランザクション内のすべての操作がエラーなしで実行を完了した後にのみ、すべての変更がデータベースにコミットされます。中間ステップのいずれかでエラーが発生した場合、すべてのデータベース変更はロールバックされ、トランザクションはコミットされません。
トランザクションが便利な場合とは?
トランザクションは、複数の操作が関連していて、それらの操作のすべてをコミットするか、一切コミットしないかのいずれかにする必要がある場合に便利です。これにより、データベースは整合性の取れた状態に保たれます。トランザクション処理は、さまざまなビジネスシナリオで活用されています。たとえば、一般的なシナリオとして銀行口座間での送金があります。最初の口座から送金額を引き落とし、その金額を 2 つ目の口座に入金します。これら 2 つの操作は、一緒にデータベースにコミットする必要があります。引き落とし操作が成功して入金操作が失敗したような場合に、口座残高に矛盾が生じることを防ぐためです。
実際に試してみる
この例は、最後の操作で入力規則エラーが発生した場合、すべてのデータベース insert 操作がどのようにロールバックされるかを示しています。この例では、invoice メソッドがトランザクション境界です。このメソッド内で実行されるすべてのコードは、データベースにすべての変更をコミットするか、すべての変更をロールバックします。この場合、Line Item (品目名) として鉛筆を指定した、新しい請求書明細を追加します。この Line Item を使用して、5,000 本の鉛筆を購入 (Units_Sold__c 項目に指定) します。これは鉛筆の全在庫数量 1,000 本を上回ります。
第 1 章で作成したサンプルの Line Item オブジェクトには入力規則が含まれます。この入力規則は、商品品目の全在庫数量が新規購入に足りるかどうかをチェックします。この例では、在庫数量 (1,000) よりも多く (5,000) の鉛筆を購入しようとしているので、入力規則は失敗して、実行時例外が発生します。コードの実行はこの時点で停止し、この例外よりも前に処理されたすべての DML 操作はロールバックされます。この場合、請求書明細と品目名はデータベースには追加されず、その insert DML 操作はロールバックされます。
- 開発者コンソールで次のクラスを追加します。
- クラス名として「MerchandiseOperations」と入力し、自動生成されたコードを次の例で置き換えます。
1public class MerchandiseOperations { 2 public static Id invoice( String pName, Integer pSold, String pDesc) { 3 // Retrieve the pencils sample merchandise 4 Merchandise__c m = [SELECT Price__c,Total_Inventory__c 5 FROM Merchandise__c WHERE Name = :pName LIMIT 1]; 6 // break if no merchandise is found 7 System.assertNotEquals(null, m); 8 // Add a new invoice 9 Invoice_Statement__c i = new Invoice_Statement__c( 10 Description__c = pDesc); 11 insert i; 12 13 // Add a new line item to the invoice 14 Line_Item__c li = new Line_Item__c( 15 Name = '1', 16 Invoice_Statement__c = i.Id, 17 Merchandise__c = m.Id, 18 Unit_Price__c = m.Price__c, 19 Units_Sold__c = pSold); 20 insert li; 21 22 // Update the inventory of the merchandise item 23 m.Total_Inventory__c -= pSold; 24 update m; 25 return i.Id; 26 } 27} - 開発者コンソールで、静的 invoice メソッドを実行します。
1Id invoice = MerchandiseOperations.invoice('Pencils', 5000, 'test 1');このスニペットでは、品目名の挿入時に品目名に対する入力規則が失敗し、DmlException が返されます。すべての DML 操作はロールバックされます。請求書明細と品目名はデータベースにはコミットされません。
- 実行ログで入力規則のエラーメッセージと例外を探しましょう。[Filter (条件)] の横に「VF_PAGE_MESSAGE」と入力します。
入力規則のエラーメッセージが絞り込まれたビューに表示されます (You have ordered more items than we have in stock.)。
- 次に、検索項目に「exception」と入力し、例外を調べます。
- 前のスニペットを削除して、次の 2 つ目のコードのスニペットを実行します。
1Id invoice = MerchandiseOperations.invoice('Pencils', 5, 'test 2');このスニペットは、品目名を含む新しい請求書明細を挿入し、データベースにコミットします。鉛筆の購入数量が全在庫数量以下であるため、入力規則の検証は成功します。