En supposant qu'il existe une contrainte unique sur la colonne name, chaque insert
va acquérir un verrou. Tout thread qui tente de l'insérer une deuxième fois simultanément attendra jusqu'à ce que le 1er insert
réussisse ou échoue (tx commit ou rolls back).
Si la première transaction réussit, la deuxième transaction échouera avec une violation de clé unique. Alors vous savez qu'il existe déjà.
S'il y a une insertion par transaction, c'est OK. S'il y a plus d'une insertion par transaction, vous risquez de créer un blocage.
Chaque thread passera un nom de chaîne - où ce nom existe dans la table, la base de données doit renvoyer l'identifiant pour la ligne, où le nom ne existe déjà, le nom doit être inséré et l'identifiant retourné.
Donc, dans l'ensemble, l'algo est comme ceci:
1 read row with name
2.1 if found, return row id
2.2 if not found, attempt to insert
2.2.1 if insert succeeds, return new row id
2.2.2 if insert fails with unique constraint violation
2.2.2.1 read row with name
2.2.2.2 read should succeed this time, so return row id
Parce qu'il peut y avoir une haute affirmation sur l'index unique, le insert
peut bloquer pendant un certain temps. Dans ce cas, la transaction peut expirer. Faites un test de stress et réglez la configuration jusqu'à ce qu'elle fonctionne correctement avec votre charge.
En outre, vous devez vérifier si vous obtenez une exception de de violation de contrainte unique ou une autre exception.
Et encore, cela ne fonctionne que s'il y a un insert par transaction, sinon il peut deadlock .
, vous pouvez également essayer de lire la ligne à l'étape 1 avec « select * for update
». Dans ce cas, il attend qu'une insertion simultanée soit validée ou réussie. Cela peut réduire légèrement la quantité d'erreur à l'étape 2.2.2 en raison de la contention sur l'index.
merci, bonne réponse - encore une chose, puis-je détecter cette exception de contrainte unique en sql? ou dois-je le laisser revenir en arrière pour être détecté en Java? – MalcomTucker
oh, et une autre question - ai-je raison de penser que mysql mettra en cache les résultats des requêtes, donc en théorie si un nom a déjà été inséré et retourné une fois, je devrais pouvoir utiliser le cache pour retourner les noms existants? – MalcomTucker
et désolé, encore une question - je suppose que l'algo que vous avez décrit ci-dessus peut tout être fait en SQL, mais dois-je gérer manuellement les verrous de table, ou mysql le fera pour moi? merci pour le conseil :) – MalcomTucker