需求:
从Java或者C#(包换任何传统编程语言)转行到Salesforce开发的程序员的习惯性思维需要打破,
云计算机(简单点说,就是租赁),那么服务器的性能最大化,负荷最优就是我们需要考虑的问题。为了性能和负荷的最优,所以才会有Salesforce比较独特的【Apex Governor Limits】这个限制。
在这里我就来讲一下关于Apex代码的编写思维。
最佳实践1。批量处理数据
如果我们在Apex代码中创建数据,那么肯定是【一次提交多条数据】比【多次提交一条数据】,性能更优化。
比如,我们有下面的示例代码
trigger accountTestTrggr on Account (before insert, before update) {
//这里的代码,每次只处理一条数据,从Trigger.new中取出第一条数据。
//但是如果我们使用DataLoader或者另外的方式导入多条Account数据的时候,
//除了第一条数据以外的数据,就不可能被执行到。
//所以这个示例代码,就是有问题的代码。
Account acct = Trigger.new[0];
List<Contact> contacts = [select id, salutation, firstname, lastname, email
from Contact where accountId = :acct.Id];
}
下面的代码,就是正常的Trigger的写法。
※当然了,正常情况下我们不会直接在Trigger里面直接写逻辑代码,那会非常不容易维护。
我们会通过TriggerHandler的方法来执行具体的逻辑代码。
大家可以参考下面的文章
【探索Apex开发之】 使用TriggerHandler,让你的代码逻辑更清晰
http://salesforcegogogo.com/BlogsItem.aspx?id=83
trigger accountTestTrggr on Account (before insert, before update) {
List<String> accountNames = new List<String>{};
//因为Trigger.new是一个数据的集合,最多会有200条数据,
//下面的写法就是从这个集合里面循环取得数据
for(Account a: Trigger.new){
//下面更新Description的值
a.Description = a.Name + ':' + a.BillingState
}
}
最佳实践2。避免在循环内执行SOQL查询,或者DML操作(数据的增删改操作)
下面的示例代码,新人是最容易犯的问题。
在For循环中更新数据
(我以前有时候也这么写,但我会明确写下备注,List变量最多只有1条数据。)
而且这样的写法,会被别人视为不专业。所以千万不能在For循环进行DML操作。
下面是关于SOQL查询和DML操作的数量限制,仅供参考。
Description | Synchronous Limit | Asynchronous Limit |
---|---|---|
Total number of SOQL queries issued1 | 100 | 200 |
Total number of DML statements issued2 | 150 | 150 |
下面是示例代码(错误的写法)
trigger accountTestTrggr on Account (before insert, before update) {
//下面的示例代码,遍历一个List类型的变量(Trigger.new)
for(Account a: Trigger.new) {
//THIS FOLLOWING QUERY IS INEFFICIENT AND DOESN'T SCALE
//Since the SOQL Query for related Contacts is within the FOR loop, if this trigger is initiated
//with more than 100 records, the trigger will exceed the trigger governor limit
//of maximum 100 SOQL Queries.
//下面的查询代码,是非常没有效率, 每次仅仅查询1条数据。
//由于查询代码在For循环中,所以如果Trigger.new的数据超过100条,
//那么这个accountTestTrggr就会马上出异常,而导致所有数据操作回滚。
List<Contact> contacts = [select id, salutation, firstname, lastname, email
from Contact where accountId = :a.Id];
for(Contact c: contacts) {
System.debug('Contact Id[' + c.Id + '], FirstName[' + c.firstname + '],
LastName[' + c.lastname +']');
c.Description=c.salutation + ' ' + c.firstName + ' ' + c.lastname;
//下面的更新代码,也是类似,因为在For循环中
//每次更新一次数据,可用的DML操作数量就减1,那就是说,如果Trigger.new的数据超过150条,
//那么这个accountTestTrggr就会马上出异常,而导致所有数据操作回滚。
//但是大家知道,在DML操作异常之前,SOQL的执行数量就已经达到极限值了。所以根本就不可能执行到150次DML操作
update c;
}
}
}
讲解了错误的写法之后,我们再来看一下正常的写法
trigger accountTestTrggr on Account (before insert, before update) {
//首先,在accountTestTrggr的最前面,把所有需要更新的数据先取出来,放到一个List变量中。
//大家看到了,Where条件里面,我们指定了ID IN 这个条件。
//IN 这个条件的值是,Trigger.newMap.keySet(),这个KeySet方法能够把Map变量里面所有的ID给取出来
//所以在这里,我们只执行一次SOQL查询。那么执行SOQL查询后,
//我们还有99次 SOQL查询可以使用。
//不当家不知柴米贵,就是类似的道理。
List<Account> accountsWithContacts = [select id, name, (select id, salutation, description,
firstname, lastname, email from Contacts)
from Account where Id IN :Trigger.newMap.keySet()];
List<Contact> contactsToUpdate = new List<Contact>{};
//下面的代码,在For循环中,修改每一条数据的值,最后把修改完的值再放入到contactsToUpdate这个变量里面。
for(Account a: accountsWithContacts){
// Use the child relationships dot syntax to access the related Contacts
for(Contact c: a.Contacts){
System.debug('Contact Id[' + c.Id + '], FirstName[' + c.firstname + '], LastName[' + c.lastname +']');
c.Description=c.salutation + ' ' + c.firstName + ' ' + c.lastname;
contactsToUpdate.add(c);
}
}
//Now outside the FOR Loop, perform a single Update DML statement.
//最后,所以我们来更新修改过的Contact数据。
//因为我们这个修改数据的操作,是在Loop循环外的,所以只占用一次DML操作,那么在accountTestTrggr执行完,
//我们只占用了一次SOQL执行数量,和一次DML执行数量,那是相当的节省。对吧
update contactsToUpdate;
}
最佳实践3。查询大量数据
下面还是Apex Governor Limits里面的限制项。
一次处理,我们最多只能从Salesforce上查询到5万条数据。
如果超过这个数据量,那么程序就直接抛出异常来结束程序运行。
Description | Synchronous Limit | Asynchronous Limit |
---|---|---|
Total number of records retrieved by SOQL queries | 50,000 | 50,000 |
TODO
所有的参考文章
https://developer.salesforce.com/ja/wiki/apex_code_best_practices
https://www.salesforceben.com/12-salesforce-apex-best-practices/
https://sfdclesson.com/2022/06/18/10-best-practices-for-apex-code/