The DML statements are simple; the discipline is in bulkification, error handling, and respecting governor limits.
- Build a list, do not DML in a loop
Wrong: for (Lead l : leads) { update l; }. Right: List<Lead> toUpdate = new List<Lead>(); for (Lead l : leads) toUpdate.add(l); update toUpdate. One DML statement covers all records.
- Use Database methods for partial success
Database.SaveResult[] results = Database.update(records, false). Loop the results to find which records failed and why. Critical for batch imports where some records will inevitably fail.
- Handle DmlException correctly
Wrap DML in try-catch (DmlException e). Log the record IDs and error messages. Decide whether to retry, skip, or fail the whole batch based on the error type.
- Pre-validate when possible
Validation rules fire on DML, but Apex pre-validation (checking required fields, format) before DML produces clearer error messages than letting the platform validation rule fail mid-transaction.
- Use upsert for repeatable imports
When loading data from an external system, define an external ID field and use upsert. New rows insert; existing rows update. Avoids duplicate detection logic.
- Test with bulk data
Apex unit tests should insert 200+ records in setup and run the triggered code on the full set. Tests that only exercise 1 record miss bulkification bugs that fail in production.
- DML inside a loop fails on bulk data. Build a list, then DML once. This is the most common Apex bug.
- Governor limits: 150 DML statements, 10,000 records per transaction. Hitting either aborts the entire transaction.
- Mixed DML Exception: cannot insert User and Account in the same transaction without async. Set up affected objects need @future.
- DML triggers cascading automation. A single update can fire triggers, workflows, processes, Flows; all counting against the same limits.
- Upsert requires a unique external ID. Sending two records with the same external ID in one upsert call throws DUPLICATE_EXTERNAL_ID.