Si bien la respuesta anterior es cierta en el sentido de que SELECCIONAR ... PARA ACTUALIZAR evitará que las sesiones/transacciones simultáneas inserten el mismo registro, esa no es toda la verdad. Actualmente estoy luchando con el mismo problema y he llegado a la conclusión de que SELECCIONAR ... PARA ACTUALIZAR es casi inútil en esa situación por la siguiente razón:
Una transacción/sesión concurrente también puede hacer una SELECCIÓN ... PARA ACTUALIZAR en el mismo valor de registro/índice, y MySQL lo aceptará felizmente de inmediato (sin bloqueo) y sin arrojar errores. Por supuesto, tan pronto como la otra sesión haya hecho eso, su sesión tampoco podrá insertar más el registro. Ni usted ni la otra sesión/transacción obtienen información sobre la situación y piensan que pueden insertar el registro de manera segura hasta que realmente lo intentan. Intentar insertar entonces conduce a un interbloqueo o a un error de clave duplicada, según las circunstancias.
En otras palabras, SELECCIONAR ... PARA ACTUALIZAR evita que otras sesiones inserten los registros respectivos, PERO incluso si hace SELECT ... PARA ACTUALIZAR y no se encuentra el registro respectivo, es probable que no pueda realmente insertar ese registro. En mi humilde opinión, eso hace que el método "primera consulta, luego inserte" sea inútil.
La causa del problema es que MySQL no ofrece ningún método para realmente bloquear registros inexistentes. Dos sesiones/transacciones simultáneas pueden bloquear registros inexistentes "PARA ACTUALIZAR" al mismo tiempo, algo que en realidad no debería ser posible y que dificulta considerablemente el desarrollo.
La única forma de evitar esto parece ser usar tablas de semáforos o bloquear toda la tabla al insertar. Consulte la documentación de MySQL para obtener más información sobre el bloqueo de tablas completas o el uso de tablas de semáforos.
Solo mis 2 centavos...