μ΄ κΈμμλ MySQLμ μ¬μ©ν΄, νΉμ λ μ½λμ λ½μ΄ κ±Έλ¦° μνμμ λ€λ₯Έ νΈλμμ μ΄ ν΄λΉ λ μ½λμ μ΄λ μμ κΉμ§ νμ©νλμ§ μ€νν΄λ³΄κ³ , MySQL λ΄λΆμμ μΈμ λ½μ μ¬μ©νλμ§ μμ보며 λΉκ΄μ λ½μ λν΄ νμμ μΈ μ΄μ λ₯Ό μκΈ°νλ κ°μΈμ μΈ κΈμ λλ€.
μΆκ°λ‘ Real MySQL μ μ½κ³ , 곡μ λ½κ³Ό λ°°ν λ½μ λ°°κ²½ μ§μμ΄ μλ λΆλ€μ΄ μ½κ² μ΄ν΄ λ κ² κ°μΌλ©°, κ²°λ‘ μ λ§μΉλ©°.. μ μ 리ν΄λμμ΅λλ€.
λͺ©μ°¨λ λ€μ μμλ‘ μ§νλ©λλ€.
- ν νΈλμμ μμ 곡μ λ½/λ°°ν λ½ νλ μ, λ€λ₯Έ νΈλμμ μμ κ°λ₯ν 쿼리 μκ°
- 곡μ λ½/λ°°ν λ½ μ¬μ© μ, λ€λ₯Έ νΈλμμ μμ μ°κΈ° μμ μ΄ λκΈ°νλ μ΄μ
- UPDATE / DELETE 쿼리 μ WHERE μ μ μΈλ±μ€ μ¬λΆμ μ€μμ±
- MySQL8.0 Repetable Read μμ Phantom Read κ° λ°μνλ κ²½μ°
- UPDATE / DELETE 쿼리λ₯Ό μ€ν ν λ, MySQL μ΄ λ΄λΆμ μΌλ‘ λ°°ν λ½μ μ¬μ©νμ§λ§ select...for update(JPAμ λΉκ΄μ λ½)μ μ¬μ©νλ μ΄μ
- λ§μΉλ©°..
1. ν νΈλμμ μμ 곡μ λ½/λ°°ν λ½ νλ μ, λ€λ₯Έ νΈλμμ μμ κ°λ₯ν 쿼리 μκ°
μ€ν νκ²½
- DBMS: Mysql 8.0
- 격리 μμ€: Repeatable Read
μ€νμ μ°μΌ ν μ΄λΈκ³Ό λ°μ΄ν°μ λλ€.
CREATE TABLE example (
id BININT,
name VARCHAR(255)
);
INSERT INTO example (id, name) VALUES (1, "a"); // 1λ² row
INSERT INTO example (id, name) VALUES (2, "b"); // 2λ² row
μ€ν 1 : λ°°νλ½ & 곡μ λ½
- μΌμͺ½ νΈλμμ
: 1λ² νμ λν΄ λ°°νλ½(Exclusive Lock)μ νλν©λλ€.
- select ... for update
- μ€λ₯Έμͺ½ νΈλμμ
: 1λ² νμ λν΄ κ³΅μ λ½(Shared Lock)μ μλν©λλ€.
- LOCK IN SHARE MODE (Mysql 5.7λ²μ μ΄ν)
- select ... for share ( Mysql 8.0λ²μ μ΄μ)
κ²°κ³Ό
- μ€λ₯Έμͺ½ νΈλμμ μ΄ κ³΅μ λ½μ νλνμ§ λͺ»νκ³ λκΈ° μνμ λ€μ΄κ°μ΅λλ€.
- λ°°νλ½μ΄ κ±Έλ¦° μνμμλ 곡μ λ½λ νλν μ μμΌλ―λ‘, λ°°νλ½ μμ λΉμ°ν νλν μ μμ΅λλ€.
μ€ν 2 : λ°°νλ½ & κΈ°λ³Έ SELECT
- μΌμͺ½ νΈλμμ : 1λ² νμ λν΄ λ°°νλ½μ νλν©λλ€.
- μ€λ₯Έμͺ½ νΈλμμ : 1λ² νμ λν΄ SELECT 쿼리λ₯Ό μ€νν©λλ€.
κ²°κ³Ό
- κΈ°λ³Έμ μΈ SELECT 쿼리λ μ±κ³΅μ μΌλ‘ μ€νλμμ΅λλ€.
- μ¦, λ°°νλ½μ΄ κ±Έλ¦° μνμμλ μ½κΈ° μμ (SELECT)μ νμ©λ©λλ€.
- λ°°νλ½μμ μ½κΈ°κ° νμ© μλλ€λ λ§μ Locking Read κ° μλλ κ²μ΄μ§ Non-Locking Read λ κ°λ₯ν©λλ€. Locking Read κ° κ³΅μ λ½, λ°°νλ½κ°μ΄ λ½μ μ¬μ©ν΄μ λ μ½λλ₯Ό μ§μ μ½λ κ²μ΄κ³ , Non-Locking Read λ μΌλ°μ μΈ select λ¬Έμ μλ―Ένλ©° μ€λ μ·μ μν μΈλ μμμ μ½λ κ²μ λλ€.
μ€ν 3 : λ°°νλ½ & UPDATE/DELETE
- μΌμͺ½ νΈλμμ : 1λ² νμ λν΄ λ°°νλ½μ νλν©λλ€.
- μ€λ₯Έμͺ½ νΈλμμ : 1λ² νμ λν΄ UPDATE λλ DELETE 쿼리λ₯Ό μ€νν©λλ€.
κ²°κ³Ό
- μ€λ₯Έμͺ½ νΈλμμ μ λκΈ° μνμ λ€μ΄κ°μ΅λλ€.
- λ°°νλ½μ΄ κ±Έλ¦° μνμμλ μ°κΈ° μμ (UPDATE, DELETE)μ΄ μ°¨λ¨λ©λλ€.
μ€ν 4 : 곡μ λ½ & SELECT/UPDATE/DELETE
- μΌμͺ½ νΈλμμ : 1λ² νμ λν΄ κ³΅μ λ½(Shared Lock)μ νλν©λλ€.
- μ€λ₯Έμͺ½ νΈλμμ : 1λ² νμ λν΄ SELECT, UPDATE, λλ DELETE 쿼리λ₯Ό μ€νν©λλ€.
κ²°κ³Ό
- SELECT 쿼리λ μ μ μ€νλμμ΅λλ€.
- νμ§λ§ UPDATEμ DELETE 쿼리λ λκΈ° μνμ λ€μ΄κ°μ΅λλ€.
μ€ν5 : 곡μ λ½ & INSERT
INSERT μμλ μ€νμ΄ μ½κ° λ€λ¦ λλ€.
μ€νμ μ¬μ©λ λ μ½λμ λλ€.
// example ν
μ΄λΈμ 3κ°μ λ μ½λ μ‘΄μ¬, id λ PK
mysql> select * from example;
+-----+------+
| id | name |
+-----+------+
| 1 | r |
| 2 | b |
| 500 | a |
+-----+------+
μ€ν 5-1. INSERT κ° λκΈ°νμ§ μμ λ μ λλ€.
1λ² νΈλμμ μμ idκ° 1λΆν° 2κΉμ§μΈ id μ 곡μ λ½μ νλνλ, id κ° 1κ³Ό 2μΈ λ μ½λμ λ μ½λ λ½μ΄ κ±Έλ €μμ΅λλ€.
// νΈλμμ
1μμ idκ° 1λΆν° 2κΉμ§ 곡μ λ½ νλ
mysql> select * from example where id between 1 and 2 for share;
+----+------+
| id | name |
+----+------+
| 1 | r |
| 2 | b |
+----+------+
// REC_NOT_GAPμ λ μ½λ μ체λ₯Ό μ κ·Έμ§λ§, κ°(Gap)μ μ κ·Έμ§ μλ μ κΈμ μλ―Έλ‘ ν΄λΉ λ μ½λλ§ λ³΄νΈνκ³ , μλ‘μ΄ λ μ½λ μ½μ
μ νμ©ν©λλ€.
// id κ° 1κ³Ό 2μΈ λ μ½λκ° κ³΅μ λ½μΈ λ μ½λ λ½μ νλνμ΅λλ€.
mysql> select * from performance_schema.data_locks;
+--------+------------------------------------------------------------------------+
| ENGINE | ... | INDEX_NAME | LOCK_TYPE | LOCK_MODE | LOCK_STATUS | LOCK_DATA |
+--------+------------------------------------------------------------------------+
| INNODB | ... | NULL | TABLE | IS | GRANTED | NULL |
| INNODB | ... | PRIMARY | RECORD | S | GRANTED | 2 |
| INNODB | ... | PRIMARY | RECORD | S,REC_NOT_GAP | GRANTED | 1 |
+--------+------------------------------------------------------------------------+
2λ² νΈλμμ μμ idκ° 1κ³Ό 2λ₯Ό λ²μ΄λλ μμμ idκ° 10κ³Ό 501μΈ λ μ½λλ₯Ό INSERTνκ³ , μ±κ³΅νμ΅λλ€.
mysql> insert into example (id, name) values (10, "c");
Query OK, 1 row affected (0.00 sec)
mysql> insert into example (id, name) values (501, "c");
Query OK, 1 row affected (0.00 sec)
μ€ν 5-2. INSERT κ° λκΈ°ν λ μ λλ€.
νΈλμμ 1μμ id κ° 2 λΆν° 500 μ¬μ΄μΈ λ μ½λλ₯Ό μ‘°ννλ©° 곡μ λ½μ νλν©λλ€.
// νΈλμμ
1μμ idκ° 2λΆν° 500κΉμ§ 곡μ λ½ νλ
mysql> select * from example where id between 2 and 500 for share;
+----+------+
| id | name |
+----+------+
| 2 | b |
| 500 | a |
+----+------+
// LOCKμ΄ κ±Έλ¦° λ°μ΄ν°μ supremum pseudo-record κ° μΆκ°λμμ΅λλ€.
mysql> select * from performance_schema.data_locks;
+--------+-------------------------------------------------------------------------------------+
| ENGINE | ... | INDEX_NAME | LOCK_TYPE | LOCK_MODE | LOCK_STATUS | LOCK_DATA |
+--------+-------------------------------------------------------------------------------------+
| INNODB | ... | NULL | TABLE | IS | GRANTED | NULL |
| INNODB | ... | PRIMARY | RECORD | S | GRANTED | supremum pseudo-record |
| INNODB | ... | PRIMARY | RECORD | S | GRANTED | 500 |
| INNODB | ... | PRIMARY | RECORD | S,REC_NOT_GAP | GRANTED | 2 |
+--------+-------------------------------------------------------------------------------------+
νΈλμμ 2μμ μ€ν 5-1κ³Ό λ¬λ¦¬ INSERT κ° μ€ν¨νμ΅λλ€. μ€ν 5-11μ²λΌ λ μ½λ λ½μ΄ λ²μ΄λ μμμΈ id=501 μΈ μμμ INSERT λ₯Ό μλνμ§λ§, λ½ νμμμμ΄ λ°μνμ΅λλ€.
μ€ν5-1μ²λΌ 곡μ λ½ μμ λ°μ INSERT λ₯Ό μλνμ§λ§, μ€ν 5-2 λ§ μ€ν¨ν μ΄μ κ° λ¬΄μμΌκΉμ??
mysql> insert into example (id, name) values (100, "z");
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into example (id, name) values (501, "z");
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
LOCK_DATE μ supremum pseudo-record κ° μκΈ° λλ¬Έμ λλ€. supremum pseudo-record λ μΈλ±μ€ νμ΄μ§μ λμ λνλ΄λ κ°μμ λ μ½λλ‘ μ¬μ€μ "κ° μ κΈ" μν μ νκΈ° λλ¬Έμ λλ€.
κ²°κ³Ό
- supremum pseudo-record κ°μ DBλ΄λΆμμ μ νκ² λλλ° μ΄μ λ°λΌ INSERT λ¬Έμ΄ λ½μ μν΄ λκΈ°ν μλ, μλ μλ μκ² λ©λλ€.
μ€ν κ²°λ‘
κ²°κ³Ό | 곡μ λ½ | λ°°ν λ½ | κΈ°λ³Έ select | update / delete | insert |
곡μ λ½ | O | X | O | X | λ μ½λ λ½μΌ κ²½μ° O κ° λ½μ΄ κ±Έλ €μμ κ²½μ° X |
λ°°ν λ½ | X | X | O | X |
λ½ μ¬μ© μ, λ€μν μν©μ μμ΄μ μ΄λ€ μμ μ΄ νμ©λκ³ , λκΈ°νλμ§ μμλ΄€μ΅λλ€.
μ΄λ₯Ό ν΅ν΄ update / delete λ λ½μ μ¬μ©ν κ² κ°λ€λ μκ°μ΄ λ€λ©°, DBμμ μΈμ λ½μ μ¬μ©νλμ§ μ°Ύμλ΄€μ΅λλ€.
* μ°Έκ³ - λκ΄μ λ½μ JPAμμ μ 곡νλ κΈ°λ₯μΌλ‘ DBμ 곡μ λ½κ³Ό 무κ΄ν©λλ€
2. 곡μ λ½/λ°°ν λ½ μ¬μ© μ, λ€λ₯Έ νΈλμμ μμ μ°κΈ° μμ μ΄ λκΈ°νλ μ΄μ
1. FOREIGN KEY μ μ½ μ‘°κ±΄μ΄ ν μ΄λΈμ μ μλμ΄ μλ κ²½μ°, INSERT / UPDATE / DELETE μμ μ μνν΄λ λλμ§ μ μ½ μ‘°κ±΄μ νμΈνκΈ° μν΄ μ‘°ννλ λ μ½λλ€μ λν΄ κ³΅μ λ μ½λ μμ€ λ½(shared record-level locks)μ μ€μ ν©λλ€.
- If a FOREIGN KEY constraint is defined on a table, any insert, update, or delete that requires the constraint condition to be checked sets shared record-level locks on the records that it looks at to check the constraint. InnoDB also sets these locks in the case where the constraint fails.
2. μ λν¬ ν€λ μ€λ³΅λ κ°μ 체ν¬ν λλ μ½κΈ° μ κΈμ, μ°κΈ° ν λλ μ°κΈ° μ κΈμ μ¬μ©νλ©° μ΄ κ³Όμ μμ λ°λλ½μ΄ μμ£Ό λΉλ²ν λ°μν©λλ€.(Real MySQL 8.0 μΆμ²)
3. UPDATE μ DELETE μνμμλ λ΄λΆμ μΌλ‘ λ½μ μ¬μ©ν©λλ€. μ΄ λ, μ¬μ©λλ λ½μ μ’ λ₯λ 쿼리λ₯Ό μ€ννκΈ° μν΄ μ¬μ©λλ μΈλ±μ€μ WHERE 쑰건μ λ°λΌ λ μ½λ λ½μΈμ§, κ° λ½μΈμ§ λ₯μ€νΈ ν€ λ½μΈμ§ λ€λ₯΄κ² μ§λ§ μ΄λ€μ κ²°κ΅ λ°°ν λ½μ μ¬μ©ν©λλ€.
- For locking reads (SELECT with FOR UPDATE or FOR SHARE), UPDATE, and DELETE statements, the locks that are taken depend on whether the statement uses a unique index with a unique search condition or a range-type search condition.
- UPDATE ... WHERE ... sets an exclusive next-key lock on every record the search encounters. However, only an index record lock is required for statements that lock rows using a unique index to search for a unique row.
- μλ μ¬μ§μ νΈλμμ μ μ΄κ³ , update 쿼리λ₯Ό μ€ν ν λ½μ΄ κ±Έλ €μλ λ°μ΄ν°λ₯Ό 보λ λͺ λ Ήμ΄κΉμ§ μ€νν μ¬μ§μ λλ€. LOCK_STATUS κ° GRATED λ λ½μ νλν μνμμ μλ―Ένλ©°, LOCK_DATE λ λ μ½λμ ν΄μκ°μ΄λ©°, LOCK_MODE λ X λ‘ λ°°νλ½μ μλ―Έν©λλ€. κ·Έλ¦¬κ³ , LOCK_TYPE μ ν΅ν΄ λ½ μ νμ λ μ½λ λ½μμ νμΈνμ΅λλ€. μ¦, update 쿼리λ λ°°ν λ½μ΄ 걸립λλ€.
4. MySQL 8.0 μ InnoDB μ€ν λ¦¬μ§ μμ§μ λ μ½λκ° μμ²΄κ° μλλΌ μΈλ±μ€μ λ μ½λλ₯Ό μ κ·Έκ² λ©λλ€. μΈλ±μ€κ° νλλ μλ ν μ΄λΈμ΄λλΌλ λ΄λΆμ μΌλ‘ μλ μμ±λ ν΄λ¬μ€ν° μΈλ±μ€λ₯Ό μ΄μ©ν΄ λ μ½λλ₯Ό μ κΈλλ€.
μΆμ²
- https://dev.mysql.com/doc/refman/8.4/en/innodb-locks-set.html
- https://dev.mysql.com/doc/refman/8.0/en/create-table-foreign-keys.html#foreign-key-locking
- Real MySQL 1κΆμ νΈλμμ κ³Ό μ κΈ
μ¦, MySQL 8.0μμλ μΈλ ν€ μ μ½ μ‘°κ±΄κ³Ό UPDATE / DELETE μμλ λ½λ€μ΄ λ΄λΆμ μΌλ‘ μ¬μ©λ©λλ€. μ΄λ‘ μΈν΄ μ μ€νμμ ν νΈλμμ μ΄ λ°°ν λ½/곡μ λ½μ νλνμ λ, λ€λ₯Έ νΈλμμ μμ λ¨μ INSERT / UPDATE / DELETE μμ μ μννλλΌλ MySQL λ΄λΆμ μΌλ‘ μλμΌλ‘ μμ±λ ν΄λ¬μ€ν° μΈλ±μ€λ₯Ό μ΄μ©ν΄ λ μ½λ λ½μ νλνκ³ μ νκ³ , λ μ½λ λ½μ λ°°ν λ½μ΄κΈ° λλ¬Έμ λκΈ° μνμ λ€μ΄κ°λ κ²μ λλ€.
μ¦, MySQL 8.0 μμλ λμμ± μ μ΄λ₯Ό μν΄ MVCC μ λ½μ μ§μν©λλ€. MVCCλ κΈ°λ³Έ select 쿼리μ κ°μ΄ μ κΈ μμ΄ μ½κΈ°λ₯Ό ν΅ν΄ μ½κΈ° νΈλμμ μ λΉ λ₯΄κ² μ²λ¦¬νλ©°, 곡μ /λ°°ν λ½μ μ°κΈ°λ₯Ό μν λμμ± μ μ΄λ₯Ό μν΄ μ¬μ©νλ κ²μΌλ‘ μ 리ν μ μμ΅λλ€.
* INSERT / UPDATE / DELETE μμ μ νλ €λ λ μ½λμ λ²μκ° κ°κ°μ λ μ½λ μμ€μΈμ§, νΉμ λ²μμΈμ§, ν μ΄λΈ μμ€μΈμ§μ λ°λΌ μ¬μ©λλ MySQL λ΄λΆμμ μ¬μ©λλ λ½μ μ’ λ₯λ λ€λ¦ λλ€.
* μΈμ μ΄λ€ λ½μ΄ μ°μ΄λμ§ μμΈν μκ³ μΆλ€λ©΄ μΆμ²μ Locking λΆλΆμ΄λ Real MySQLμ Lock ννΈλ₯Ό μ°Έκ³ νμκΈΈ μΆμ²λ립λλ€.
3. UPDATE / DELETE 쿼리 μ WHERE μ μ μΈλ±μ€ μ¬λΆμ μ€μμ±
λν, MySQLμ UPDATEλ DELETE μμ μ λ΄λΆμ μΌλ‘ λ°°ν λ½μ μ¬μ©νκΈ° λλ¬Έμ WHERE μ‘°κ±΄μ΄ μ€μν©λλ€.
WHERE 쑰건μ μ¬μ©λλ 컬λΌμ μ μ ν μΈλ±μ€κ° μλ κ²½μ°, μ°κΈ° μμ μ ν λ μ½λλΏλ§ μλλΌ λ€λ₯Έ λ μ½λμλ λ½μ΄ 걸릴 μ μκ³ , μ΅μ μ κ²½μ° ν μ΄λΈ λ¨μλ‘ λ½μ΄ 걸릴 μ μμ΅λλ€. μ¦, UPDATE / DELETE 쿼리λ₯Ό μ²λ¦¬ ν λ, WHERE 쑰건μ PKμ κ°μ μΈλ±μ€κ° μλ 컬λΌμ μ¬μ©ν΄μΌ νλ€λ μλ―Έμ λλ€.
WHERE 쑰건μ μΈλ±μ€κ° μλ UPDATE / DELETE μΏΌλ¦¬κ° μ€νλλ©΄ ν μ΄λΈμ λͺ¨λ νμ μ€μΊνκ³ , λΆνμν λ μ½λμλ λ½μ΄ μ€μ λ μ μμ΅λλ€.
μλ₯Ό λ€μ΄, UPDATE / DELETE ... WHERE last_name = "μ’ ν" and first_name = "μ" μ΄λ μΏΌλ¦¬κ° μμ λ, last_name μ΄ "μ’ ν"μΈ λ μ½λκ° 1000건μ΄λΌκ³ κ°μ νκ³ , κ·Έ μ€μμ first_name μ΄ "μ" μ λ§μ‘±νλ λ μ½λκ° λ¨ 1κ°λΌκ³ κ°μ νκ² μ΅λλ€. μ΄ λ, last_name μλ§ μΈλ±μ€κ° μ€μ λμλ€λ©΄ last_name μ΄ "μ’ ν"μ λ§μ‘±νλ 1000건μ λ μ½λμ ν΄λΉνλ μΈλ±μ€μ λ½μ΄ κ±Έλ¦¬κ² λ©λλ€.(* MySQL 8.0μμ λ½μ λ μ½λκ° μλ μΈλ±μ€μ κ²λλ€.)
μ΄ λ, λ μ½λ λ½μ΄ κ±Έλ¦° 1000건μ λ μ½λ μ€, first_name = "μ" μ λ§μ‘±νλ 1건μ λ°μ΄ν°λ₯Ό μ μΈν 999건μ λΆνμνκ² λ½μ΄ κ±Έλ¦¬κ² λμμ΅λλ€. λ§μ½, last_name μλ μΈλ±μ€κ° μλ€λ©΄ last_name="μ’ ν" μ μ°ΎκΈ° μν΄ MySQL μ ν μ΄λΈ ν μ€μΊμ νκ² λ κ²μ΄κ³ , μ΄ κ³Όμ μμ ν μ΄λΈμ λͺ¨λ λ μ½λμλ λ½μ κ±Έκ² λ©λλ€.
μ΄λ¬ν μ΄μ λ‘ UPDATE / DELETE μ μΈλ±μ€κ° μλ 컬λΌμ WHERE 쑰건μ μ μ€μΌλ‘μ¨ λΆνμν λ μ½λμ λ½μ΄ 걸리λ κ²μ λ°©μ§νλ κ²μ΄ μ€μν©λλ€.
λ§μ½, μμμ²λΌ μΈλ±μ€κ° μλ 컬λΌμ WHERE 쑰건μ μ μ€μΌνλ€λ©΄ (last_name , first_name) λ 컬λΌμ λ©ν° μ»¬λΌ μΈλ±μ€λ₯Ό μμ±ν΄μ£Όλ©°, λ λμκ° first_name μ μΉ΄λλ리ν°κ° λ λκΈ° λλ¬Έμ (first_name , last_name) μΌλ‘ μΈλ±μ€λ₯Ό μμ±νλ©° λ½μ λ°©μ§ν μ μμ΅λλ€.
* μΆμ² : Real MySQL 5.3.2 μΈλ±μ€μ μ κΈ
4. MySQL 8.0 Repetable Read μμ λΉκ΄μ λ½ μ¬μ© μ, Phantom Read κ° λ°μνλ κ²½μ°
μΆκ°λ‘, Real MySQL 8.0 μμ select ... for update μ, Phantom Read λ¬Έμ κ° λ°μ ν μλ μλ€λ μ¬μ€ μκ³ κ³μ ¨λμ? 곡μ λ¬Έμμμλ Non-Locking Read μ, λ₯μ€νΈ ν€ λ½μΌλ‘ Phantom Read λ¬Έμ λ₯Ό λ§μ μ μλ€κ³ λμ μμ΅λλ€.
νμ§λ§, λΉκ΄μ λ½μΈ select ... for update κ°μ Locking Read μ, Phantom Read κ° λ°μν κ²½μ°κ° μμ΅λλ€.
Non-Locking Read : μΏΌλ¦¬κ° [1]μΌμͺ½ νΈλμμ μμ select ... for update → [2]μ€λ₯Έμͺ½ νΈλμμ insert μμλ‘ μ§ν λ κ²½μ°
λ¨Όμ , μΌμͺ½ νΈλμμ μμ select ... for update νμ μ€λ₯Έμͺ½ νΈλμμ μμ insert λ₯Ό νλ©΄ μ€λ₯Έμͺ½ νΈλμμ μ λκΈ° μνκ° λλ©° λ μ½λ μ½μ μ μν΄ λ°μνλ phatom read λ λ°μνμ§ μμ΅λλ€.
Locking Read : μΏΌλ¦¬κ° [1]μΌμͺ½ select → [2]μ€λ₯Έμͺ½ insert → [3]μ€λ₯Έμͺ½ commit → [4]μΌμͺ½ select ... for update μμμΌ κ²½μ°
μλ μ¬μ§μ²λΌ 1λ²λΆν° 4λ²κΉμ§ μ°¨λ‘λ‘ μμλλ‘ μμ±νλ μΌμͺ½ νΈλμμ μ΄ κ°μ νΈλμμ μμλ λΆκ΅¬νκ³ , phantom read κ° λ°μν κ²μ νμΈν μ μμ΅λλ€. μ΄λ select ... for update κ° μΈλ μμμ μ½μ§ μκ³ , κΈ°λ³Έ select μ λ¬λ¦¬ ν μ΄λΈ λ μ½λλ₯Ό λ°λ‘ μ½κΈ° λλ¬ΈμΈλ°μ. MVCCκΈ°λ²μ λ°λΌ κΈ°λ³Έ select μΏΌλ¦¬μΈ 1λ²μμλ μΈλμμμ μ½κ³ , λΉκ΄μ λ½μ΄ κ±Έλ¦° 4λ²μμλ μΈλ μμμ΄ μλ ν μ΄λΈ λ μ½λλ₯Ό μ½κ² λ©λλ€.
μ΄λ° 볡μ‘ν μν©μ΄ κ°μ ν μ΄λΈ(μν°ν°)μμ λ°μν μ μλ μΆκΈ°λ νμ§λ§, κ·Έλ λ€κ³ λ 100%λΌλ 보μ₯μ μμΌλκΉ μ΄λ»κ² ν΄μΌν μ§ μ°Έ μ΄λ ΅μ΅λλ€. μ΄λ¬ν μ΄μ λ‘ κΈ λ§μ§λ§μ μ€λͺ λ릴ν λ°, μ κ² μμ΄μ μ΄λ μμΌλ‘ λΉκ΄μ λ½μ μ¬μ©νμ§ μμ μ΄μ μ€ νλκ° λ©λλ€.
5. UPDATE / DELETE 쿼리λ₯Ό μ€ν ν λ, MySQL μ΄ λ΄λΆμ μΌλ‘ λ°°ν λ½μ μ¬μ©νμ§λ§ select...for update(JPAμ λΉκ΄μ λ½)μ μ¬μ©ν΄ λμμ± μ μ΄λ₯Ό νλ μ΄μ
MySQLμ λ΄λΆμ μΌλ‘ UPDATE/DELETE 쿼리λ₯Ό μ€νν λ ν(ν μ΄λΈ)μ λ°°ν λ½μ μ€μ νμ§λ§, μ΄ λ½μ 쿼리 μ€ν μμ μλ§ μ€μ λ©λλ€. μ΄ λλ¬Έμ λ°μ΄ν° μ‘°ν μμ λΆν° λ°μ΄ν°λ₯Ό 보νΈνκΈ° μν΄ select...for updateμ κ°μ λͺ λ Ήμ μ¬μ©ν΄ λ°°νλ½μ μ§μ μ€μ νλ κ²μ΄ νμν©λλ€. λ°μ΄ν° μ‘°ν ν UPDATEλ₯Ό μ€νν λ μ‘°ν μμ λΆν° λ€λ₯Έ νΈλμμ μ΄ λ°μ΄ν°λ₯Ό μμ νμ§ λͺ»νλλ‘ λ°°νλ½μ μ€μ νμ¬ λ°μ΄ν° μΆ©λμ λ§μμΌ ν©λλ€.
κ·Έλ μ§ μμΌλ©΄ μλμ²λΌ Lost Update λ¬Έμ κ° λ°μν©λλ€.
Lost Update λ λ νΈλμμ μ΄ κ°μ row μ λν΄ μ°κΈ° μμ (insert, update, delete)μ μνν λ, ν νΈλμμ μ κ²°κ³Όκ° λ°μλμ§ μλ κ²μ μλ―Έν©λλ€. λ§μ½, λκ³Ό κ΄λ ¨λ νΈλμμ μ΄λΌλ©΄ ν°μΌλκ² μ£ . κ·Έλμ μμ λ λκ³Ό κ΄λ ¨λ κ²μΌλ‘ κ°μ Έμμ΅λλ€.
- update λ¬Έλ§ μ¬μ©ν΄μ Lost Update λ¬Έμ λ°μνλ κ²½μ°
id=1 μΈ λ μ½λμ money 컬λΌμ κ°(1000)μ μΌμͺ½ νΈλμμ μμλ 500μ λΉΌκ³ , μ€λ₯Έμͺ½ νΈλμμ μλ 100μ λΉΌκ³ , λ νΈλμμ μ 컀λ°νμ΅λλ€. κ·Έλ¬λ, μΌμͺ½ νΈλμμ μ Query OK, 1 row affected (4.28 sec) μ ν΅ν΄ update μ λ°°ν λ½μ΄ κ±Έλ € λκΈ°νμ§λ§ κ²°κ³Όλ id=1μΈ λ μ½λμ money 컬λΌμ κ°μ 500 μΌλ‘, μ€λ₯Έμͺ½ νΈλμμ μ κ²°κ³Όκ° λ μ½λμ λ°μλμ§ μμμ΅λλ€.
- select ... for update μ¬μ©ν΄μ Lost Update λ¬Έμ λ°μνμ§ μλ κ²½μ°
λ°°ν λ½μ μ¬μ©νλ id=1 μΈ νμ money 컬λΌμ κ°(1000)μ μ€λ₯Έμͺ½ νΈλμμ μμλ 100μ λΉΌμλ§μ, μΌμͺ½ νΈλμμ μλ id=1 μΈ νμ money 컬λΌμ κ°μ μ‘°ννλ 1000μμ 100μ λΊ κ°μΈ 900μ΄ λμ€κ² λμμ΅λλ€.
6. λ§μΉλ©°..
곡μ λ½/λ°°ν λ½/MVCC λ₯Ό 곡λΆνκ³ , Real MySQLμ 곡λΆνλ©΄μ λ½μ μ¬μ©νλ©΄ μ΄λ€ 쿼리 μμ κΉμ§ μν₯μ λ―ΈμΉλμ§ νμ ν·κ°λ Έκ³ , λ°°ν λ½κ³Ό MySQL μμ μ§μνλ λ μ½λ λ½ / κ° λ½ / λ₯μ€νΈ ν€ λ½μ μ°¨μ΄κ° 무μμΈμ§, update μλ λ°°ν λ½μ΄ 걸리λλ° select ... for update λ μ νμνμ§? μ§μ μ€ννκ³ μ 리ν΄λ³΄μμ΅λλ€.
μ΄λ² μ€νμ ν΅ν΄ UPDATE / DELETE μμ λ λ°°ν λ½μ μ¬μ©νκ³ , μΈλν€/μ λν¬ ν€ μ μ½ μ‘°κ±΄λ€μ μ΄λ»κ² λ°μ΄ν°μ 무결μ±μ 보μ₯νλμ§ κΆκΈνλλ° μ΄λ² κΈ°νμ μ 리ν μ μμμ΅λλ€.
μ΄λ κ²
- MySQL λ΄λΆμ μΌλ‘ λ°μ΄ν°μ 무결μ±(μΈλν€, μ λν¬ ν€)μ μ§ν€κΈ° μν΄ λ½μ κ±Έκ³ ,
- UPDATE / DELETE 쿼리 μ μΈλ±μ€κ° μλ 컬λΌμ WHERE μ μ λ£μΌλ©΄ μμμΉ λͺ»νκ² μλ§μ λ μ½λμ λ½μ΄ 걸릴 μλ μκ³ ,
- Repetable Read μμ λΉκ΄μ λ½μ μ¬μ©ν λ, phantom read λ λ°μνλ κ²½μ°λ μλ€λ³΄λ(λ체μ μΌλ‘λ λ°μνμ§ μμ§λ§..)
μ¬κΈ°μ λμμ± μ μ΄λ₯Ό μν΄ λΉκ΄μ λ½μ μΆκ°λ‘ μ¬μ©ν΄μ λ°λλ½ μνμ λ μ¦κ° μμΌμΌ ν κΉ? λ μκ°μ΄ λ€μμ΅λλ€. μ΄λ¬ν μ΄μ λ‘ λΉκ΄μ λ½μ λν΄ νμμ μ΄κ² λμμ΅λλ€. λν, λκ΅°κ° μ κ² 'λΉκ΄μ λ½μ μ μ¬μ© μνμ ¨λμ?' λΌ λ¬Όμ΄λ³Έλ€λ©΄ μ΄ κ²½νμ ν λλ‘ λ§μ λ릴 κ² κ°μ΅λλ€.
μ΄μ κ΄λ ¨ν΄μ, μΈνλ° μ§μ μλ΅μμ μνλκ»μ λμμ± μ μ΄λ₯Ό μν΄ DB λ½μ κ±°λ λ°©λ²μ νΌνκ³ , μμμ μ°μ°μ΄λ λ‘μ§μ μ ꡬμμ λ§λ λ°©λ²μ μ νΈνλ€κ³ λ§μμ ν΄μ£Όμ κ²μ λ³΄κ³ μ΄λ² κ²½νμ ν΅ν΄ μ‘°κΈμ μ΄ν΄νκ² λμμ΅λλ€.