DEX455

Apex 中的数据操作:sObject 与 DML 完全指南

课程介绍

Apex 数据操作完全指南:深入详解 sObject 类型系统(通用/特定类型转换与字段设置状态)、DML 操作(单条vs批量/批量推荐模式)、DML 语句 vs Database 类方法(部分成功处理)、原子事务、全部 DML 操作(Insert/Update/Upsert/Merge/Delete/Undelete/ConvertLead)含关联记录与外部 ID、异常处理与结果对象、DMLOptions(字段截断/分配规则/重复规则/邮件/语言/部分成功)、保存点与事务回滚(releaseSavepoint与callout)、混合DML(setup对象/@future解决)、记录锁定(FOR UPDATE/10秒超时/死锁避免)、以及批量DML异常重试机制和数据约束。

课程章节

本课程共有 15 个章节

  • 1

    Working with Data in Apex

    第 163 页

    同学你好,今天我们来聊聊在Salesforce的Apex里怎么跟数据打交道。你可能看到课程大纲里提到了“sBody”,其实它是“sObject”的笔误,我们正式叫它sObject,这才是Salesforce里保存数据对象的主要类型。 你可以把sObject想象成数据库里的表格,或者说每一行记录。我们要往平台里记录信息、修改信息,用的就是数据操作语言,英文叫DML——像插入、更新、删除这些都归它管。而想查找数据,就要用查询语言,也就是SOQL。 这章内容挺丰富的,我们会先讲怎么定义sObject,以及怎么访问它的各个字段。然后重点练习DML的各种操作:插入新记录、更新已有记录、upsert(就是有就更新,没有就插入)、删除、甚至把删掉的数据再恢复回来,还有合并记录,以及把潜在客户转成正式客户的那个convertLead操作。 之后我们会比较两种执行DML的方式——直接写DML语句,或者用Database类的方法,了解什么时候该用哪种。学完操作了,自然要会处理出错的情况,所以会讲到异常处理。还有事务控制和保存点,让你可以像打游戏存盘一样,出错时回滚数据。另外,Database类的方法还能让你做更精细的DML操作,比如允许部分成功。最后还会介绍用FOR UPDATE给记录上锁,防止别人同时修改。 这样把一张Slide的内容讲明白,是不是轻松很多?后面我们会一节节展开,你就能得心应手地操作Salesforce数据了。

    查看详情
  • 2

    Working with sObjects — Types & Access

    第 164 页

    同学们,今天我们来聊聊 Apex 里一个非常基础,但特别重要的概念——,sObject 变量,。 你可以把 sObject 理解成 Salesforce 里的一条数据记录,比如一个客户、一个商机,或者一个自定义对象的一行信息。在 Apex 代码中,我们声明 sObject 变量的时候,必须使用这个对象的 ,SOAP API 名称,。比如标准账户的 API 名称是 `Account`,那我们就写 `Account acc = new Account();`。 Apex 还提供了一个很灵活的写法——通用的 sObject 类型。也就是说,我们可以写 `sObject obj = new Account();`,这样这个变量就能代表任意类型的记录。当我们希望写一段能处理不同对象的通用代码时,这个特性就非常有用。 在新建 sObject 实例的时候,我们还可以直接在括号里用,逗号分隔的“字段名=值”,来设置初始字段值。比如这样: ```apex Account acc = new Account(Name='张三', Phone='13800138000'); ``` 一眼就能看明白,一条新账户记录的名字和电话就有了。 最后要特别提一下,,自定义标签不是标准的 sObject,。也就是说,你不能去 `new` 一个自定义标签的实例来取值。访问自定义标签的值,只能用系统类 `System.Label.标签名` 的方式。比如一个标签叫 `WelcomeMessage`,代码里就得写成 `System.Label.WelcomeMessage`。 简单总结一下:sObject 就是记录在代码里的化身,声明用 API 名称,可以通用,可以初始化,但自定义标签得用专门的访问方式。好,这块内容就讲到这里,大家有问题随时提。

    查看详情
  • 3

    Accessing sObject Fields & Validation

    第 165 页

    同学们,今天我们来聊聊Apex里怎么操作sObject的字段,其实跟咱们熟悉的Java很像。 首先你可以用简单的点符号来读取或者修改字段。比如有一个联系人对象 con,你想拿到它的名字,就直接 con.FirstName;要修改它,就 con.LastName = '张' ,简单明了。 但是要注意,系统自动生成的字段,你是改不了的。比如创建日期 CreatedDate 或者记录ID,这些由Salesforce自己维护,你只能读,不能写。 接下来,如果你用的是通用的 SObject 类型,而不是具体像 Account、Contact 那种明确的对象,使用上就有点限制。通过点符号,你只能直接拿到 Id 字段。因为通用类型不知道你到底有哪些字段,所以如果要访问 Id 以外的字段,就得用 put() 和 get() 方法。像这样用 get 读取:con.get('FirstName') ,用 put 设置:con.put('LastName', '李') 。这个是针对动态或通用对象的用法。 还有一个很重要的概念:sObject 的字段可以处于“未设置”状态。它跟空值或空白字符串是不一样的。未设置的意思是从来没有赋过值,而空字符串是明确赋予了一个空值,null 也是明确给了空。虽然很多时候它们表现得相似,但在某些场景下,比如判断字段是否在查询中返回,或者进行更新操作时,行为会不同。所以你心里要有这个区别。 最后,平台还有个非常贴心的保护机制。当你的 Apex 代码被解析和验证时,系统会真实地去检查你引用的 sObject 和字段名称是不是存在。如果对象名或字段名写错了,部署或保存的时候就会报错。而且,如果你试图修改代码后去删除一个已经在代码里用到的自定义字段,平台会阻止你,防止你的代码崩溃。这就帮我们提前规避了很多低级错误。 好,这就是对sObject字段访问的要点,咱们在实际写代码的时候可以马上用起来。

    查看详情
  • 4

    Data Manipulation Language (DML)

    第 166 页

    同学们,现在我们翻开新的一章,来聊聊数据操作语言。在讲义上大家可能会看到一个缩写叫TLR,其实这是个小小的笔误,正确的叫法是DML,也就是Data Manipulation Language,数据操纵语言。咱们待会儿提起它,都统一叫DML。 那DML到底是干什么用的呢?简单说,它就是Apex里专门用来“写”数据库的一套工具。有了它,你就能在Salesforce里做四件事:插入全新的记录、更新已有的记录、删除不需要的记录,甚至还能把不小心删掉的记录从回收站里恢复回来。是不是很实用? 而且,DML操作特别灵活,你既可以只针对一条记录动手,也可以一次性批量处理几百条记录,比如一下子更新好多联系人的地址。这比你一条一条慢慢改要高效得多。 大家要记住一个关键的区别:我们之前学的SOQL,它的工作是“读”,是帮我们查询并把数据找出来;而DML的工作是“写”,负责添加或改动数据。一个查,一个改,分工很明确。 好,搞清楚了DML是什么,接下来我们就一起来看看,在实际代码里,这些插入、更新、删除和恢复的语句到底该怎么写。

    查看详情
  • 5

    How DML Works — Bulk vs. Single

    第 167 页

    同学们,我们这节课来看看 Apex 里关于 TLR 操作的一些重要规则。什么?你可能还不清楚 TLR 具体指什么,没关系,你可以先把它理解为对 sObject——也就是我们那些标准或自定义对象——做的数据操作,比如新增、修改、删除这类动作。官方文档有时会直接用 TLR 这个缩写,我们就跟着这么叫。 那重点来了,,你可以一次只对一个 sObject 执行 TLR 操作,也可以一次对一组 sObject,也就是一个列表,批量执行,。哪种方式更好呢?答案很明确:推荐批量操作。为什么?因为 Salesforce 对每个 Apex 事务有严格的限制。其中一个限制就是,,每个事务里最多只能有 150 个 TLR 声明,。如果你在循环里逐个对单个记录做操作,每一个都算一次声明,次数很快就爆了。但如果你把一堆记录放进列表,对列表执行一次 TLR 操作,无论列表里有 10 条还是 200 条记录,,都只算一次声明,,这样就能大大降低碰到 150 这个限制的风险。 除了声明次数,还有,另一个限制:单个事务里,TLR 操作能处理的记录总数不能超过 10,000 行,。所以就算你用批量方式省下了声明次数,也要留意总行数别超。 最后还要记住,,大多数 TLR 操作是在当前用户的上下文中执行的,。什么意思呢?就是说,操作时会检查当前用户的权限、共享规则。如果用户没有某个对象的编辑权限,那批操作里的相关记录就会失败;共享规则也类似,只会处理用户有权看到的记录。 简单总结一下:用列表批量执行,一次操作顶多条,不仅高效,还能巧妙避开 150 次声明的坑;同时留神 10,000 行总记录的天花板,并且权限和共享规则会自动生效。把这几点记牢,写代码时心里就有谱了。

    查看详情
  • 6

    DML Statements vs. Database Class Methods

    第 168 页

    同学们,今天我们来看一下在Apex里面执行TLR操作的两种方法。TLR操作听起来可能有点陌生,其实你完全可以把它理解成对记录进行增删改,也就是我们常说的数据库操作。 Apex给了我们两种方式来完成这件事。第一种叫做TLR陈述,这其实就是像 insert、update、delete 这样的语句,写起来非常简单。不过,如果有一条记录出现问题,那整个操作就会失败,并且会马上抛出一个异常,你可以在代码里用 try-catch 抓住它,然后去处理。 第二种方式是使用数据库类的方法,比如 Database.insert、Database.update 等等。这种方法更灵活,因为它允许你设置部分记录处理。你在调用这些方法的时候,可以在第二个参数那里给它传一个布尔值。如果改成 true,那即使某几条记录出错了,剩下那些没问题的记录依然可以正常保存成功。而且这时候,它不会抛出异常,而是会返回一个结果对象的数组。这个数组里,每一个元素都对应一条记录的处理状态,以及出错时附带的错误信息,你可以一条一条去检查。 总结一下,如果你希望一遇到错误就立刻中断,把问题暴露出来,那就用TLR陈述,简单直接。如果你希望操作能够部分成功,只让有问题的记录失败,那你就用数据库类方法,并且记得第二个参数写 true,再去处理返回的结果数组。这样,你的程序就会更健壮,不会因为一颗老鼠屎坏了一锅粥啦。

    查看详情
  • 7

    Atomic Transactions & DML Operations Overview

    第 169 页

    今天我们来讲一个概念,叫做TLR操作,它和事务的执行关系非常密切。 先来理解一下什么是事务。你可以把事务想象成一组操作,它们被当成一个整体来看待。就像你去银行转账,从A账户扣钱、再往B账户加钱,这两步要么都成功,要么都失败,如果中间出了问题,钱不会凭空消失,一切都会回到操作前的状态。 在Salesforce的Apex里,TLR操作就是在这样的事务中执行的。TLR代表的是Trigger、类方法、匿名代码块、Apex页面或者自定义Web服务方法,这些就是事务的边界。也就是说,事务从哪里开始、到哪里结束,由这些块来决定。 这个概念最重要的规则就是“全或无”。事务里所有的TLR操作,要么全部成功提交到数据库,要么只要中间任何一个地方发生错误,整个事务就会回滚,之前做过的所有数据修改都会被撤销,就像什么都没发生过一样。这保证了数据的完整性和一致性,不会出现一半成功一半失败的混乱情况。 那TLR支持哪些具体操作呢?你可以用它来插入新记录、更新已有的记录,还有直接更新记录的字段值——注意这里我说了两个“更新”,第一个是常规的update操作,第二个则特指用特定的语句去修改字段。另外还可以删除记录,甚至把已经放进回收站的记录再恢复出来,也就是取消删除。对于重复的记录,还可以进行合并;对于销售过程中的潜在客户,你可以用TLR去执行转换操作。 最后还要记住一个数量上的限制:当你调用一次插入、更新、删除或取消删除方法时,最多能传入10,000条sObject记录。如果超过这个数目,就需要分批处理,否则会触发限制错误。 总结一下,TLR操作在其所属的事务边界内,遵循“同生共死”的原则,支持多种数据操作,并且单次操作有记录条数上限。理解这点,对你写出安全稳健的Apex代码很有帮助。

    查看详情
  • 8

    Inserting, Updating & Related Records

    第 170 页

    好,我们来看看这段内容。它讲的是在Salesforce里,如果两个对象之间已经有了关系,比如客户和订单,或者是父对象和子对象,那怎么往里面插入新的相关记录。 简单说,你可以在插入新记录时,通过一个叫“外卡ID”的东西,把它和已有的记录关联起来。这个“外卡ID”其实就是一种外部标识,可以让系统认出这条记录该跟谁连上。 要注意的是,当你用一次操作同时处理父记录和子记录的时候,子记录上关联父记录的那些字段,没法顺便就更新了父记录的其他字段。如果你想改父记录字段的内容,必须再用一次单独的操作。这是规则,不然系统会报错。 还有一种更灵活的做法,就是利用父记录上自定义的“外部ID字段”来添加关联的子记录。这样你就不一定非要拿到那个长长的系统ID,只要知道这个外部ID,就能把关系建立起来。 更有意思的是,如果你要一次性创建父记录和它的一系列子记录,比如创建一个新客户,同时创建它的好几个联系人和订单,可以在一条语句里完成,只要你把父记录放在数组里子记录的前面,而且支持的最深层数是十层。也就是说,父子链可以嵌套,但最深到第十层为止。 概括起来就是:有关系时,关联靠外卡ID或外部ID;一次操作不能跨层级更新父记录;批量创建时顺序要对、深度有限。这样讲,能理解吧?

    查看详情
  • 9

    Upserting, Merging & Deleting Records

    第 171 页

    好,同学们,我们这节课来聊几个非常实用的数据操作,它们能帮你优雅地处理记录,而不用写一堆判断逻辑。我们一个一个说。 首先,我们来看 ,Upsert,。你可能会遇到这样的情况:你手里有一条记录,但你不知道它在数据库里是已经存在,还是全新的。如果不存在,你想创建;如果存在,你想更新。这时候 Upsert 就派上用场了,它用一个指定的字段来决定到底是插入还是更新。比如,你可以用外部 ID 来匹配,如果有相同外部 ID 的记录,就更新;如果没有,就新建。这样你就不必先查询再判断,一行代码就搞定了。 接下来是 ,Merge,,合并。它允许你把最多三个重复的记录合并到一个主记录里去。关键点在于,主记录上的字段值,不管有没有数据,都会保留;而其他被合并的记录,只有主记录对应字段为空时,它们的值才会补上去。所以主记录上已经填好的信息不会被覆盖。这个操作很适合清理重复数据。 然后是 ,Delete, 和 ,Undelete,。当你调用 Delete,记录并不会立即从数据库消失,而是先被移到回收站。这个删除操作还会连带删除那些与之有主从关系的子记录——这叫级联删除。而如果删错了,你可以用 Undelete 把它恢复回来。恢复时,记录本身回来,同时那些单纯的查找关系也会自动恢复,这很方便。 最后,,ConvertLead,。这是专门用来处理潜在客户转换的。在实际业务中,一个线索经过跟进,可能变成了真正的客户,我们需要把它转换为客户、联系人,甚至还可以生成一个商机。在 Apex 里,你不能用普通的 DML 语句直接做这件事,而是必须通过 Database 类的 convertLead() 方法。这个方法接受 LeadConvert 对象,返回转换结果。记住,它不是写在 TLR 声明里的那种操作,必须依靠这个方法才能完成。 好了,整个 Slide 的核心就是:Upsert 帮你智能决策插入还是更新;Merge 合并并保留主记录优先;Delete 是软删除且级联;Undelete 恢复关系;ConvertLead 用专门方法生成客户等。理解这些操作的特性,会让你的代码简洁又健壮。 我们休息一下,下张幻灯片继续。

    查看详情
  • 10

    Exception Handling & Database Result Objects

    第 172 页

    同学们,咱们今天来看看这个关于TLR操作和结果处理的Slide。 TLR呢,你可以理解为就是那些会修改数据库的操作,比如插入、更新、删除什么的。当你直接写DML语句的时候,万一碰到问题,它会直接抛出一个运行时异常,咱们得用 `try-catch` 块去兜底。 但这么处理有个问题——如果一次操作好几条记录,只要有一条失败,整个异常就抛出来了,你根本不知道具体是哪条记录出的错。所以更推荐用 `Database` 类提供的方法,比如 `Database.insert()`、`Database.update()`,这些方法会返回一个结果对象,里面装着每条记录的详细状态。 根据操作类型不同,返回的结果对象也不一样: - 做插入和更新,返回的是 ,SaveReport,(其实标准叫 SaveResult,你理解成保存报告就好)。 - 做 upsert,返回 ,UpsertReport,,它比 SaveReport 多了一个 `isCreated()` 方法,能帮你判断这条记录是新建的还是被更新的。 - 如果是合并记录,返回 ,MergeReport,。 - 删除返回 ,DeleteReport,,取消删除返回 ,UndeleteReport,。 - 还有线索转换,用的是 ,LeadConvertReport,。 这些“报告”对象都有一套通用的方法: - `isSuccess()` 告诉你这次操作成功还是失败。 - 成功了,可以用 `getId()` 拿到新记录的 ID。 - 如果失败,就调用 `getErrors()` 把具体错误信息取出来。 这里还有一个特别实用的功能——,部分处理,。当你在调用 Database 方法的时候,把第二个参数设为 `true`(其实是 `allOrNone = false`),那就不会因为某一条记录失败而抛出异常了。你可以安安稳稳地遍历结果列表,用 `isSuccess()` 一条一条去检查,该记录的记录,该报错的单独处理。这样整个操作的鲁棒性就好多了。 好,这部分的核心就是:告别粗暴的异常,拥抱结果对象,用巧劲去处理数据库操作。有什么疑问我们接着聊。

    查看详情
  • 11

    DML Options & Transaction Control

    第 173 页

    各位同学,大家好。今天咱们要翻开 Slide,学习一个很实用的小工具,叫做 ,Database.DMLOptions,。 你看到的这个 “Datab. DMLops”,其实就是它的简写,不用纠结,记住它叫 DML Options 就行。 那它是干什么的呢?简单说,当你在 Apex 里做,插入,或,更新,数据的操作时,如果你想顺便控制一些额外的行为,比如“字段太长时要不要自动截断”、“要不要触发分配规则”、“要不要发送邮件”等等,就可以通过这个 DMLOptions 来设定。它就像给我们的 DML 语句加了一堆开关和选项。 我们来看看这些开关长什么样。 第一个,,allowFieldTruncation,。这个属性控制字符串截断。比如一个文本字段最大长度是 255,你不小心塞了 300 个字符过去,如果把这个设为 true,系统就直接帮你把多出来的部分剪掉,保存成功;如果设为 false,它就会报错。简单省心吧? 第二个,,assignmentRuleHeader,。它专门针对案例 (Case) 和 线索 (Lead),用来指定是否要跑分配规则。比如让系统自动把新案例分配给相应的人,你设一下这个属性就行,不用再去 UI 上勾选。 第三个,,duplicateRuleHeader,。如果你保存的记录被系统判定为是重复的,比如手机号跟现有记录一样,一般会阻止保存。但把这个属性设上,就允许硬把这条“重复”记录存进去。 第四个,,emailHeader,。它可以控制自动回复邮件、是否发送给外部用户、以及是否触发跟邮件相关的 Apex 触发器。做批量导入时,为了不狂发邮件炸邮箱,就可以用这个关掉。 第五个,,locale,。有时你拿到错误信息的返回,或者一些选项列表的标签,这个属性能指定用什么语言返回,做多语言项目时会帮上忙。 最后,,optAllOrNone,,有的版本可能写成 optAllOrNo,意思是“全有或全无”。如果设为 true,你一次插入 100 条记录,但凡有一条失败,整个操作全回滚,一条都不留;如果设为 false,就可以部分成功、部分失败,剩下的记录能保存。 好了,记住最重要一点:,DMLOptions 只对 Apex 里的 DML 操作管用,,在标准 Salesforce 界面上点保存按钮,它可不理这堆设置。以后再写批量逻辑的时候,脑子里就要冒出这个好朋友啦。好,这节课我们就聊到这儿,下次见!

    查看详情
  • 12

    Savepoints & Transaction Rollback

    第 174 页

    同学,我们今天来讲一个很实用的知识点——Apex 里面的“保存点”,也就是 Savepoint。 你可以把保存点想象成游戏里的存档。在程序运行到某个时刻,你对数据库说:“嘿,记住现在数据库的状态。” 之后,如果你发现操作出了问题,或者需要撤销刚才的改动,就可以直接“读档”,让数据库恢复到那个存档的状态。而且不用重启,也不用整个回滚,非常方便。 那在 Apex 里怎么实现呢?很简单,用 `Database.setSavepoint()` 这个方法就能生成一个保存点。如果你后面想回滚,也就是把数据库恢复到保存点那一刻的样子,就可以调用 `Database.rollback(savepoint)`。这样,从保存点之后所有还没来得及提交的 DML 操作(也就是增删改)都会被丢弃。同时,回滚的时候,所有从保存点之后拿到的表锁、行锁也都会被释放掉,不影响其他操作。 当然,保存点好用,但也有一些限制,这个要注意: 第一,如果你有好几个保存点,比如先设了保存点 A,又设了保存点 B。如果你回滚到 A,那 B 就会失效,不能再用 B 回滚了,因为 B 是建立在 A 之后的状态上的。这就像游戏里你如果读了一个更早的存档,后面存的进度自然就没了。 第二,保存点不能跨触发器调用。也就是说,你不能在一个触发器里设个保存点,然后指望在另一个触发器中回滚它。保存点的作用范围只在同一个触发器上下文或者同一个执行块里。 第三,保存点只恢复数据库状态,但不会恢复静态变量的值。也就是说,如果你在保存点之后改了一个静态变量,然后回滚,那个静态变量还是改后的值,不会变回去。这一点一定要记清楚,因为它可能会引起逻辑上的小麻烦。 最后还有个小细节,回滚的时候,虽然数据复原了,但如果你在插入记录时生成的 sObject ID 并不会被回收。意思就是说,你本来插入了一条记录拿到了一个 ID,回滚后那条记录没了,但这个 ID 已经被消耗掉了,不会重复使用。这是 Salesforce 平台的一种设计,避免 ID 冲突。 最后,当你用完了保存点,确定不再需要它了,记得调用 `Database.releaseSavepoint()` 来释放这个保存点,这样可以节省资源,也不会在后续误操作时意外回滚。 简单总结一下:用 `setSavepoint` 存档,`rollback` 读档,`releaseSavepoint` 删档。注意限制:早期回滚让后期失效、不能跨触发器、静态变量不恢复、ID 永久消耗。 好,咱们这节课就讲到这里,下次遇到需要局部回滚的场景,你就可以放心地用保存点了。

    查看详情
  • 13

    Mixed DML & Setup Objects

    第 175 页

    好,我们来看一个Apex开发中非常容易踩到的“坑”——关于事务里混合操作设置对象和非设置对象的问题。 你可能会问,什么是设置对象?就是那些和系统配置、用户权限相关的sObject,比如User、UserRole、Profile、PermissionSet等等。非设置对象就是我们平时处理业务的那些,比如Account、Contact、Opportunity。 在Apex里,如果你在一个事务中,既对设置对象做DML操作,又对非设置对象做DML操作,就可能会报错。官方说法是“某些设置对象上的TLR操作不能与非设置对象上的TLR混合”,TLR就是Trigger、Workflow、Process Builder这些自动化逻辑的统称。为啥会有这个限制?因为设置对象的变化会直接影响用户对记录的访问权限,Salesforce为了保证数据安全和权限一致性,就不允许在同一个事务里把这两类混在一起。 举个例子:你想在一个事务里,先更新一个Account,然后又去更新某个User的Role。这样可能会失败,因为更新了用户角色,权限就变了,之前那个Account的操作到底该不该允许呢?系统很难实时判断,干脆一刀切,不允许。 那遇到了该怎么办?有三种常用的解决方案: 第一种,用@future方法。把其中一类操作放到异步的@future方法里执行,这样它们就属于不同事务了,互不干扰。比如你把更新UserRole放到一个带@future的静态方法里,当前事务只处理Account,就不会冲突。 第二种,在测试类里,如果只是为了验证逻辑,可以用System.runAs()块来切换用户上下文。这样可以在不同权限下跑不同的DML,避开了混合事务的限制。 第三种,最根本的,就是设计上就把这两类操作拆到不同的事务里。比如用户点击按钮触发一个操作,你可以通过流程设计,先完成设置对象的更新,再通过另一个独立的进程去处理业务数据。 记住这个要点,你以后在写涉及权限和设置对象混合操作的代码时,就能提前规避这个报错了。这个限制不是Bug,而是Salesforce安全模型的一部分,理解原因之后,解决方法也很简单。

    查看详情
  • 14

    Locking Records

    第 176 页

    同学们,我们来看这页关于,记录锁定,的内容。这部分在 Apex 开发里非常重要,特别是当多个用户或后台进程同时想修改同一条记录的时候,很容易产生数据冲突。Salesforce 提供了一种锁定机制,来保证数据的一致性。 简单来说,当一条 sObject 记录被锁定以后,其他任何客户端或者用户,不管是通过代码还是直接在 Salesforce 界面上操作,都无法再更新这条记录了。只有锁定它的那个客户端,可以安安心心地执行自己的逻辑,做完更新,并且能确保在这个过程中,这条记录不会被别人偷偷改掉。这就保证了操作的原子性和数据安全。 那怎么才能在 Apex 里锁住记录呢?方法很简单:你在写内联 SOQL 查询的时候,在语句的最后加上一个关键字就行了。这里幻灯片上可能有个小笔误,大家注意一下,正确的写法是 ,FOR UPDATE,,不是 FOR GROUP。也就是说,你先写好 `SELECT ... FROM ... WHERE ...`,然后紧接着写上 `FOR UPDATE`,这样查出来的记录就被你锁住了。 不过用的时候有个限制要记住:,你不能把 ORDER BY 和 FOR UPDATE 一起用,。如果你需要对查询结果排序,可以先把数据查出来放到列表里,再用 Apex 的排序方法处理,没必要在锁记录的同时非得在查询里排序。 另外,Salesforce 的运行时引擎本身也内置了一些防止死锁的措施,它会在锁定子记录之前,先把相关的父记录锁住,并且会按照记录 ID 的顺序来锁定。这样能大大降低因为两个进程互相等待对方释放锁而卡死的概率。 虽然平台已经帮我们做了这些预防,但我们在设计逻辑的时候还是得小心,仍然要遵循标准的死锁避免技术。比如,尽量保持事务简短,按照固定的顺序去访问和锁定记录,减少同时锁住多张表的情况。这样你的代码才会更健壮,不容易在生产环境里出问题。 好,这就是这页 Slide 的核心内容。理解记录锁定,对写出高并发、高可靠性的 Apex 代码非常有帮助。

    查看详情
  • 15

    Key Data Considerations

    第 177 页

    同学们,我们来看这一页内容,它总结了几条在Apex里插入和更新数据时必须遵守的重要规则,我一条条给你讲清楚。 首先,,凡是必填字段,不管是插入新记录,还是更新现有记录时恰好要修改它,都必须给它一个非空的值,,不能留null,否则操作会失败。接着,如果你给字符串字段赋的值太长了,超过了定义的长度,在API版本15.0及之后保存的Apex类里,会直接抛出一个运行时错误,让程序中断。所以一定要控制好字符串长度。 第二点,sObject有一组描述权限的属性,比如“是否允许创建”、“是否允许更新”——虽然幻灯片上写了两个“

    查看详情