Skip to main content

SF-0274 · Compare · Medium

What is the difference between DML Statements vs Database Class Methods?

✓ Verified by Vikas Singhal · Last reviewed 5/17/2026 · Updated for Spring '26

Both DML statements (insert a;) and Database class methods (Database.insert(a);) hit the same database engine. The difference is in how they handle failures, return results, and expose options like partial success and duplicate handling. Pick the wrong one and a single bad record kills your whole batch.

The two syntaxes

// DML statement — concise, throws DmlException on any failure
insert accounts;

// Database class method — verbose, returns results, configurable failure behavior
Database.SaveResult[] results = Database.insert(accounts, false);

The all-or-nothing problem

When you write insert accounts; and any one record fails validation, the entire operation rolls back. You get a DmlException, you lose every successful insert, and you have no idea which records would have succeeded.

Database.insert(accounts, false) flips that behavior. With allOrNone = false, valid records save, invalid ones return errors, and you decide what to do with each.

Side-by-side comparison

FeatureDML StatementDatabase Class Method
Syntaxinsert records;Database.insert(records, allOrNone)
Default behaviorAll-or-nothingAll-or-nothing (when allOrNone = true)
Partial successNot availableallOrNone = false
Return valueNone — record Ids populated in placeSaveResult[] / UpsertResult[] / DeleteResult[]
Failure handlingThrows DmlExceptionReturns failed result with error details
Duplicate handlingStandard duplicate rulesConfigurable via Database.DMLOptions
Assignment rulesStandardConfigurable via DMLOptions
Suitable forInternal operations, testsIntegrations, async jobs, user-facing UIs

Reading SaveResult

Database.SaveResult[] results = Database.insert(accounts, false);

for (Integer i = 0; i < results.size(); i++) {
    Database.SaveResult sr = results[i];
    if (sr.isSuccess()) {
        System.debug('Inserted record Id: ' + sr.getId());
    } else {
        for (Database.Error err : sr.getErrors()) {
            System.debug('Account[' + i + '] failed: '
                + err.getStatusCode() + ' — ' + err.getMessage()
                + ' on fields: ' + err.getFields());
        }
    }
}

The SaveResult keeps the same order as the input list, so results[i] always corresponds to accounts[i]. That’s how you log or retry specific records.

DMLOptions: the power user level

Database.DMLOptions exposes settings the DML statement form cannot reach:

Database.DMLOptions options = new Database.DMLOptions();
options.DuplicateRuleHeader.AllowSave = true;            // bypass duplicate rule
options.AssignmentRuleHeader.UseDefaultRule = true;      // run lead assignment
options.EmailHeader.TriggerUserEmail = true;             // send "new owner" email
options.OptAllOrNone = false;

Database.insert(leads, options);

Anywhere you’ve ever wondered “how do I get the lead assignment rule to fire from Apex?” — that’s where.

When to use which

Use a DML statement when:

  • You want all-or-nothing behavior (most internal Apex)
  • The code is short, simple, and a failure is a true exception
  • You don’t need fine-grained error reporting

Use a Database method when:

  • You’re processing an integration payload where some records may legitimately fail (bad data, FK misses)
  • You’re writing a batch job that should continue on individual errors and report them
  • You need to configure duplicate rules, assignment rules, or email triggers
  • You want the structured SaveResult array for logging or compensating actions

Try-catch is not a substitute

A common junior mistake:

try {
    insert accounts;
} catch (DmlException e) {
    // This catches the exception but you've already lost every record
    System.debug(e.getMessage());
}

The catch fires, but the transaction rolled back. You can’t recover the partial successes — they never happened. If you need partial success, Database.insert(list, false) is the only way.

What interviewers are really looking for

The question tests whether you’ve felt the pain of an integration failing because one bad record killed 200 good ones. Mention allOrNone = false, SaveResult.getErrors(), and Database.DMLOptions — all three signal real production experience.

Verified against: Apex Developer Guide — Bulk DML Exception Handling, Database Methods. Last reviewed 2026-05-17 for Spring ‘26 release.