You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apex测试创建测试User触发MIXED_DML_OPERATION错误的问询

MIXED_DML_OPERATION错误的原因及解决方法

错误原因

Salesforce将对象分为两类:设置对象和非设置对象:

  • 设置对象(如User、Profile、Role)用于组织级配置,操作会影响整个Salesforce环境的规则和权限;
  • 非设置对象(如Account、Contact、Opportunity)是业务数据载体,仅涉及具体业务记录。

为了避免配置操作与业务数据操作互相干扰、保证事务原子性和数据一致性,Salesforce禁止在同一个事务内混合执行两类对象的DML操作。你的代码先插入了非设置对象(Account),接着在同一事务中插入设置对象(User),触发了这个限制。

解决方法

1. 使用System.runAs()隔离事务

System.runAs()会创建一个独立的事务上下文,在这个上下文中执行设置对象的DML操作,就能和之前的非设置对象操作隔离。

示例代码:

@isTest
private class MyTestClass {
    @isTest
    static void testUserCreation() {
        // 先创建非设置对象(Account、Contact)
        Account testAcc = new Account(Name='Test Account');
        insert testAcc;
        
        Contact testCon = new Contact(LastName='Test', AccountId=testAcc.Id);
        insert testCon;
        
        // 通过System.runAs开启新事务,创建User
        System.runAs(new User(Id=UserInfo.getUserId())) {
            Profile standardProfile = [SELECT Id FROM Profile WHERE Name='Standard User'];
            User testUser = new User(
                FirstName='Demo', LastName='User',
                Username='demo_user_' + System.currentTimeMillis() + '@test.com',
                Email='demo@test.com', Alias='demousr', ProfileId=standardProfile.Id,
                TimeZoneSidKey='America/Los_Angeles', LocaleSidKey='en_US',
                EmailEncodingKey='UTF-8', LanguageLocaleKey='en_US',
                CommunityNickname='demousr'
            );
            insert testUser;
            
            // 后续测试逻辑(如关联查询、业务操作)
            // ...
        }
    }
}

2. 调整操作顺序(适用于无需提前创建业务对象的场景)

如果业务逻辑允许,可以先在主事务中创建设置对象(User),再创建关联的非设置对象(Account、Contact),这样避免跨类别DML混合:

@isTest
private class MyTestClass {
    @isTest
    static void testUserAssociation() {
        // 先创建设置对象(User)
        Profile standardProfile = [SELECT Id FROM Profile WHERE Name='Standard User'];
        User testUser = new User(
            FirstName='Demo', LastName='User',
            Username='demo_user_' + System.currentTimeMillis() + '@test.com',
            Email='demo@test.com', Alias='demousr', ProfileId=standardProfile.Id,
            TimeZoneSidKey='America/Los_Angeles', LocaleSidKey='en_US',
            EmailEncodingKey='UTF-8', LanguageLocaleKey='en_US',
            CommunityNickname='demousr'
        );
        insert testUser;
        
        // 再创建关联的非设置对象
        Account testAcc = new Account(Name='Test Account', OwnerId=testUser.Id);
        insert testAcc;
        
        Contact testCon = new Contact(LastName='Test', AccountId=testAcc.Id, OwnerId=testUser.Id);
        insert testCon;
        
        // 后续测试逻辑
        // ...
    }
}

3. 拆分@testSetup与测试方法

如果使用@testSetup准备测试数据,要确保该方法内只执行同一类对象的DML:

  • 若@testSetup中创建设置对象,测试方法内再创建非设置对象;
  • 若@testSetup中创建非设置对象,测试方法内通过System.runAs()创建设置对象。

内容的提问来源于stack exchange,提问作者I am not Fat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 09:15:15