この文章は Salesforce 機械翻訳システムを使用して翻訳されました。詳細はこちらをご参照ください。
英語に切り替える

トランザクションの制御

「トランザクション要求」、「savepoint の生成とリリース」、「トランザクションのロールバック」などを参照してください。

すべての要求は、Apex コードを実行するトリガー、クラスメソッド、Web サービス、Visualforce ページ、または匿名ブロックによって区切られます。要求全体が正常に完了した場合、すべての変更はデータベースに確定されます。たとえば、Visualforce ページが Apex コントローラーをコールしたことにより、さらに Apex クラスがコールされたとします。すべての Apex コードの実行が完了し、Visualforce ページの実行が完了したときに、変更がデータベースに確定されます。要求が正常に完了しなかった場合は、データベースへのすべての変更はロールバックされます。

savepoint の生成とトランザクションのロールバック

場合によっては、ビジネスルールによってレコードの処理中に作業の一部 (すでに実行された DML ステートメント) をロールバックして、その処理を別の指示のもとで続行できるようにする必要があります。Apex では、savepoint を生成できます。これは要求中のある時点を示し、その時点でのデータベースの状態を指定します。savepoint の後にある DML ステートメントを破棄して、savepoint の生成時の状態にデータベースを復元できます。savepoint 以降に取得されたすべてのテーブルと行のロックはリリースされます。

次の制限事項は、savepoint 変数の生成とデータベースのロールバックに適用されます。

  • 複数の savepoint を設定し、生成された最新の savepoint 以外の savepoint にロールバックした場合、後から設定した savepoint 変数もロールバックされ、無効になります。たとえば、最初に savepoint SP1 を生成し、次に savepoint SP2 を生成した場合、SP1 にロールバックすると、変数 SP2 は無効になります。savepoint SP2 を使用しようとすると、ランタイムエラーが発生します。
  • 各トリガー呼び出しが新しいトリガーコンテキストであるため、savepoints への参照は、トリガー呼び出しを通過することはできません。静的変数として savepoint を宣言し、トリガーコンテキスト全体で使用しようとすると、ランタイムエラーが発生します。
  • 設定した各セーブポイントは、DML ステートメントのガバナ制限に含まれます。
  • ロールバック中、静的変数は戻されません。トリガーの実行を再試行する場合、静的変数には最初の実行から得た値が維持されます。

  • Database.rollback(Savepoint) では、DML 行数制限にはカウントされませんが、DML 文字制限にはカウントされます。この動作は、すべての API バージョンに適用されます。
  • savepoint の設定後に挿入された sObject の ID は、ロールバック後にクリアされません。ロールバック前に作成した変数を使用して sObject を挿入しようとすると、その sObject 変数には ID があるため失敗します。同じ変数を使用して sObject を更新または更新/挿入しようとした場合も、sObject はデータベース内に存在せず、更新できないため失敗します。DML 操作をさらに行うには、ID を設定せずに sObject 変数を作成します。

setSavepointrollback データベースメソッドの使用例を次に示します。

1Account a = new Account(Name = 'xyz');
2insert a; 
3Assert.isNull([SELECT AccountNumber FROM Account WHERE Id  = :a.Id]. AccountNumber);  
4// Create a savepoint while AccountNumber is null 
5Savepoint sp = Database.setSavepoint(); 
6// Change the account number 
7a.AccountNumber = '123'; 
8update a; 
9Assert.areEqual('123', [SELECT AccountNumber FROM Account WHERE Id  = :a.Id]. AccountNumber); 
10// Rollback to the previous null value 
11Database.rollback(sp);
12Assert.isNull([SELECT AccountNumber FROM Account WHERE Id  = :a.Id]. AccountNumber);

savepoint のリリースとコールアウトの使用

コールアウトを許可するには、savepoint を使用して、コミットされていない DML をすべてロールバックします。次に、Database.releaseSavepoint メソッドを使用して、目的のコールアウトを行う前に savepoint を明示的にリリースします。Database.releaseSavepoint() がコールされると、SAVEPOINT_RELEASE がログに記録されます。

詳細は、「releaseSavepoint()」を参照してください。

この例では、コミットされていない DML がロールバックされ、savepoint がリリースされたため、makeACallout() コールアウトが成功しています。

1Savepoint sp = Database.setSavepoint();
2try {
3  // Try a database operation
4  insert new Account(name='Foo');
5  integer bang = 1 / 0;
6} catch (Exception ex) {
7   Database.rollback(sp);
8   Database.releaseSavepoint(sp);
9   makeACallout();
10}
11

この例では、コールアウトを行う前に savepoint がリリースされていません。CalloutException は、コールアウトを行う前にすべてのアクティブな savepoint をリリースする必要があることを通知します

1Savepoint sp = Database.setSavepoint();
2try {
3  makeACallout(); 
4} catch (System.CalloutException ex) {
5   Assert.isTrue(ex.getMessage().contains('All active Savepoints must be released before making callouts.'));
6}
7

この例では、コールアウトが行われた時点で、DML は保留中です。CalloutException は、コールアウトを行う前にトランザクションをロールバックするか、トランザクションをコミットする必要があることを通知します。

1Savepoint sp = Database.setSavepoint();
2insert new Account(name='Foo');
3Database.releaseSavepoint(sp);
4try {
5  makeACallout(); 
6} catch (System.CalloutException ex) {
7   Assert.isTrue(ex.getMessage().contains('You have uncommitted work pending. Please commit or rollback before calling out.'));
8}
9

コールアウトと savepoint の使用については、これらのガイドラインを参照してください。

  • Database.releaseSavepoint() がコールされた時点でコミットされていない作業が保留されている場合、コミットされていない作業はロールバックされません。トランザクションが成功するとコミットされます。
  • リリースされた savepoint にロールバックしようとすると、TypeException になります。
  • Database.releaseSavepoint() をコールした後にロールバックしようとすると、System.InvalidOperationException になります。 
  • savepoint に対して Database.releaseSavepoint() メソッドをコールすると、ネストされた savepoint もリリースされます。

バージョン管理動作の変更

API バージョン 60.0 以降の Apex テストでは、Test.startTest()Test.stopTest() がコールされると、すべての savepoint がリリースされます。いずれかの savepoint がリセットされると、SAVEPOINT_RESET イベントが記録されます。

API バージョン 60.0 より前のバージョンでは、savepoint を作成した後にコールアウトを実行すると、コミットされていない DML や変更が savepoint にロールバックされたかにかかわらず、CalloutException が発生します。また、API バージョン 60.0 より前のバージョンでは、ロールバックをコールするたびに DML 行の使用制限が増加します。