以下是您可能想了解的有关使用数据操作语言的一些事项。
- 设置 DML 选项
- 交易控制
- 在 DML 操作中不能一起使用的 sObject 某些 sObject(有时称为设置对象)上的 DML 操作
不能与同一事务中其他 sObject 上的 DML 混合使用。之所以存在此限制,是因为某些 sObject 会影响用户对组织中记录的访问。您必须在不同的事务中插入或更新这些类型的 sObject,以防止使用不正确的访问级别权限执行操作。例如,您无法在单个交易中更新帐户和用户角色。 - 不支持 DML 操作的 sObject
- 批量 DML 异常处理
- 您应该了解的有关 Apex 中数据的信息
设置 DML 选项
您可以通过设置所需的选项来指定插入和更新操作的 DML 选项 在对象中。您可以通过在 sObject 上调用方法或将其作为 参数添加到 and 方法中。Database.DMLOptionsDatabase.DMLOptionssetOptionsDatabase.insertDatabase.update使用 DML 选项,您可以指定:
- 字段的截断行为。
- 分配规则信息。
- 重复的规则信息。
- 是否发送自动电子邮件。
- 标签的用户区域设置。
- 操作是否允许部分成功。
该类具有以下属性:
Database.DMLOptions
- allowFieldTruncation属性
- assignmentRuleHeader属性
- dupicateRuleHeader
- emailHeader属性
- locale选项属性
- optAllOrNone(optAllOrNone)属性
DMLOptions 仅适用于针对 API 版本 15.0 及更高版本保存的 Apex。DMLOptions(DMLOptions) 设置仅对使用 Apex DML 执行的记录操作生效,而不对通过 Salesforce 用户界面。
allowFieldTruncation属性
该属性指定 字符串的截断行为。在针对 15.0 之前的 API 版本保存的 Apex 中,如果您 为字符串指定一个值,如果该值太大,则该值将被截断。对于 API 版本 15.0 及更高版本中,如果指定的值过大,则操作将失败,并且 返回错误消息。该属性允许您指定以前的行为 截断,而不是针对 API 版本 15.0 保存的 Apex 中的新行为,以及 后。allowFieldTruncationallowFieldTruncation该属性采用 Boolean 价值。如果 ,该属性将截断 String 值太长,这是 API 版本 14.0 及更早版本中的行为。为 例:
allowFieldTruncationtrue
Database.DMLOptions dml = new Database.DMLOptions();
dml.allowFieldTruncation = true;
assignmentRuleHeader属性
该属性指定 创建案例或潜在顾客时要使用的分配规则。assignmentRuleHeader
注意
Database.DMLOptions 对象支持案例和潜在顾客的分配规则,但不支持 对于帐户。使用该属性,您可以 设置以下选项:
assignmentRuleHeader
- assignmentRuleID:作业的 ID 案例或线索的规则。分配规则可以处于活动状态,也可以处于非活动状态。ID 可以是 通过查询 AssignmentRule sObject 进行检索。如果指定,则不要指定 。如果该值不在正确的 ID 中 格式(15 个字符或 18 个字符的 Salesforce ID),调用失败,并出现异常 返回。useDefaultRule
- useDefaultRule:指示是否默认 (活动)分配规则将用于案例或潜在顾客。如果指定,则不指定 一。assignmentRuleId
以下示例使用该选项:
useDefaultRule
Database.DMLOptions dmo = new Database.DMLOptions();
dmo.assignmentRuleHeader.useDefaultRule= true;
Lead l = new Lead(company='ABC', lastname='Smith');
l.setOptions(dmo);
insert l;
以下示例使用该选项:
assignmentRuleID
Database.DMLOptions dmo = new Database.DMLOptions();
dmo.assignmentRuleHeader.assignmentRuleId= '01QD0000000EqAn';
Lead l = new Lead(company='ABC', lastname='Smith');
l.setOptions(dmo);
insert l;
注意
如果组织中没有分配规则,则在 API 中 版本 29.0 及更早版本,创建案例或潜在顾客时,设置为 分配给预定义的默认所有者的案例或潜在顾客。在 API 版本 30.0 和 稍后,案例或潜在顾客未分配,并且不会分配给默认值 所有者。useDefaultRuletrue
dupicateRuleHeader属性
该属性确定是否 可以保存标识为重复的记录。重复的规则是 重复管理功能。dupicateRuleHeader使用该属性,您可以设置 这些选项。
dupicateRuleHeader
- allowSave:指示记录是否 标识为重复项可以保存。
以下示例演示如何保存已标识为 重复。若要了解如何循环访问重复错误,请参阅 DuplicateError 类
Database.DMLOptions dml = new Database.DMLOptions();
dml.DuplicateRuleHeader.AllowSave = true;
Account duplicateAccount = new Account(Name='dupe');
Database.SaveResult sr = Database.insert(duplicateAccount, dml);
if (sr.isSuccess()) {
System.debug('Duplicate account has been inserted in Salesforce!');
}
emailHeader属性
Salesforce 用户界面允许您指定在以下情况下是否发送电子邮件 将发生以下事件:
- 创建新案例或任务
- 将案例电子邮件转换为联系人
- 新用户电子邮件通知
- 潜在客户队列电子邮件通知
- 密码重置
在针对 API 版本 15.0 或更高版本保存的 Apex 中,Database.DMLOptions 属性允许您指定其他 有关由于 Apex 而发生其中一个事件时发送的电子邮件的信息 DML 代码执行。emailHeader使用该属性,可以设置这些选项。
emailHeader
- triggerAutoResponseEmail:指示是否 触发自动响应规则 () 或不触发 (),用于线索和案例。这封电子邮件可以 由许多事件自动触发,例如在创建案例或 重置用户密码。如果此值设置为 ,则在创建案例时,如果存在联系人的电子邮件地址 在 ContactID 中指定,电子邮件将发送到该地址。如果没有, 电子邮件将发送到 SuppliedEmail 中指定的地址。truefalsetrue
- triggerOtherEmail:指示是否 触发组织外部的电子邮件 () 或不 ()。这封邮件可以自动 由创建、编辑或删除案例的联系人触发。truefalse
- triggerUserEmail:指示是否 触发发送给组织中用户的电子邮件 () 或不发送给 ()。这封电子邮件 可由多个事件自动触发;重置密码,创建一个 新用户,或创建或 修改任务。truefalse注意添加注释 Apex 中的案例不会触发向组织中的用户发送电子邮件,即使设置为 。triggerUserEmailtrue
即使自动发送的电子邮件可以由 Salesforce 用户界面,的 DMLOptions 设置仅对在 Apex 代码中执行的 DML 操作生效。emailHeader在以下示例中,选项是 指定:
triggerAutoResponseEmail
Account a = new Account(name='Acme Plumbing');
insert a;
Contact c = new Contact(email='jplumber@salesforce.com', firstname='Joe',lastname='Plumber', accountid=a.id);
insert c;
Database.DMLOptions dlo = new Database.DMLOptions();
dlo.EmailHeader.triggerAutoResponseEmail = true;
Case ca = new Case(subject='Plumbing Problems', contactid=c.id);
database.insert(ca, dlo);
由于群组事件而通过 Apex 发送的电子邮件包含其他行为。组事件是 IsGroupEvent 为 true 的事件。 EventAttendee 对象跟踪受邀加入组的用户、潜在顾客或联系人 事件。请注意通过 Apex 发送的群组活动电子邮件的以下行为:
- 向用户发送群组活动邀请时,该选项将遵循该选项triggerUserEmail
- 向潜在顾客或联系人发送群组活动邀请时,该选项将遵循该选项triggerOtherEmail
- 更新或删除群组活动时发送的电子邮件也会根据需要遵循 和 选项triggerUserEmailtriggerOtherEmail
locale选项属性
该属性指定语言 Apex 返回的任何标签。该值必须是有效的用户区域设置(language 和 国家/地区),例如 de_DE 或 en_GB。该值为 String,长度为 2-5 个字符。前两个 字符始终是 ISO 语言代码,例如“fr”或“en”。如果值为 进一步由一个国家/地区限定,则该字符串还具有下划线 (_) 和另一个 ISO 国家/地区代码,例如“US”或“UK”。例如,美国的字符串是 “en_US”,而加拿大法语的字符串是“fr_CA”。localeOptions
optAllOrNone(optAllOrNone)属性
该属性指定 操作允许部分成功。如果设置为 ,则所有更改 如果任何记录导致错误,则回滚。此属性的默认值是,成功处理的记录已提交 而有错误的记录则没有。此属性在保存的 Apex 中可用 Salesforce API 版本 20.0 及更高版本。optAllOrNoneoptAllOrNonetruefalse
交易控制
所有请求都由触发器、类方法、Web 分隔 执行 Apex 代码的服务、Visualforce 页面或匿名块。如果整个请求 成功完成,所有更改都将提交到数据库。例如,假设一个 Visualforce 页面调用了 Apex 控制器,而 Apex 控制器又调用了额外的 Apex 类。只 当所有 Apex 代码都完成运行并且 Visualforce 页面完成运行时,是 提交到数据库的更改。如果请求未成功完成,则所有 数据库更改将回滚。
有时,在处理记录期间,您的业务规则需要 部分工作(已执行的 DML 语句)被“回滚”,以便处理可以 继续朝另一个方向前进。Apex 使您能够生成保存点, 也就是说,请求中指定数据库当时状态的点。任何 DML 可以放弃保存点之后发生的语句,并且可以将数据库还原到 与生成保存点时所处的状态相同。
以下限制适用于生成保存点变量和回滚 数据库:
- 如果设置了多个保存点,则回滚到不是最后一个保存点 SavePoint 时,后面的 SavePoint 变量将失效。例如,如果你 先生成保存点,然后生成保存点,然后回滚到 ,该变量将不再有效。如果您尝试使用它,您将收到运行时错误。SP1SP2SP1SP2
- 对保存点的引用不能交叉触发器调用,因为每个触发器调用都是 新的触发器上下文。如果将保存点声明为静态变量,则尝试在 触发上下文时,您将收到运行时错误。
- 您设置的每个保存点都计入 DML 语句的调控器限制。
- 静态变量在回滚期间不会还原。如果您尝试再次运行触发器,则 静态变量保留第一次运行的值。
- 每次回滚都计入 DML 语句的调控器限制。您将收到一个 运行时错误,如果尝试回滚数据库的次数更多。
- 设置保存点后插入的 sObject 上的 ID 未清除 回滚后。创建一个要在回滚后插入的 sObject。尝试插入 sObject 使用在回滚之前创建的变量失败,因为 sObject 变量具有 使用相同的变量更新或更新插入 sObject 也会失败,因为 sObject 不在数据库中,因此无法更新。
下面是使用 和 Database 方法的示例。setSavepointrollback
Account a = new Account(Name = 'xxx'); insert a;
System.assertEquals(null, [SELECT AccountNumber FROM Account WHERE Id = :a.Id].
AccountNumber);
// Create a savepoint while AccountNumber is null
Savepoint sp = Database.setSavepoint();
// Change the account number
a.AccountNumber = '123';
update a;
System.assertEquals('123', [SELECT AccountNumber FROM Account WHERE Id = :a.Id].
AccountNumber);
// Rollback to the previous null value
Database.rollback(sp);
System.assertEquals(null, [SELECT AccountNumber FROM Account WHERE Id = :a.Id].
AccountNumber);
在 DML 操作中不能一起使用的 sObject
对某些 sObject(有时称为设置对象)的 DML 操作, 不能在同一事务中与其他 sObject 上的 DML 混合使用。此限制 之所以存在,是因为某些 sObject 会影响用户对组织中记录的访问。您必须 在不同的事务中插入或更新这些类型的 sObject 以防止操作 从不正确的访问级别权限发生。例如,您无法更新 单个事务中的帐户和用户角色。执行 DML 操作时,不能将以下 sObject 与其他 sObject 一起使用 在同一笔交易中。
- 身份验证会话
- 字段权限
- 预测分享
- 群您只能在事务中插入和更新组,并与其他组 s对象。不允许其他 DML 操作。
- 集团成员注意使用 Salesforce API 版本 14.0 保存旧版 Apex 代码 更早版本,您可以在 相同的交易。
- 对象权限
- ObjectTerritory2AssignmentRule
- ObjectTerritory2AssignmentRuleItem
- 权限集
- 权限集分配
- QueueSObject (英语)
- 规则区域 2 协会
- SetupEntityAccess
- 领土
- 地区2
- Territory2Model(区域2模型)
- 用户您可以在 Apex 代码中与其他 sObject 一起在事务中插入用户 使用 Salesforce API 版本 14.0 及更早版本保存。您可以插入一个 用户在 Apex 代码中与其他 sObject 的事务中保存 将 UserRoleId 指定为 null 时的 Salesforce API 版本 15.0 及更高版本。您可以使用以下命令更新事务中的用户 使用 Salesforce API 版本 14.0 保存的 Apex 代码中的其他 sObject 和 早些时候您可以使用以下 使用 Salesforce API 版本 15.0 及更高版本保存的 Apex 代码,当用户 不包含在 Lightning Sync 配置中 (活动或非活动),并且以下字段不会更新:
- UserRoleId
- IsActive
- 预测已启用
- IsPortal已启用
- 用户名
- 配置文件 Id
- UserPackage许可证
- 用户角色
- 用户区域
- UserTerritory2Association
如果您将 Visualforce 页面与自定义控制器一起使用,则不能混合使用 sObject 类型 在单个请求或操作中使用这些特殊 sObject 中的任何一个。但是,您可以 在后续请求中对这些不同类型的 sObject 执行 DML 操作。为 例如,您可以使用“保存”按钮创建一个帐户,然后创建一个具有 具有提交按钮的非 null 角色。您可以使用 流程如下:
- 创建一个对一种类型的 sObject 执行 DML 操作的方法。
- 创建第二个方法,该方法使用 future 批注来操作第二个 sObject 类型。
此过程将在下一节的示例中演示。
示例:使用 Future 方法执行混合 DML 操作
此示例演示如何使用 future 方法执行混合 DML 操作 对 User 对象执行 DML 操作。
public class MixedDMLFuture {
public static void useFutureMethod() {
// First DML operation
Account a = new Account(Name='Acme');
insert a;
// This next operation (insert a user with a role)
// can't be mixed with the previous insert unless
// it is within a future method.
// Call future method to insert a user with a role.
Util.insertUserWithRole(
'mruiz@awcomputing.com', 'mruiz',
'mruiz@awcomputing.com', 'Ruiz');
}
}
public class Util {
@future
public static void insertUserWithRole(
String uname, String al, String em, String lname) {
Profile p = [SELECT Id FROM Profile WHERE Name='Standard User'];
UserRole r = [SELECT Id FROM UserRole WHERE Name='COO'];
// Create new user with a non-null user role ID
User u = new User(alias = al, email=em,
emailencodingkey='UTF-8', lastname=lname,
languagelocalekey='en_US',
localesidkey='en_US', profileid = p.Id, userroleid = r.Id,
timezonesidkey='America/Los_Angeles',
username=uname);
insert u;
}
}
- 测试方法
中的混合 DML 操作 测试方法允许执行混合数据操作语言 (DML) 操作,其中包括设置 sObject 和其他 sObject(如果执行 DML 操作的代码包含在方法块中)。还可以在测试方法调用的异步作业中执行 DML。例如,通过这些技术,您可以在同一测试中创建具有角色和其他 sObject 的用户。System.runAs
测试方法中的混合 DML 操作
测试方法允许执行混合数据操作语言 (DML) 操作 包括设置 sObject 和其他 sObject(如果执行 DML 的代码) 操作包含在方法中 块。还可以在测试方法调用的异步作业中执行 DML。这些 例如,通过技术,您可以创建具有角色的用户,并在 同样的测试。
System.runAs
设置 sObjects 列在不能一起使用的 sObjects 中 在 DML 操作中。
注意
由于在部署期间会跳过对混合 DML 操作的验证,因此可能会有 部署测试时与运行时测试失败次数的差异 用户界面。
示例:System.runAs 块中的混合 DML 操作
此示例说明如何将混合 DML 操作包含在块中以避免混合 DML 错误。该块在 当前用户的上下文。它创建一个具有角色和测试的测试用户 帐户,这是一个混合 DML 操作。
System.runAsSystem.runAs
@isTest
private class MixedDML {
static testMethod void mixedDMLExample() {
User u;
Account a;
User thisUser = [SELECT Id FROM User WHERE Id = :UserInfo.getUserId()];
// Insert account as current user
System.runAs (thisUser) {
Profile p = [SELECT Id FROM Profile WHERE Name='Standard User'];
UserRole r = [SELECT Id FROM UserRole WHERE Name='COO'];
u = new User(alias = 'jsmith', email='jsmith@acme.com',
emailencodingkey='UTF-8', lastname='Smith',
languagelocalekey='en_US',
localesidkey='en_US', profileid = p.Id, userroleid = r.Id,
timezonesidkey='America/Los_Angeles',
username='jsmith@acme.com');
insert u;
a = new Account(name='Acme');
insert a;
}
}
}
使用@future绕过混合 测试方法中的 DML 错误
不允许在单个事务中混合 DML 操作。你不能执行 在同一事务中设置一个 sObject 和另一个 sObject 上的 DML。但是,您可以 将一种类型的 DML 作为异步作业的一部分执行,而在另一种作业中执行其他类型的 DML 异步作业或原始事务中。此类包含一个方法,该方法将由 随后的 例。
@future
public class InsertFutureUser {
@future
public static void insertUser() {
Profile p = [SELECT Id FROM Profile WHERE Name='Standard User'];
UserRole r = [SELECT Id FROM UserRole WHERE Name='COO'];
User futureUser = new User(firstname = 'Future', lastname = 'User',
alias = 'future', defaultgroupnotificationfrequency = 'N',
digestfrequency = 'N', email = 'test@test.org',
emailencodingkey = 'UTF-8', languagelocalekey='en_US',
localesidkey='en_US', profileid = p.Id,
timezonesidkey = 'America/Los_Angeles',
username = 'futureuser@test.org',
userpermissionsmarketinguser = false,
userpermissionsofflineuser = false, userroleid = r.Id);
insert(futureUser);
}
}
此类调用上一个中的方法 类。
@isTest
public class UserAndContactTest {
public testmethod static void testUserAndContact() {
InsertFutureUser.insertUser();
Contact currentContact = new Contact(
firstName = String.valueOf(System.currentTimeMillis()),
lastName = 'Contact');
insert(currentContact);
}
}
不支持 DML 操作的 sObject
您的组织包含 Salesforce 提供的标准对象和自定义对象 您创建的。这些对象可以在 Apex 中作为 sObject 数据类型的实例进行访问。 您可以查询这些对象,并对它们执行DML操作。但是,一些标准 对象不支持 DML 操作,但您仍然可以在查询中获取它们。他们 包括以下内容:
- AccountTerritoryAssignmentRule
- AccountTerritoryAssignmentRuleItem
- Apex组件
- ApexPage(顶点页面)
- 营业时间
- 业务流程
- 种类Node
- 货币类型
- DatedConversionRate
- NetworkMember(仅允许)update
- 流程实例
- 轮廓
- 记录类型
- SelfServiceUser(自助服务用户)
- 静态资源
- 地区2
- UserAccountTeamMember 用户
- 用户首选项
- 用户区域
- 网页链接
- 如果客户记录的记录类型为“个人帐户”,则“名称”字段不能为 使用 DML 操作进行修改。
批量 DML 异常处理
批量 DML 调用引起的异常(包括 作为调用的直接结果而触发的触发器)的处理方式不同,具体取决于 原始呼叫的来源:
- 当由于直接源自 Apex DML 的批量 DML 调用而发生错误时 语句,或者如果数据库 DML 的参数 方法指定为 ,运行时 引擎遵循“全有或全无”规则:在单次 操作,所有记录必须更新成功或整个操作 回滚到 DML 语句之前的点。如果指定了数据库 DML 方法的参数 as 和 a before 触发器分配一个 字段的值无效,则不会插入部分有效记录集。allOrNonetrueallOrNonefalse
- 当由于源自 SOAP API 的批量 DML 调用而发生错误时,默认 设置,或者如果数据库 DML 的参数 方法被指定为 , 运行时引擎至少尝试部分保存:allOrNonefalse
- 在第一次尝试期间,运行时引擎将处理所有记录。任何 由于验证规则或 唯一索引冲突被搁置一旁。
- 如果在第一次尝试期间出现错误,运行时引擎会使 第二次尝试,仅包括未生成的记录 错误。在第一个期间未生成错误的所有记录 尝试,如果任何记录生成错误(可能 由于竞争条件),它也被搁置一旁。
- 如果在第二次尝试期间出现其他错误,则运行时 引擎进行第三次也是最后一次尝试,仅包含这些记录 在第一次和第二次尝试期间不会产生错误。如果有的话 记录生成错误,整个操作失败并显示错误 消息,“存在 Apex 触发器时批量重试次数过多 和部分故障。
- 在第二次和第三次尝试期间,调速器限制将重置为 它们在第一次尝试之前的原始状态。请参阅 Execution Governors 和 限制。
- Apex 触发器在第一次保存尝试时触发,如果出现错误 对于某些记录,随后会尝试 保存成功记录的子集,触发器将在此上重新触发 记录的子集。
您应该了解的有关 Apex 中数据的信息
非 null 必填字段、值和 null 字段在现有记录上插入新记录或更新必填字段时,必须 为所有必需的值提供非值 领域。null与 SOAP API 不同,Apex 允许您在不更新 sObject 记录上的数组的情况下更改字段值。The API 由于许多 SOAP 提供程序对值的处理不一致,因此需要更新此数组。因为 Apex 运行 仅在 Lightning 平台上,此解决方法是不必要的。nullfieldsToNullnull某些 sObject 不支持 DML某些 sObject 不支持 DML 操作。请参阅不支持 DML 操作的 sObject。字符串字段截断和 API 版本使用 API 版本 15.0 及更高版本保存(编译)的 Apex 类和触发器会生成 如果为字段分配的 String 值太长,则运行时错误。用于启用 DML 操作的 sObject 属性为了能够插入、更新、删除或取消删除 sObject 记录,sObject 必须 将相应的属性(、、或分别)设置为 。createableupdateabledeletableundeletabletrueID 值该语句自动设置 ID 所有新 sObject 记录的值。插入已具有 ID 的记录,以及 因此,组织的数据中已存在 – 会产生错误。有关详细信息,请参阅列表。insertand 语句检查每批记录中是否存在重复的 ID 值。如果 有重复项,前五个被处理。对于第六个和所有附加 重复的 ID,则这些条目的 SaveResult 会标记为类似于 以后:insertupdateMaximum number of duplicate updates in one batch (5 allowed). Attempt to update Id more than once in this API call: number_of_attempts.更新的 sObject 记录的 ID 不能在语句中修改,但相关记录 ID 可以修改。update具有唯一约束的字段对于某些具有具有唯一约束的字段的 sObject, 插入重复的 sObject 记录会导致错误。例如,插入 具有相同名称的 CollaborationGroup sObject 会导致错误,因为 CollaborationGroup 记录必须具有唯一的名称。自动设置系统字段插入新记录时,系统字段(如 、 和)会自动更新。你不能 在 Apex 中显式指定这些值。同样,在更新记录时,系统 、 和 等字段会自动更新。CreatedDateCreatedByIdSystemModstampLastModifiedDateLastModifiedByIdSystemModstampDML 语句处理的最大记录数最多可以将 10,000 个 sObject 记录传递给单个 、 、 和 方法。insertupdatedeleteundelete
每个语句由两个操作组成,一个用于插入记录,另一个用于插入记录 一个用于更新记录。其中每个操作都分别受 和 的运行时限制的约束。例如,如果更新插入超过 10,000 条记录 并且所有这些都正在更新,您会收到一个错误。(请参阅执行调控器和限制upsertinsertupdate)更新插入和外键如果已将外键设置为引用,则可以使用外键更新插入 sObject 记录 领域。有关详细信息,请参阅对象引用中的字段类型 对于 Salesforce。为多个对象类型创建记录
与 SOAP API 一样,您可以在 Apex 中为多个对象类型创建记录。 包括自定义对象,在 API 版本 20.0 及更高版本的一次 DML 调用中。例如 您可以在一次通话中创建联系人和帐户。您最多可以为 10 个创建记录 一次调用中的对象类型。
记录的保存顺序与它们在 sObject 输入数组中输入的顺序相同。如果 您正在输入具有父子关系的新记录,即父记录 必须在数组中的子记录之前。例如,如果您要创建联系人 如果引用的帐户也在同一调用中创建,则该帐户必须 数组中的索引比联系人的索引小。联系人引用了 帐户,使用外部 ID 字段。
您不能添加引用相同对象类型的另一条记录的记录 同样的电话。例如,“联系人”对象具有“报告对象”字段 这是对另一个联系人的引用。如果一个联系人,则无法在一次通话中创建两个联系人 联系人使用“报告对象”字段引用 输入数组。您可以创建一个联系人,该联系人引用了另一个联系人 以前创建。
Salesforce 将多个对象类型的记录分解为多个块。一个 chunk 是输入数组的子集,每个 chunk 包含一个对象的记录 类型。数据是逐块提交的。与以下项相关的任何 Apex 触发器 区块中的记录每个区块调用一次。考虑一个 sObject 输入数组 包含以下一组记录:
account1, account2, contact1, contact2, contact3, case1, account3, account4, contact4
- account1, account2
- contact1, contact2, contact3
- case1
- account3, account4
- contact4
每个调用最多可以处理 10 个区块。如果 sObject 数组包含超过 10 个 块,则必须在多个调用中处理记录。更多信息 关于此功能,请参阅为不同的 SOAP API Developer 中的对象类型 指南。
注意
对于 Apex,插入或更新 DML 操作的输入数组分块具有 两个可能的原因:存在多个对象类型或默认块大小 200. 如果由于这两个原因而在输入数组中发生分块,则每个分块 计入 10 个区块的限制。如果输入数组仅包含一种类型的 sObject,则不会达到此限制。但是,如果输入数组至少包含两个 sObject 类型,并包含大量对象,这些对象被分块成 200 个组, 您可能会达到此限制。例如,如果您有一个包含 1,001 的数组 连续的潜在客户后跟 1,001 个连续的联系,数组将被分块到 12 组:两组是由于 Lead 和 Contact 的不同 sObject 类型,以及 其余部分是由于默认的分块大小为 200 个对象。在本例中, 插入或更新操作返回错误,因为已达到 10 个区块的限制 在混合阵列中。解决方法是为每个对象类型调用 DML 操作 分别。DML 和知识对象在知识文章(KnowledgeArticleVersion 类型,例如 自定义FAQ__kav文章类型),正在运行的用户必须具有知识用户功能 许可证。否则,调用包含对知识的 DML 操作的类方法 文章会导致错误。如果正在运行的用户不是系统管理员,并且不是 具有知识用户功能许可证,调用类中的任何方法都会返回错误 即使调用的方法不包含知识文章的 DML 代码,但另一个 方法。例如,下面的类包含两个方法,只有一个 其中对知识文章执行 DML。非管理员非知识用户,其 调用该方法将获得以下内容 错误:doNothingDML operation UPDATE not allowed on FAQ__kav
public class KnowledgeAccess {
public void doNothing() {
}
public void DMLOperation() {
FAQ__kav[] articles = [SELECT Id FROM FAQ__kav WHERE PublishStatus = 'Draft' and Language = 'en_US'];
update articles;
}
}
解决方法是将输入数组从 FAQ__kav 数组强制转换为 DML 语句 articles 添加到泛型 sObject 类型的数组中,如下所示:
public void DMLOperation() {
FAQ__kav[] articles = [SELECT id FROM FAQ__kav WHERE PublishStatus = 'Draft' and Language = 'en_US'];
update (sObject[]) articles;
}
锁定记录
锁定 sObject 记录时,不允许其他客户端或用户进行更新 通过代码或 Salesforce 用户界面。锁定记录的客户端可以 对记录执行逻辑并进行更新,并保证锁定的记录 在锁定期间不会被其他客户端更改。
- 锁定语句
在 Apex 中,您可以使用在更新 sObject 记录时锁定它们,以防止争用条件和其他线程安全问题。FOR UPDATE - 锁定 SOQL For 循环
- 避免死锁
锁定语句
在 Apex 中,您可以使用锁定 sObject 记录,以防止竞争条件和其他 线程安全问题。
FOR UPDATE
当 sObject 记录被锁定时,不允许其他客户端或用户进行更新 通过代码或 Salesforce 用户界面。锁定记录的客户端可以 对记录执行逻辑并进行更新,并保证锁定的记录 在锁定期间不会被其他客户端更改。锁被释放 当交易完成时。要在 Apex 中锁定一组 sObject 记录,请在任何内联 SOQL 语句后嵌入关键字。例如 以下语句除了查询两个帐户外,还会锁定帐户 那是 返回:
FOR UPDATE
Account [] accts = [SELECT Id FROM Account LIMIT 2 FOR UPDATE];
注意
您不能使用 任何使用锁定的 SOQL 查询。ORDER BY
锁定注意事项
- 当记录被客户端锁定时,锁定客户端可以修改其字段 同一事务中数据库中的值。其他客户端必须等到 事务完成,记录不再被锁定,然后才能更新 相同的记录。其他客户端仍然可以查询相同的记录,同时 锁。
- 如果尝试锁定当前由其他客户端锁定的记录,则进程将等待 在获取新锁之前,最多 10 秒才能释放锁。如果等待 时间超过 10 秒,a 是 扔。同样,如果您尝试更新当前被其他客户端锁定的记录 并且锁在最多 10 秒内没有松开,而是抛出 A。QueryExceptionDmlException
- 如果客户端尝试修改锁定的记录,则在 锁定在进行更新调用后的短时间内释放。在这个 情况下,如果 第二个客户获得了该记录的旧副本。为了防止发生覆盖, 第二个客户端必须首先锁定记录。锁定过程将返回 通过语句从数据库获取的记录。第二个客户端可以使用此副本进行新的更新。SELECT
- 在 Apex via 子句中获取的记录锁在进行标注时会自动释放。谨慎使用 同时在以前可以执行查询的上下文中进行标注。FOR UPDATEFOR UPDATE
- 当您对一条记录执行 DML 操作时,相关记录也会被锁定 到有问题的记录。
警告
在 Apex 代码中设置锁定时要小心。请参阅避免死锁。
锁定 SOQL For 循环
关键字也可以在 SOQL 循环。为 例:
FOR UPDATEfor
for (Account[] accts : [SELECT Id FROM Account
FOR UPDATE]) {
// Your code
}
正如 SOQL For 循环中所讨论的,上面的示例在内部对应于 SOAP API 中对 and 方法的调用。query()queryMore()
请注意,没有语句。如果你的 Apex 触发器成功完成,任何数据库更改都会自动提交。 如果 Apex 触发器未成功完成,则对数据库所做的任何更改 被回滚。commit
避免死锁
Apex 存在死锁的可能性,就像任何其他涉及的过程逻辑语言一样 更新多个数据库表或行。为避免此类死锁,Apex 运行时引擎:
- 首先锁定 sObject 父记录,然后锁定子记录。
- 当多个相同类型的记录被 编辑。
作为开发人员,在锁定行时要小心,以确保你 不引入死锁。验证是否正在使用标准死锁 通过以相同顺序访问表和行的规避技术 从应用程序中的所有位置。