web-dev-qa-db-fra.com

Principes de base de la transaction. Quel est le résultat de 2 transactions fonctionnant simultanément?

J'ai une question plutôt fondamentale sur les transactions.
[.____] supposons une table Account avec un montant de colonne. Maintenant, nous avons le code suivant:

BEGIN  
$amount = SELECT amount FROM ACCOUNT WHERE id = 123;  
$amount = $amount - 100;  
UPDATE ACCOUNT SET amount = $amount WHERE id = 123;    
COMMIT

Maintenant, si cet extrait se déroule simultanément par 2 transactions, T1 et T2, que se passeront-ils?
[.____] Je sais que dans MySQL par défaut, le niveau d'isolement est REPEATABLE READ.
[.____] Alors disons que le montant initialement est de 500.
[.____] alors lorsque les 2 transactions finissent, le montant final sera-t-il 300 ou 100?
[.____] Je veux dire quand ils commencent tous les deux lire de la table que je suppose est une serrure partagée.
[.____] Quand on met à jour la table, il obtient un droit de verrou exclusif? Alors, qu'advient-il de l'autre transaction? Procédera-t-il avec le montant "View" quand il a commencé I.E. 500?

4
Jim

Il n'y a pas de verrou partagé implicite dans lecture répétable niveau d'isolement.

Vous devez modifier la séquence de transaction comme suit:

Niveau d'isolement

Vous pouvez passer à la [~ # ~] sérialisable [~ # ~ ~] niveau d'isolement et désactiver l'autocommande. De cette façon, la ligne est verrouillée en mode partagé implicitement.

Si vous voulez rester avec lecture répétable ou lu engagée , vous devrez appeler Sélectionnez ... pour mettre à jour manuellement avant de faire la mise à jour.

Query (suggestion facultative)

Vous devriez également expérimenter avec

UPDATE ACCOUNT SET amount = amount - 100 WHERE id = 123; 

avec l'autocommande handicapés et SÉRIALISABLE niveau d'isolement.

Je l'ai suggéré parce que vous faites deux questions (sélectionnez et mettez à jour) pour modifier le montant. Vous pourriez simplement le faire avec une requête.

Ta question

Étant donné que le verrouillage lit et non implicitement avec lecture répétable , il y a une possibilité de 500 étant utilisée deux fois.

Tu as demandé

Est-il possible de définir le niveau d'isolement à un niveau de connexion? I.e. Ne touchez pas le niveau d'isolement global?

Oui, Vous pouvez définir le niveau d'isolation dans la session :

SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL   {
    REPEATABLE READ
  | READ COMMITTED
  | READ UNCOMMITTED
  | SERIALIZABLE    }
2
RolandoMySQLDBA

Je pense que le montant sera de 400 après deux transactions commettes.

Testons. Session 1:

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT amount FROM ACCOUNT WHERE id = 123;
+--------+
| amount |
+--------+
|    500 |
+--------+
1 row in set (0.00 sec)

Session n ° 2:

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT amount FROM ACCOUNT WHERE id = 123;
+--------+
| amount |
+--------+
|    500 |
+--------+
1 row in set (0.00 sec)

Session 1

mysql> UPDATE ACCOUNT SET amount = 400 WHERE id = 123;
Query OK, 0 rows affected (2.63 sec)
Rows matched: 1  Changed: 0  Warnings: 0

Session n ° 2

mysql> UPDATE ACCOUNT SET amount = 400 WHERE id = 123;
... waiting for a RW lock held by session #1

Session 1

mysql> commit;

Session n ° 2

Query OK, 0 rows affected (2.63 sec)
Rows matched: 1  Changed: 0  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

Soit une session:

mysql> SELECT amount FROM ACCOUNT WHERE id = 123;
+--------+
| amount |
+--------+
|    400 |
+--------+
1 row in set (0.00 sec)
2
akuzminsky