Apex 电子邮件服务、Visualforce、AJAX 与事务限制完全指南
Apex综合指南:电子邮件服务(Messaging.InboundEmailHandler/每日限制=用户许可证×1000最大1M/25MB大小限制/沙箱地址不复制/InboundEmail对象完整属性/创建任务和退订处理两个完整示例/出站邮件5,000外部地址限制)、Visualforce控制器(自定义控制器vs扩展/系统提供类/用户模式执行)、JavaScript Remoting三元素(@RemoteAction static global/public/回调函数/所有方法暴露安全警告)、Apex in AJAX(executeAnonymous/webservice调用/命名空间)、原子事务模型(全部或全无/资金转账示例/付款交易例外)、完整Governor Limits表格(同步vs异步/100SOQL/150DML/6-12MB堆/10-60s CPU/Scheduled适用同步限制/Bulk API取高值/认证托管包独立限制×11跨命名空间/平台级每日异步限制/Cursor限制/Flex Queue)、批量DML+SOQL优化最佳实践、弹性限制Beta(弹性=日限+min(许可限,10M)/OrgLimits监控/节流处理)和Governor Limit邮件警告。
本课程共有 7 个章节
大家好,欢迎来到这章的内容。我先带大家浏览一下我们这一讲要接触的几个重点,它们可以说是Salesforce开发中非常实用的能力。这页PPT上列得比较全,我们一个一个来看,很快你就能知道它们分别是做什么的。 首先是,Apex电子邮件服务,,这个功能能让我们的代码直接处理入站的电子邮件。比如说你给客户发了一个服务邮箱,客户回复之后,Apex可以把邮件的内容、标题,甚至附件都拿到手,然后自动在系统里创建案例或者更新数据,完全不需要人手动去看邮件。这就是我们说的“入站邮件处理”,很酷对吧? 接下来是,Visualforce自定义控制器,。可能你已经用过标准控制器来帮页面显示记录,但有时业务逻辑很复杂,我们就得自己写Apex控制器,控制页面上的数据怎么加载、按钮按下去之后干什么。这会让你的Visualforce页面变得特别灵活。 然后是两个关于异步通信、让页面不刷新就能和后端交互的技术。第一个叫,JavaScript Remoting,,它是一种很方便的调用方式,你可以在JavaScript里直接写一个函数名,就能调用Apex里静态的方法,然后把结果显示在页面上,就像在本地调用一样。第二个是,AJAX工具包中的Apex,,思路类似,也是从客户端用JavaScript去调用Apex,但它的用法是基于一个预先加载的类库,适合更传统的AJAX模式。这两个都用来提升用户体验,不用整页刷新。 接下来,我们要关注数据可靠性的核心概念——,Apex原子事务与保存点、回滚,。在写代码的时候,你可能需要连续更新好几条记录,比如从账户扣钱,再给订单加钱,如果中间一步失败了,前面做的改动必须撤销,否则账就对不齐了。Apex里的“保存点”和“回滚”就是干这个的,你可以设置一个存档点,万一后面代码出异常,就回到这个干净的状态,保证事务要么全做,要么全不做。 最后,也是每个Salesforce开发人员时刻都要注意的:,执行管理器限制和同步Apex作业的弹性限制,。系统给我们的代码设定了各种“围墙”,比如一个请求里能查多少次数据库、能执行多少条语句。这里面还专门细分了类别限制,以及同步作业(就是不走异步队列立即执行的作业)的弹性限制,意思是系统会根据资源忙不忙来动态调整允许的并发量。了解这些限制并学会看log,才能让你的代码在线上跑得又稳又快,避免踩到“极限”被强制终止。 这一页就是一个全景图,接下来我们对每个点都会展开细讲,先有个印象就好。准备好了吗?我们开始第一个模块。
同学们,咱们来看这张幻灯片,讲的是Salesforce里的“电子邮件服务”。简单来说,你可以用它来处理系统收到的每一封邮件,包括邮件正文、标题,还有附件。打个比方,你可以设置一个服务,让它一收到客户邮件,就自动根据邮件里的联系信息,在系统里帮你建一条联系人记录,这样就不用手动输入了。 Salesforce收到邮件后,会把每封入站邮件都变成一个叫做 ,InboundMail, 的对象(它在实际API里叫InboundEmail,不过概念一样)。这个对象就像一个小包裹,里面装着邮件的所有信息。 那怎么让系统处理这个小包裹呢?你需要写一个Apex类,并且让这个类去实现一个接口。Slide上写的是 ,Message.InboundMailDeliverable, ,你开发的时候可能会看到它最常见的叫法是 ,Messaging.InboundEmailHandler,,意思是一样的,都是规定好要去处理入站邮件。 这个接口里会有一个处理方法,方法一执行,系统就会把那个InboundMail对象传给你。拿到这个对象,你就能在代码里轻松取到邮件的具体内容、标题,还有附件啦。这样一来,所有入站邮件你都可以按自己的想法去自动化处理了。
同学,今天我们来讲两个实际使用InboundMail的例子,也就是当有人发邮件到你的Salesforce邮箱时,系统如何自动处理这些邮件。我们通过代码实现一些有用的操作。 先看第一个例子:给联系人创建任务。 想象一下,你收到一封邮件,想自动为发件人创建一个任务,把邮件内容作为任务描述。怎么做呢? 我们写个Apex类,实现`Messaging.InboundEmailHandler`接口。这个接口要求我们实现一个`handleInboundEmail`方法,它接收邮件对象,然后返回一个`Messaging.InboundEmailResult`。 在这个方法里,我们先用`email.fromAddress`得到发件人地址,然后去查询联系人,看哪个联系人的邮箱地址跟发件人一致。如果找到了,就创建一个新任务,任务的`Subject`可以设为邮件的主题,`Description`就用邮件的纯文本正文。最后关联到这个联系人,并把任务插入数据库。 代码末尾,我们返回一个成功的结果,告诉Salesforce邮件处理成功了。这样,每次收到邮件,就会自动给对应的联系人创建任务,非常方便。 第二个例子更实用:处理取消订阅。 很多公司需要让用户通过邮件退订。比如,用户在主题里写“取消订阅”。我们可以在代码里检查邮件主题是否包含这几个字。如果包含,就去查找所有联系人里邮箱匹配发件人的,以及所有潜在客户里邮箱匹配的,然后把这些人的`HasOptedOutOfEmail`字段设为`true`。这就代表他们选择退出邮件营销了。 同样,我们返回一个成功结果。注意,这里可能匹配到多个联系人或潜在客户,所以我们用列表更新它们。 这样,任何发来的取消订阅邮件都能自动生效,省去人工操作。 这两个例子都实现了同一个接口,返回`InboundEmailResult`,结构很简单,只是一个成功标志。实际部署时,你还需要在Salesforce设置里配好邮件服务,把邮件转发给这个Apex类处理。 这就是通过InboundMail自动处理邮件的两种典型用法。记住,关键点就是实现`handleInboundEmail`方法,从邮件对象里提取信息,然后做业务操作。你可以发挥想象,做更多自动化,比如自动转发、创建个案等等。 好了,这节课就到这里,希望你对InboundMail有了更深的理解。
同学们,我们来看这张幻灯片讲的内容。它说的是,在Salesforce里,我们可以用Apex来写一些自定义的代码,然后把这些代码用到Visualforce页面上去。 那怎么用呢?主要有两种方式。第一种,叫做自定义控制器或者控制器扩展。简单说,就是你可以自己写一个Apex类,来控制Visualforce页面背后的逻辑,比如从数据库查数据、处理点击按钮这些事。 第二种方式,就是我们今天要重点聊的:JavaScript Remoting。这个功能很实用,它可以让你在Visualforce页面上,直接用JavaScript来调用后台Apex的方法,不用刷新整个页面。这样用户体验会更好,因为响应很快。 那怎么在Apex代码里让一个方法能被JavaScript远程调用呢?你需要在这个方法前面加上一个注解,叫做 @RemoteAction。注意,方法有几个要求:必须是静态的——也就是static,而且访问级别必须是global或者public。不能是private的。 在JavaScript这边怎么调用呢?调用的格式是:控制器名.方法名,然后括号里传参数。参数有几个呢?第一部分是你这个方法本身需要的参数;第二部分是一个回调函数,用来处理返回的结果;第三部分是一个可选的配置对象。举个例子,大概是这个样子:MyController.getAccount(accountId, function(result, event){ ... }, {escape: true})。 还有一点很重要,就是安全问题。一旦你把一个Apex类设置为Visualforce页面的控制器,那这个类里面所有标记了@RemoteAction的方法,都会从页面上暴露出去,JavaScript都可以调用。所以,添加控制器的时候要谨慎,确保只开放必要的方法,别一不小心把不该暴露的也暴露了。 好,这就是这张幻灯片的核心内容。大家有什么问题吗?
好,咱们来看这页的内容,它讲的是Apex里的事务和保存点,这两个概念对保证数据不出错特别重要。 首先,不管你是通过AJAX Toolkit调用Apex——也就是用匿名块或者公开的Web Service方法——这些调用都会跑在一个Apex事务里。什么叫事务呢?简单说,Apex会把一次执行里所有的数据库操作(比如插入、更新、删除)打包成一个原子单元。要么全部成功提交,要么只要中间有一步失败,前面已经做过的修改也会全部回滚,绝不会出现“一半成功一半失败”的情况,这就确保了数据完整性。 那么事务的边界在哪儿呢?其实就是一次完整的执行单元,比如一个触发器、一个类的方法、一段匿名块、一个Visualforce页,或者一个Web Service。在这些边界里面跑的所有代码,都共享同一个事务。 但有时候,你不想整个事务都回滚,只想撤销到中间的某个点。这时候就可以用“保存点”。你可以在代码里打个标记,之后如果觉得某一步做错了,就可以回滚到那个标记,只丢弃这之后做的DML变更。 不过用保存点
同学们,今天我们来讲一个非常重要的概念,叫做州长执行限制,也就是Governor Limits。为什么叫州长?其实就是像一个严格的州长,时刻盯着你的程序,确保你不会一个人用掉整个平台的资源。Salesforce是一个多租户平台,意思是所有客户共享同一套基础设施,所以必须保证每家公司、每个事务都公平地占用资源,不能让一个写得不好的代码把其他人都拖慢。 那么,在一个事务里,比如一次按钮点击、一个Web服务调用,Apex会受到哪些限制呢?我们分几类来看。 首先是关于数据库查询的。你最多只能执行100个SOQL查询,前提是同步操作。那同步是什么意思呢?就是用户在前台点一个按钮,系统立刻响应,页面还在等着结果。这时候SOQL查询数不能超过100个。另外,所有查询返回的总行数不能超过5万行。这5万行不是说一个查询最多5万,而是这一个事务里,所有查询加起来返回的行数,最多5万。 然后是DML操作,也就是增删改查里除了查之外的操作。我们叫它DML语句,限制是150个。总记录行数不能超过1万行。什么意思呢?你一次插入100条记录,就算一次DML,100条都算在1万行的限额里。如果你用了很多次DML,不仅要看次数,还要累计行数。 接下来是执行时间的限制。同步事务里,CPU时间不能超过10秒。CPU时间不是墙上挂的钟表时间,而是服务器真正花在运行你代码上的时间。如果数据库查询慢,可能不占你的CPU时间,但代码循环、运算这些就会消耗。还有堆内存,也就是你的代码里声明的变量、集合这些占用的内存,同步事务最多6 MB,异步能到12 MB。 说到异步,也就是后台运行的操作,比如未来方法、批处理这些,限制会宽松一些。同步操作刚才说了100个SOQL、10秒CPU、6 MB堆;异步操作允许200个SOQL,CPU时间60秒,堆内存12 MB。所以,尽量把重活放到后台去做,这也是我们设计的原则。 还有一个在任何一个事务里都有限制的是对外部的调用。你的代码可以调用外部的Web服务,或者通过HTTP请求发出去,最多100次调用,而且这100次调用的累积超时时间是120秒。也就是所有调用加起来等待的时间不能超过120秒,防止你一直卡住。 除了每个事务的限制,还有每天的总限制。一个组织每天最多能执行25万次批处理里的异步方法,或者按照用户许可证数量乘以200来计算,两者取高的那个。这个主要针对频繁运行的异步作业。 另外,如果你从AppExchange装了一些认证的托管包,这些包里的代码也有自己的单独限制,和你的主限制是分开的。这样就不会因为你写了自己的代码,就挤占了托管包应用的资源,反过来也一样。所以平台考虑得很周全,防止互相干扰。 总结一下,每一次事务就像一次考试,州长就是监考老师,他给你规定了答题时间、纸张数量、翻书次数等等。你要在限制内完成任务,如果超过,系统就会毫不留情地抛出异常。这听起来很严格,但正是这种设计,让Salesforce这个巨大的共享平台始终保持稳定、安全、高效。所以,写代码时,心中一定要有这些限制,养成好的习惯,比如少用循环里的SOQL,及时释放内存,能用异步就异步。这样你的应用才能跑得又快又稳。 好,关于州长执行限制,我们就先讲到这里。有什么问题,大家可以随时提。
好,同学们,接下来我们聊一聊在 Salesforce 开发中,如何避开调控器限制,写出高效的 Apex 代码。这就像给你的程序戴上安全帽,避免它因为超载而崩溃。 首先记住一个大原则:,永远不要一条一条地处理数据,要一次处理一批。, 比如说 DML 操作,如果你在一个循环里每次插入一条记录,每一条都会消耗一次 DML 限制,几百条下来很容易碰到墙。正确的做法是,先把所有要处理的数据放进一个列表,循环结束后再用一条 DML 语句统一处理。这种“收集成列表,一次操作”的方式,能成百上千倍地降低限额的消耗。 同样,SOQL 查询也不能放在循环里。如果你的代码在 for 循环中每次都查询数据库,调控器会很快把你拦下。这里的技巧是:先用一个集合(比如 Set)把需要查的 ID 或字段值收集起来,然后用带 IN 子句的 SOQL 一次性取出所有相关记录。Set 能自动去重,效率很高。 那么,如果查询返回的数据量可能非常大,我们该怎么做呢?Apex 提供了一个专门的安全模式:,SOQL for 循环,。写法是 `for (MyObject obj : [SELECT ...]) {}`。这种方式下,Apex 会分批从数据库获取记录,而不是一次性把所有结果加载到内存里。这样既避免了堆空间用尽,也撑住了调控器的查询行数限制。对于几十万、上百万条记录的大查询,这是推荐的官方模式,请一定用起来。 接下来,为了让查询跑得又快又省限额,我们还要学会 ,“选择性查询”,。说白了,就是要尽量用索引字段来过滤。比如有索引的字段有主键、外键、唯一字段,或者在后台被标记为索引的。在你的 WHERE 子句里优先用这些字段,能极大减少数据库扫描的范围,查询更高效,限额也消耗得更少。 刚提到了限制,还有一个贴心的新功能要告诉你。Salesforce 推出了 ,弹性限制(Beta),。有些批量作业啊,比如 Scheduled Jobs,每日的异步 Apex 执行数量有限额。如果你们的业务量突然增大,超过了默认的 250,000 次执行,弹性限制可以让你以受控的速率继续处理,不会粗暴地把作业杀掉了。它就像给高速路开了个缓行区,虽然慢一点,但还能走。 最后,我们有义务时刻监视自己的代码是否快要踩线。你可以在 Apex 设置里打开 ,控管者限制电子邮件警告,。当你的代码消耗掉任何一个限制的 50% 时,系统就会给你发邮件提醒,让你有机会在发生致命异常前赶紧优化。这就像车子仪表盘上的油量警告灯,提前提醒,避免半路抛锚。 好了,总结一下这节课的重点: - 把 DML 搜集起来批量做。 - 绝不在循环里跑 SOQL,用 Set 配合 IN 子句。 - 查询海量数据用 SOQL for 循环。 - 利用索引字段让查询具有选择性。 - 了解弹性限制,给紧急作业一条活路。 - 打开 50% 警告邮件,保持警惕。 把这些习惯内化,你的 Apex 代码就能在 Salesforce 的“交通规则”里安全顺畅地跑起来。下次课我们继续深入看具体的优化案例,谢谢大家。