Comment produire des lectures fantômes?

en utilisant "read reproductible" il devrait être possible de produire une lecture fantôme, mais comment? J'en ai besoin pour un exemple d'enseignement aux élèves CS.

je pense que je dois faire un "SELECT ... Où x< = 888" sur un champ x non indexé, avec une limite supérieure 888 absente, puis sur une autre connexion insérez une nouvelle ligne avec une valeur juste en dessous de 888.

Sauf que ça ne fonctionne pas. Ai-je besoin d'une très grande table? Ou quelque chose d'autre?

21
demandé sur Martin Smith 2011-03-26 22:55:09

6 réponses

Erik,

je viens juste de le tester avec un très grand nombre de lignes.

vous ne trouverez jamais de fantômes sur InnoDB mysql avec read commited ou un niveau d'isolement plus restreint. Il est expliqué dans la documentation:

REPEATABLE READ: Pour les lectures cohérentes, il y a une importante différence entre le niveau d'isolation READ committed: Toutes les lectures cohérentes au sein de la même transaction lire l'instantané établi par la première lecture de. Ce par convention, on entend que si vous émettez plusieurs énoncés simples (non-verrouillage) de sélection dans le cadre d'une même opération, ces énoncés de sélection sont également cohérents les uns par rapport aux autres. Voir La Section 13.6.8.2, "Consisting Nonlocking Reads".

mais vous ne pouvez pas aussi trouver de fantômes dans le niveau d'isolement de Read commited: c'est nécessaire parce que les "rangées de fantômes" doivent être bloquées pour que la réplication MySQL et la récupération fonctionnent.

informations plus détaillées: http://dev.mysql.com/doc/refman/5.1/en/set-transaction.html

je pense que vous aurez besoin pour passer à une autre base de données de la marque pour montrer les fantômes de vos élèves. J'utilise à la fois MSSQLSERVER et Oracle.

Bien ... sa pitié pour votre première question.

14
répondu dani herrera 2013-08-26 16:35:22

possibilité de reproduire des lectures de fantômes pour le moteur InnoDB pour le niveau d'isolement la lecture reproductible est discutable, parce que InnoDB utilise contrôle de simultanéité Multiversion - pour chaque ligne, Le moteur du MVCC connaît les numéros de transaction lorsque la ligne a été insérée et supprimée et peut reproduire l'historique des mises à jour de la ligne.

ainsi, toutes les instructions SELECT consécutives afficheront l'état du tableau au début de la transaction, à l'exception des lignes qui ont été insérées, supprimées ou mises à jour par le même ce qui suit: transaction. Aucune nouvelle rangée engagée par d'autres transactions n'apparaîtra, parce qu'elles auront des numéros de transaction d'insertion plus grands que ceux de cette transaction, et la gamme de rangées n'a pas d'importance ici.

j'ai pu reproduire des lectures de fantômes pour le niveau d'isolement répétable lire pour Apache Derby base de données, parce qu'elle n'utilise pas le contrôle de concurrence multiversion (version 10.8.2.2 au moment de la rédaction de cette réponse).

pour se reproduire, régler correctement niveau de transaction (dans le client SQL D'ij-Derby):

-- Set autocommit off
autocommit off;
-- Set isolation level corresponding to ANSI REPEATABLE READ
set isolation rs;

T1:

SELECT * FROM TableN;

T2:

INSERT INTO TableN VALUES(55, 1);
COMMIT;

T1 de nouveau:

SELECT * FROM TableN;

maintenant T1 devrait voir une ligne de plus;

4
répondu Nulldevice 2011-11-28 12:21:05

le" fantôme lu " dans MySQL au niveau D'isolement RR est caché en profondeur, mais peut encore le reproduire. Voici les étapes:

  1. create table ab(un int primary key, int b);

  2. Tx1:

    commencer;

    sélectionnez * à partir de l'ab; // ensemble vide

  3. Tx2:

    commencer;

    insert into ab valeurs(1,1);

    engager;

  4. Tx1:

    sélectionnez * à partir de l'ab; // ensemble vide, qui devrait fantômes disparus.

    mettre à jour ab ensemble b = 2 où a = 1; // 1 ligne affectée.

    sélectionner * à partir de ab; / / 1 rangée. phantom lire ici!!!!

    s'engager;

4
répondu ColinBinWang 2016-12-16 06:32:04

InnoDB devrait protéger contre les lectures fantômes, comme d'autres l'ont écrit.

mais InnoDB a un comportement bizarre différent lié au verrouillage. Lorsqu'une requête acquiert un verrou, il acquiert toujours le verrou sur la version la plus récente de la ligne. Essayez donc le suivant

CREATE TABLE foo (i INT PRIMARY KEY, val INT);
INSERT INTO foo (i, val) VALUES (1, 10), (2, 20), (3, 30);

puis en deux sessions simultanées (ouvrez deux fenêtres de terminal):

-- window 1                               -- window 2
START TRANSACTION;
                                          START TRANSACTION;

                                           SELECT * FROM foo;

 UPDATE foo SET val=35 WHERE i=3;

                                           SELECT * FROM foo;

cela devrait indiquer val = 10, 20, 30 dans les deux sélections, puisque répétable-READ signifie que la seconde fenêtre ne voit que les données telles qu'elles existaient au début de la transaction.

par contre:

                                           SELECT * FROM foo FOR UPDATE;

la deuxième fenêtre attend pour acquérir la serrure de la rangée 3.

COMMIT;

maintenant le SELECT dans la deuxième fenêtre termine, et affiche les lignes avec val = 10, 20, 35, parce que le verrouillage de la ligne fait que le SELECT voit la version la plus récente engagée. Les opérations de verrouillage dans InnoDB agissent comme si elles étaient exécutées en lecture-engagement, quel que soit le niveau d'isolement de la transaction.

vous pouvez même alterner:

                                           SELECT * FROM foo;

                                           SELECT * FROM foo FOR UPDATE;

                                           SELECT * FROM foo;

                                           SELECT * FROM foo FOR UPDATE;
1
répondu Bill Karwin 2016-12-16 06:44:34

Phantom lit peut se produire parce qu'il n'existe pas de serrures de portée, alors un exemple est (pseudocode):

Thread1

Transaction 1

Update TableN set X=2 where X=1

wait(s1)
Select TableN where X=1

Commit 

thread2

Transaction 2:

insert into tableN(id, X) values(55,1)
commit;
notify(s1)

dans wikipedia il y a un autre exemple de phantom lit: Phantom lit|wikipedia

l'important ici est la syncronisation des transactions, vous pouvez utiliser des points de synchronisation.

EDIT exemple utilisant la fonction de sommeil mysql(non testé):

DÉBUT DE LA TRANSACTION; Mettre à jour la table X = 2 où X=1 SÉLECTIONNER SLEEP (30) À PARTIR DE DUAL; sélectionnez TableN où X=1; COMMIT;

--dans l'autre fil, avant 20 secondes;

DÉBUT DE LA TRANSACTION; insérez dans TableN(id, X) des valeurs(55,1);

COMMIT;

0
répondu CronosNull 2011-04-24 15:36:15

pour compléter la bonne réponse de Dani, vous pouvez utiliser Microsoft Sql Server pour montrer ce comportement à vos étudiants.

Sql Server affiche des lectures fantômes dans le niveau d'isolement de lecture répétable tel que réclamé par la documentation ici.

Postgres souscrit à la même notion que InnoDb comme expliqué ici. Avec Postgres aussi, aucune lecture fantôme n'arrive en lecture répétitive et est donc également inadaptée à votre but didactique.

Sql Server offre un autre niveau d'isolation, snapshot, qui fait ce que MySql InnoDb et Postgres font dans read répétable (qui est une implémentation sans serrure, basée sur la version de Read répétable sans Phantom lit, mais qui n'est pas sérialisable).

Sql Server Express est gratuit bien que vous ayez besoin d'une machine Windows. Vous pouvez également obtenir vous-même un compte Windows Azure et de montrer ce comportement avec Sql Azure en ligne.

0
répondu John 2013-12-10 17:04:52