You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apex触发器单条正常批量触发超Governor Limits问题排查与优化

问题:Apex触发器批量处理失败的原因与重构方案

我是一名Salesforce开发者,正在开发基于关联Account数据更新Contact记录的Apex触发器。该触发器在UI中逐条创建或更新记录时表现正常,但批量处理(如Data Loader或API)时失败。

触发器简化代码

trigger ContactTrigger on Contact (after insert, after update) {
    for (Contact c : Trigger.new) {
        if (c.AccountId == null) {
            continue;
        }

        Account acc = [
            SELECT Id, Industry
            FROM Account
            WHERE Id = :c.AccountId
        ];

        if (acc.Industry == 'IT') {
            c.Description = 'IT Account';
            update c;
        }
    }
}

批量操作时的错误信息

  • System.LimitException: Too many SOQL queries: 101
  • System.LimitException: Too many DML statements: 151

已尝试的方案

  • 添加空值检查与循环内条件逻辑
  • 限制触发器仅在所需上下文运行
  • 确认无Flows或Process Builder引发的递归

但批量操作问题仍持续存在。


为什么仅批量处理时失败?

Salesforce有严格的Governor Limits(运行时限制):单事务内最多允许100次SOQL查询、150次DML操作。

  • 单条记录操作时,触发器仅执行1次SOQL和1次DML,远低于限制,所以正常运行。
  • 批量操作时,原代码在循环中对每条Contact单独执行SOQL查询和DML更新。比如批量处理100条Contact,就会触发100次SOQL和100次DML;若批量数超过100,直接触发SOQL次数超限;DML次数超过150也会触发报错。

重构方案(符合批量处理规范)

遵循Salesforce Apex最佳实践:批量查询、批量更新,绝对避免在循环内执行SOQL和DML。

步骤1:创建触发器Handler类(分离逻辑,便于维护)

public class ContactTriggerHandler {
    // 静态变量防止递归更新
    private static Boolean isRecursive = false;

    public static void handleAfterInsertUpdate(List<Contact> newContacts) {
        if (isRecursive) return;
        isRecursive = true;

        // 1. 收集所有非空的AccountId并去重
        Set<Id> accountIds = new Set<Id>();
        for (Contact c : newContacts) {
            if (c.AccountId != null) {
                accountIds.add(c.AccountId);
            }
        }

        // 2. 批量查询关联的Account数据
        Map<Id, Account> accountMap = new Map<Id, Account>([
            SELECT Id, Industry 
            FROM Account 
            WHERE Id IN :accountIds
        ]);

        // 3. 收集需要更新的Contact记录
        List<Contact> contactsToUpdate = new List<Contact>();
        for (Contact c : newContacts) {
            Account acc = accountMap.get(c.AccountId);
            if (acc != null && acc.Industry == 'IT') {
                Contact updatedContact = new Contact(
                    Id = c.Id,
                    Description = 'IT Account'
                );
                contactsToUpdate.add(updatedContact);
            }
        }

        // 4. 批量执行DML更新
        if (!contactsToUpdate.isEmpty()) {
            update contactsToUpdate;
        }

        isRecursive = false;
    }
}

步骤2:简化触发器,仅调用Handler

trigger ContactTrigger on Contact (after insert, after update) {
    ContactTriggerHandler.handleAfterInsertUpdate(Trigger.new);
}

重构后的优势

  • 无论批量多少条记录,仅执行1次SOQL查询和1次DML更新,完全符合Governor Limits要求。
  • 用Set<Id>去重AccountId,避免查询重复的Account数据。
  • 静态变量isRecursive防止触发器递归调用(比如更新Contact后再次触发update事件)。
  • 分离触发器与业务逻辑,代码更易维护和测试。

内容的提问来源于stack exchange,提问作者bselavina

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.11 19:12:32