0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Part 5: ガバナ制限を考慮したエラーハンドリングとバッチ処理の例外処理

Posted at

Part 5: ガバナ制限を考慮したエラーハンドリングとバッチ処理の例外処理

前回は エラーログの記録、ユーザー通知、トランザクション管理 について解説しました。
今回は ガバナ制限を考慮したエラーハンドリングバッチ処理の例外処理 について詳しく解説します。


1. ガバナ制限を考慮したエラーハンドリング

Salesforce では、Apex の実行時に「ガバナ制限 (Governor Limits)」が適用されます。
特に LimitExceptiontry-catch でキャッチできないため、事前対策が重要 です。

1.1. LimitException の代表例

以下のような制限を超えると LimitException が発生し、処理が強制終了します。

ガバナ制限 説明
SOQL 100 クエリ制限 1 トランザクションで SOQL を 100 回以上実行するとエラー
DML 150 操作制限 insert, update, delete などを 150 回以上実行するとエラー
CPU 時間制限 処理に 10 秒以上かかるとエラー
ヒープサイズ制限 メモリ使用量が 6MB (標準) または 12MB (バッチ) を超えるとエラー

1.2. Limits クラスを使った制限の事前チェック

ガバナ制限を回避するために、Limits クラスを使って現在の使用状況を確認できます。

if (Limits.getQueries() >= Limits.getLimitQueries() - 5) {
    System.debug('SOQL クエリ制限に近づいています');
}
if (Limits.getDmlStatements() >= Limits.getLimitDmlStatements() - 10) {
    System.debug('DML 操作制限に近づいています');
}

Limits.getQueries() で現在の SOQL 実行回数を取得し、
Limits.getLimitQueries() で上限(100)を取得できます。


1.3. SOQL forループ を使ってクエリ制限を回避

通常の for ループで SOQL を使うと、100 クエリ制限を超える可能性があります。

NG 例:

for (Account acc : [SELECT Id, Name FROM Account]) {
    Contact con = [SELECT Id FROM Contact WHERE AccountId = :acc.Id LIMIT 1]; // クエリがループごとに実行される
}

この方法だと アカウントが 100 件以上あると SOQL 100 回制限 を超えてエラーになります


OK 例:

Map<Id, Account> accountMap = new Map<Id, Account>([SELECT Id, Name FROM Account]);
List<Contact> contacts = [SELECT Id, AccountId FROM Contact WHERE AccountId IN :accountMap.keySet()];

この方法なら SOQL 実行回数は 2 回に抑えられます


1.4. Database.insert() を使って DML 操作制限を回避

insert をループの中で実行すると、DML 150 回制限を超える可能性 があります。

NG 例:

for (Account acc : accounts) {
    insert acc; // 150 件以上のアカウントを処理するとエラー
}

OK 例:

insert accounts; // 一括 DML で 1 回の操作で済む

2. バッチ処理 (Batch Apex) の例外処理

バッチ処理では、数千~数百万件のレコードを処理することがあるため、
エラーハンドリングの戦略が重要 になります。


2.1. バッチで try-catch を使う

バッチ実行中にエラーが発生すると、そのバッチ内の全レコードがロールバック されます。
これを防ぐには try-catch を使って エラーになったレコードだけをスキップ します。

NG 例:

global void execute(Database.BatchableContext bc, List<Account> scope) {
    insert scope; // 1件でもエラーがあると全件ロールバックされる
}

OK 例:

global void execute(Database.BatchableContext bc, List<Account> scope) {
    List<Account> successList = new List<Account>();
    
    for (Account acc : scope) {
        try {
            insert acc;
            successList.add(acc);
        } catch (DmlException e) {
            System.debug('エラー: ' + e.getMessage());
        }
    }
}

こうすることで、エラーになったレコードだけをスキップし、成功したレコードはそのまま処理 できます。


2.2. Database.insert() でエラーを個別処理

Database.insert() の第二引数に false を指定すると、部分成功が可能 になります。

global void execute(Database.BatchableContext bc, List<Account> scope) {
    Database.SaveResult[] results = Database.insert(scope, false);
    
    for (Database.SaveResult sr : results) {
        if (!sr.isSuccess()) {
            for (Database.Error err : sr.getErrors()) {
                System.debug('エラー: ' + err.getMessage());
            }
        }
    }
}

この方法では、エラーが発生したレコードだけを特定し、他のレコードは正常に処理 されます。


2.3. バッチのエラーを finish() でログに記録

バッチ実行後にエラーログを記録するには finish() メソッドを活用します。

global void finish(Database.BatchableContext bc) {
    Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
    mail.setSubject('バッチ処理完了');
    mail.setPlainTextBody('バッチ処理が完了しました。エラーログを確認してください。');
    mail.setToAddresses(new String[] {'admin@example.com'});
    Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}

このように finish()バッチ完了時にメール通知 することで、エラー発生時にすぐ気付けます。


3. 例外処理のベストプラクティス

  • ガバナ制限を意識する
    • SOQL forループ を避ける
    • Limits クラスを使って事前チェック
    • 一括 DML (insert list) を活用
  • バッチ処理では try-catch を使う
    • 1 件のエラーで全件ロールバックされないようにする
  • バッチのエラーを finish() で記録・通知する
    • エラーログを作成し、管理者に通知

まとめ

今回は、ガバナ制限を考慮したエラーハンドリングバッチ処理のエラーハンドリング について解説しました。

  • SOQL 100 回制限DML 150 回制限事前チェック で回避
  • try-catch を使って バッチ処理でのロールバックを防ぐ
  • Database.insert(scope, false)部分成功を許可
  • finish()エラーログを記録し、通知する

次の Part 6 では、テストクラスでのエラーハンドリングカスタム例外の活用 について解説します!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?