Uniqueness med InnoDB
Jeg er forvirret :)Jeg prøver at lave et simpelt uniqueness check med InnoDB og
dens låse/transaktions mekanismer:
Eksisterer der en bruger med email adressen 'b'?
Hvis nej, så indsæt ham.
Hvordan laves dette således at 2 processer ikke kan konflikte?
(og uden brug af lock tables).
Se følgende, hvor mysql_1 godt nok er sikker på at kunne
indsætte brugeren med email adressen 'b', men hvor mysql_2
fejler med en deadlock besked. Jeg ville gerne at mysql_2
slet ikke måtte udføre sin første select.
mysql_1 afspejler altså én process og mysql_2 en anden process.
Benytter repeatable read som transaktions niveau.
mysql_1> describe users;
+----------+-----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+-----------------------+------+-----+---------+----------------+
| id | mediumint(8) unsigned | | PRI | NULL | auto_increment |
| address | mediumtext | YES | | NULL | |
| phone | varchar(255) | YES | | NULL | |
| mobile | varchar(255) | YES | | NULL | |
| email | varchar(255) | | UNI | | |
| password | varchar(32) | | | | |
| notes | mediumtext | YES | | NULL | |
| status | enum('user','admin') | | | user | |
| name | varchar(255) | | | | |
+----------+-----------------------+------+-----+---------+----------------+
9 rows in set (0.01 sec)
mysql_1> delete from users;
Query OK, 2 rows affected (0.00 sec)
mysql_1> begin;
Query OK, 0 rows affected (0.01 sec)
mysql_1> select * from users where email = 'b' for update;
Empty set (0.00 sec)
mysql_2> select * from users where email = 'b' for update;
Empty set (0.00 sec)
mysql_1> insert into users set email = 'b';
mysql_2> insert into users set email = 'b';
mysql_2> ERROR 1213: Deadlock found when trying to get lock; Try restarting transaction
mysql_1>
Query OK, 1 row affected (11.12 sec)
mysql_1> commit;
Query OK, 0 rows affected (0.00 sec)
mysql_1> select * from users;
+----+---------+-------+--------+-------+----------+-------+--------+------+
| id | address | phone | mobile | email | password | notes | status | name |
+----+---------+-------+--------+-------+----------+-------+--------+------+
| 11 | NULL | NULL | NULL | b | | NULL | user | |
+----+---------+-------+--------+-------+----------+-------+--------+------+
1 row in set (0.00 sec)
Endvidere siger nederste paragraf på
http://dev.mysql.com/doc/mysql/en/InnoDB_Next-key_locking.html,
at sådan et check kan laves med bare lock in share mode. Hvordan det
(i relation til ovenstående eksempel)?
Problemet med at gøre det, jeg prøver, tror jeg er, at innodb intet
låser idet resultatsættet er tomt. Og således kan mysql_2 fint udføre
sin første select.
