J'ai vu beaucoup de questions similaires mais je ne suis toujours pas tout à fait sûr d'avoir raison.

Nous avons une application qui lance un job pour envoyer en masse de nombreux messages. L'état de livraison des messages est reçu ultérieurement par lots et sans ordre particulier.

La structure de la table est comme: -

CREATE TABLE `message` (
  `pk` char(32) NOT NULL DEFAULT '',
  `job_id` varchar(40) DEFAULT NULL,
  `status` varchar(40) DEFAULT NULL,
  `update_date` datetime DEFAULT NULL,
  PRIMARY KEY (`pk`),
  KEY `job_id` (`job_id`),
  KEY `status` (`status`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Les enregistrements sont initialement créés avec status défini sur null. Sa valeur devrait passer de null à sent, puis à delivered. Les instructions ci-dessous sont utilisées pour mettre à jour les enregistrements.

Lorsque l'état à définir est - delivered

Update message SET status = 'delivered', update_date = Now()
    WHERE job_id = :someId

Lorsque l'état à définir est - sent

Update message SET status = 'sent', update_date = Now()
    WHERE job_id = :someId AND status IS NULL

Le problème est qu'il est possible qu'il y ait deux threads essayant simultanément de définir le status du même enregistrement sur «envoyé» et «livré». Dans ce cas, «livré» est le statut final, nous voudrions donc que cela finisse par gagner.

Les déclarations ci-dessus garantiront-elles cela dans MySql ou MariaDB?

0
AppleGrew 20 nov. 2018 à 20:49

3 réponses

Meilleure réponse

Oui, à la fois dans MySQL et MariaDB (et probablement dans n'importe quelle base de données SQL). les mises à jour de la même ligne sont atomiques.

  • «envoyé» écrasera NULL, mais pas «livré»
  • «livré» écrasera NULL et «envoyé»

Voici ce que tu veux. Assurez-vous simplement que le message avec le job_id donné existe avant de le mettre à jour :)

0
Vladislav Vaintroub 21 nov. 2018 à 16:24
Update message SET status = 'delivered', update_date = Now()
    WHERE job_id = :someId
      AND status = 'sent'    -- add this??

(Il ne devrait y avoir aucune différence entre MySQL et MariaDB dans ce domaine.)

0
Rick James 20 nov. 2018 à 18:12
Update message SET status = 'sent', update_date = Now()
WHERE job_id = :someId
AND status != 'delivered';
0
Croco 20 nov. 2018 à 18:50