Apex - 调节器限制
Governor 执行限制可确保 Force.com 多租户平台上资源的高效利用。 这是 Salesforce.com 为高效处理而指定的代码执行限制。
什么是调控器限制?
众所周知,Apex 在多租户环境中运行,即单个资源由所有客户和组织共享。 因此,有必要确保没有人垄断资源,因此 Salesforce.com 创建了一组管理和限制代码执行的限制。 每当超过任何调节器限制时,它都会抛出错误并停止程序的执行。
从开发人员的角度来看,确保我们的代码应该可扩展并且不应该达到限制非常重要。
所有这些限制均适用于每笔交易。 单个触发器执行就是一个事务。
正如我们所见,触发器设计模式有助于避免极限错误。 我们现在将看到其他重要的限制。
避免 SOQL 查询限制
每个事务只能发出 100 个查询,也就是说,当您的代码发出超过 100 个 SOQL 查询时,它将抛出错误。
示例
此示例显示如何达到 SOQL 查询限制 −
以下触发器迭代客户列表,并使用字符串"Ok to Pay"更新子记录的(账单)描述。
// Helper 类:下面的代码需要检查。
public class CustomerTriggerHelper {
public static void isAfterUpdateCall(Trigger.new) {
createInvoiceRecords(trigger.new);//Method call
updateCustomerDescription(trigger.new);
}
// 创建账单记录的方法
public static void createInvoiceRecords (List<apex_customer__c> customerList) {
for (APEX_Customer__c objCustomer: customerList) {
if (objCustomer.APEX_Customer_Status__c == 'Active' &&
trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
// 检查旧值和新值的条件
APEX_Invoice__c objInvoice = new APEX_Invoice__c();
objInvoice.APEX_Status__c = 'Pending';
InvoiceList.add(objInvoice);
}
}
insert InvoiceList; // DML to insert the Invoice List in SFDC
}
// 更新账单记录的方法
public static updateCustomerDescription (List<apex_customer__c> customerList) {
for (APEX_Customer__c objCust: customerList) {
List<apex_customer__c> invList = [SELECT Id, Name,
APEX_Description__c FROM APEX_Invoice__c WHERE APEX_Customer__c = :objCust.id];
// 此查询将针对客户列表拥有的记录数以及将要触发的记录数触发
// 当记录超过 100 条时达到调控器限制
for (APEX_Invoice__c objInv: invList) {
objInv.APEX_Description__c = 'OK To Pay';
update objInv;
// Update invoice, this will also hit the governor limit for DML if large
// number(150) of records are there
}
}
}
}
当调用"updateCustomerDescription"方法并且客户记录数量超过 100 时,就会达到 SOQL 限制。 为了避免这种情况,切勿在 For 循环中编写 SOQL 查询。 在本例中,SOQL 查询已写入 For 循环中。
以下示例将展示如何避免 DML 以及 SOQL 限制。 我们使用嵌套关系查询来获取账单记录,并使用上下文变量 trigger.newMap 来获取 id 和客户记录的映射。
// SOQL-编写查询并避免限制异常的好方法
// 辅助类
public class CustomerTriggerHelper {
public static void isAfterUpdateCall(Trigger.new) {
createInvoiceRecords(trigger.new); //Method call
updateCustomerDescription(trigger.new, trigger.newMap);
}
// 创建账单记录的方法
public static void createInvoiceRecords (List<apex_customer__c> customerList) {
for (APEX_Customer__c objCustomer: customerList) {
if (objCustomer.APEX_Customer_Status__c == 'Active' &&
trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
// 检查旧值和新值的条件
APEX_Invoice__c objInvoice = new APEX_Invoice__c();
objInvoice.APEX_Status__c = 'Pending';
InvoiceList.add(objInvoice);
}
}
insert InvoiceList; // 在 SFDC 中插入账单列表的 DML
}
// 更新账单记录的方法
public static updateCustomerDescription (List<apex_customer__c>
customerList, Map<id, apex_customer__c> newMapVariable) {
List<apex_customer__c> customerListWithInvoice = [SELECT id,
Name,(SELECT Id, Name, APEX_Description__c FROM APEX_Invoice__r) FROM
APEX_Customer__c WHERE Id IN :newMapVariable.keySet()];
//仅查询一次并获取所有记录
List<apex_invoice__c> invoiceToUpdate = new
List<apex_invoice__c>();
for (APEX_Customer__c objCust: customerList) {
for (APEX_Invoice__c objInv: invList) {
objInv.APEX_Description__c = 'OK To Pay';
invoiceToUpdate.add(objInv);
// 将修改后的记录添加到List中
}
}
update invoiceToUpdate;
}
}
DML 批量调用
此示例显示批量触发器以及触发器助手类模式。 您必须先保存辅助类,然后保存触发器。
注意 − 将以下代码粘贴到我们之前创建的"CustomerTriggerHelper"类中。
// 辅助类
public class CustomerTriggerHelper {
public static void isAfterUpdateCall(List<apex_customer__c> customerList,
Map<id, apex_customer__c> mapIdToCustomers, Map<id, apex_customer__c>
mapOldItToCustomers) {
createInvoiceRecords(customerList, mapOldItToCustomers); //Method call
updateCustomerDescription(customerList,mapIdToCustomers,
mapOldItToCustomers);
}
// 创建账单记录的方法
public static void createInvoiceRecords (List<apex_customer__c>
customerList, Map<id, apex_customer__c> mapOldItToCustomers) {
List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>();
List<apex_customer__c> customerToInvoice = [SELECT id, Name FROM
APEX_Customer__c LIMIT 1];
for (APEX_Customer__c objCustomer: customerList) {
if (objCustomer.APEX_Customer_Status__c == 'Active' &&
mapOldItToCustomers.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
//检查旧值和新值的条件
APEX_Invoice__c objInvoice = new APEX_Invoice__c();
objInvoice.APEX_Status__c = 'Pending';
objInvoice.APEX_Customer__c = objCustomer.id;
InvoiceList.add(objInvoice);
}
}
system.debug('InvoiceList&&&'+InvoiceList);
insert InvoiceList;
// 用于在 SFDC 中插入账单列表的 DML。 这也遵循批量模式
}
// 更新账单记录的方法
public static void updateCustomerDescription (List<apex_customer__c>
customerList, Map<id, apex_customer__c> newMapVariable, Map<id,
apex_customer__c> oldCustomerMap) {
List<apex_customer__c> customerListWithInvoice = [SELECT id,
Name,(SELECT Id, Name, APEX_Description__c FROM Invoices__r) FROM
APEX_Customer__c WHERE Id IN :newMapVariable.keySet()];
// 仅查询一次并获取所有记录
List<apex_invoice__c> invoiceToUpdate = new List<apex_invoice__c>();
List<apex_invoice__c> invoiceFetched = new List<apex_invoice__c>();
invoiceFetched = customerListWithInvoice[0].Invoices__r;
system.debug('invoiceFetched'+invoiceFetched);
system.debug('customerListWithInvoice****'+customerListWithInvoice);
for (APEX_Customer__c objCust: customerList) {
system.debug('objCust.Invoices__r'+objCust.Invoices__r);
if (objCust.APEX_Active__c == true &&
oldCustomerMap.get(objCust.id).APEX_Active__c == false) {
for (APEX_Invoice__c objInv: invoiceFetched) {
system.debug('I am in For Loop'+objInv);
objInv.APEX_Description__c = 'OK To Pay';
invoiceToUpdate.add(objInv);
// Add the modified records to List
}
}
}
system.debug('Value of List ***'+invoiceToUpdate);
update invoiceToUpdate;
// 该语句是Bulk DML,它在List上执行DML并避免
// DML 调控器限制
}
}
// 此类的触发代码:将此代码粘贴到"Customer_After_Insert"中
// 在客户对象上触发
trigger Customer_After_Insert on APEX_Customer__c (after update) {
CustomerTriggerHelper.isAfterUpdateCall(Trigger.new, trigger.newMap,
trigger.oldMap);
// Trigger调用辅助类,并且Trigger中没有任何代码
}
其他 Salesforce 调控器限制
下表列出了重要的调节器限制。
| 描述 | 调控器 |
|---|---|
| 总堆大小 | 6 MB/12 MB |
| 发出的 DML 语句总数 | 150 |
| 单个 SOSL 查询检索的记录总数 | 2000 |
| 发出的 SOSL 查询总数 | 20 |
| Database.getQueryLocator 检索到的记录总数 | 10000 |
| SOQL 查询检索的记录总数 | 50000 |

