🕵️ SicherheitslückenWhat continuous operational resilience looks like under DORA(09.09.2026 um 17:53 Uhr)
🔧 AI Nachrichten OpenAI seeks tougher AI rules. CIOs may feel the ripple effects(10.09.2026 um 12:11 Uhr)
🔧 AI Nachrichten Mistral valued at €21bn after €3bn Series D funding round(08.09.2026 um 10:19 Uhr)
🪟 Windows TippsWindows XP's Cursor Indicator Is Getting a Windows 11 Refresh(25.08.2026 um 13:00 Uhr)
🕵️ SicherheitslückenWhat continuous operational resilience looks like under DORA(09.09.2026 um 17:53 Uhr)
🔧 AI Nachrichten OpenAI seeks tougher AI rules. CIOs may feel the ripple effects(10.09.2026 um 12:11 Uhr)
🔧 AI Nachrichten Mistral valued at €21bn after €3bn Series D funding round(08.09.2026 um 10:19 Uhr)
🪟 Windows TippsWindows XP's Cursor Indicator Is Getting a Windows 11 Refresh(25.08.2026 um 13:00 Uhr)

🔧 Programmierung 🕛 vor 2 Monaten 3 Min Lesezeit
0

Cómo eliminé duplicados en la generación de números de factura sin usar locks

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht




Cómo eliminé duplicados en la generación de números de factura sin usar locks



Tenía un sistema de facturación en producción (Java/JAX-RS + MongoDB, corriendo en Tomcat) donde cada documento —factura, egreso, comprobante— necesita un número consecutivo único. Nada exótico. El problema apareció solo bajo carga: dos requests casi simultáneos generaban el mismo número.






El síntoma



Un usuario reportó dos facturas con el mismo folio. En logs, ambas requests llegaron con 40ms de diferencia. El código hacía esto:




CODE
// Antes: lee el último número, le suma 1, guarda
Documento ultimo = dao.findLastByTipo("FACTURA");
int siguiente = ultimo.getNumero() + 1;
nuevoDocumento.setNumero(siguiente);
dao.save(nuevoDocumento);






Clásico read-then-write sin atomicidad. Entre el find y el save, otro thread (u otro proceso, u otro pod si escalas horizontal) puede leer el mismo "último número" y generar el mismo consecutivo. Es el mismo problema que un debounce mal hecho en un botón físico: dos pulsos que deberían ser uno solo porque no hay una ventana atómica que los serialice.






Por qué no usé locks



Lock a nivel de aplicación (synchronized, semáforos) no sirve si vas a escalar a más de una instancia. Lock a nivel de base de datos (transacciones con bloqueo explícito) funciona pero añade latencia y complejidad de manejo de deadlocks que no necesitaba para este caso.






La solución: operación atómica nativa de Mongo



MongoDB tiene findOneAndUpdate con $inc, que es atómico a nivel de documento. En vez de leer-calcular-guardar, le pides a Mongo que incremente y te devuelva el valor ya incrementado, en una sola operación indivisible.



Colección dedicada:




CODE
// colección: contadores
{ _id: "FACTURA", secuencia: 1042 }






Código:




CODE
Bson filtro = Filters.eq("_id", "FACTURA");
Bson update = Updates.inc("secuencia", 1);
FindOneAndUpdateOptions opts = new FindOneAndUpdateOptions()
.returnDocument(ReturnDocument.AFTER)
.upsert(true);

Document contador = collection.findOneAndUpdate(filtro, update, opts);
int siguienteNumero = contador.getInteger("secuencia");






Esto es atómico incluso con N instancias de la aplicación pegándole a la misma base al mismo tiempo. Mongo serializa internamente las operaciones sobre el mismo _id, así que no hay ventana donde dos requests lean el mismo valor.






La red de seguridad: índice único



findOneAndUpdate resuelve el 99% de los casos, pero no cuesta nada blindar el dato final con un índice único sobre el campo numero dentro de la colección de documentos:




CODE
db.facturas.createIndex(
{ tipo: 1, numero: 1 },
{ unique: true }
)






Si por alguna razón (bug futuro, migración, dato legacy) se intenta insertar un duplicado, Mongo lo rechaza con un E11000 en vez de guardarlo silenciosamente. Prefiero un error explícito en logs a un duplicado silencioso que alguien descubre tres meses después en una auditoría.






Resultado



Cero duplicados desde que se desplegó, incluyendo picos de concurrencia reales (varios usuarios facturando al cierre de mes). El patrón se repite igual para cualquier secuencia que necesite unicidad garantizada bajo concurrencia: consecutivos de comprobantes, tickets, números de orden, lo que sea.






Resumen para copiar y pegar




  1. Nunca generes consecutivos con find + cálculo en memoria + save.

  2. Usa findOneAndUpdate + $inc sobre una colección de contadores dedicada.

  3. Blinda con índice único como última línea de defensa, no como solución principal.

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
1 Quelle
Sam Altman calls GPT-6 Astra rollout ‘messy’ as enterprise users wait for access
1 Quelle
Swiss government explores replacing Microsoft 365 with open-source software
1 Quelle
What continuous operational resilience looks like under DORA
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Cómo eliminé duplicados en la generación de números de factura sin usar locks

Thematisch verwandte Begriffe: Cómo, eliminé, duplicados, generación · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...