Em ambientes onde múltiplos processos atuam sobre os mesmos dados ao mesmo tempo, conflitos de concorrência podem se tornar um problema real. Atualizações simultâneas, registros sendo manipulados por fluxos paralelos ou automações complexas em Apex podem gerar inconsistências, falhas silenciosas ou até interrupções inesperadas no processamento.
É justamente para esses cenários que o SOQL Locking Records existe. Ele permite bloquear registros temporariamente durante uma transação Apex, garantindo que nenhum outro processo os altere enquanto você executa uma lógica crítica.
Neste artigo, vamos explorar como funciona o locking no Salesforce, quando usá-lo com segurança e quais boas práticas ajudam a evitar deadlocks.
O que é Locking Records no Salesforce
O Locking Records é um mecanismo de bloqueio de registros acionado diretamente por uma consulta SOQL por meio da cláusula FOR UPDATE. Ao utilizá-la, todos os registros retornados pela consulta ficam bloqueados até o final da transação Apex.
Isso significa que:
-
Nenhum outro processo pode alterar esses registros enquanto o Apex estiver em execução.
-
Não é necessário fazer commit manual.
-
Se a transação falhar, todas as alterações são revertidas.
-
Se ela concluir com sucesso, o Salesforce realiza o commit automaticamente.
-
Esse recurso é extremamente útil em operações críticas que dependem da integridade total dos dados durante o processamento.
for (Account acc : [
SELECT Id
FROM Account
WHERE CreatedDate = THIS_MONTH
FOR UPDATE
]) {
// Sua lógica aqui
}
Ao executar essa consulta:
-
Todos os registros retornados são bloqueados imediatamente.
-
Outros processos Apex ou automações que tentarem atualizá-los receberão uma exceção.
Atenção: ORDER BY não é permitido
O Salesforce não permite usar ORDER BY em consultas que tenham FOR UPDATE.
Isso protege o tempo de bloqueio, pois ordenar registros aumenta o tempo de execução e prolonga o período de lock — o oposto daquilo que se deseja ao utilizar esse recurso.
O que acontece se o registro já estiver bloqueado?
Existem duas situações comuns:
1. QueryException
Ocorre quando sua SOQL tenta bloquear um registro que já está bloqueado por outra transação ativa.
2. DmlException
Surge quando você tenta realizar um update em um registro que está bloqueado por outra transação.
Um exemplo com tratamento adequado:
try {
List accts = [
SELECT Id, Name
FROM Account
WHERE CreatedDate = THIS_MONTH
FOR UPDATE
];
for (Account acc : accts) {
acc.Name = acc.Name + ' - Processado';
}
update accts;
} catch (QueryException qe) {
System.debug('Erro ao tentar bloquear registros: ' + qe.getMessage());
} catch (DmlException de) {
System.debug('Erro ao atualizar registros bloqueados: ' + de.getMessage());
}
Evitando Deadlocks
Assim como qualquer sistema transacional, o Apex pode enfrentar deadlocks — situações onde uma transação aguarda outra indefinidamente.
Para minimizar riscos, o runtime do Salesforce segue regras de bloqueio:
-
Registros pai são bloqueados antes dos registros filhos.
-
Registros do mesmo objeto são bloqueados sempre na ordem do ID.
Apesar dessas proteções, a recomendação é clara:
Realize o lock somente nos registros que realmente serão alterados.
Bloquear mais registros do que o necessário aumenta o risco de espera e de deadlock.
Boas práticas ao usar SOQL Locking Records
Para garantir o uso seguro e eficiente, considere as seguintes recomendações:
1. Não utilize FOR UPDATE em consultas amplas
Evite aplicar lock em centenas ou milhares de registros de forma desnecessária.
2. Bloqueie o mais tarde possível e libere o mais cedo possível
Priorize trechos de código curtos e objetivos.
3. Combine com execução assíncrona
Usar métodos future, Queueable ou Batch Apex pode evitar conflitos em momentos de pico, pois o Salesforce gerencia a janela de execução ideal.
4. Evite ORDER BY
Conforme mencionado, essa operação aumenta o tempo de bloqueio e não é permitida com FOR UPDATE.
5. Sempre trate QueryException e DmlException
Erros de concorrência são comuns em grandes organizações.
Quando usar (e quando evitar) o Locking Records
Use quando:
-
Múltiplos processos podem atualizar os mesmos registros quase simultaneamente.
-
Sua lógica depende de integridade total durante o processamento.
-
Você precisa evitar leituras ou gravações inconsistentes entre automações.
Evite quando:
-
A consulta retorna um número muito grande de registros.
-
Os dados não serão alterados.
-
A lógica não é crítica a ponto de exigir bloqueio.
Conclusão
O SOQL Locking Records é uma ferramenta poderosa para garantir integridade em operações críticas no Salesforce. Embora o próprio CRM gerencie muito bem cenários de concorrência, existem momentos em que o bloqueio explícito é necessário para evitar conflitos, falhas de atualização e inconsistências.
Mais importante do que saber como utilizar o FOR UPDATE é entender quando ele realmente deve ser aplicado.
Use com parcimônia, trate exceções adequadamente e considere sempre a execução assíncrona quando possível.