今回ã‹ã‚‰æ•°å›žã«ã‚ãŸã‚Šã€Transactdã®ã‚ªãƒšãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ã¨InnoDBã«ãŠã‘ã‚‹ãƒãƒƒã‚¯ã«ã¤ã„ã¦è§£èª¬ã—ã¾ã™ã€‚
ãƒãƒƒã‚¯ã«ã¤ã„ã¦ã¯ã‚ã¾ã‚Šè‰¯ãã‚ã‹ã‚‰ãªãã¦ã‚‚ã¨ã‚Šã‚ãˆãšãれãªã‚Šã«å‹•ãアプリケーションã¯ä½œã‚Œã¦ã—ã¾ã„ã¾ã™ã€‚ã§ã™ãŒã€ãƒžãƒ«ãƒãƒ¦ãƒ¼ã‚¶ãƒ¼ç’°å¢ƒã§ãƒŸãƒƒã‚·ãƒ§ãƒ³ã‚¯ãƒªãƒ†ã‚£ã‚«ãƒ«ãªã‚¢ãƒ—リケーションを書ãã«ã¯ã€ãƒãƒƒã‚¯ã®ç†è§£ãŒä¸å¯æ¬ ã§ã™ã€‚ãƒãƒƒã‚¯ã‚’ã†ã¾ã使ã£ã¦çŸ›ç›¾ã‚„é–“é•ã„ã®ãªã„èªã¿æ›¸ãã¨åŒæ™‚実行性ã®è‰¯ã„アプリケーションã«ã—ã¾ã—ょã†ã€‚
ãã®1ã§ã¯ã€Transactdを実装ã™ã‚‹ä¸Šã§MySQLã®ã‚½ãƒ¼ã‚¹ã‚„ドã‚ュメントã‹ã‚‰å¾—ãŸçŸ¥è¦‹ã‚’基ã«ã€InnoDBã®ãƒãƒƒã‚¯ã®ç¨®é¡žã¨åˆ†é›¢ãƒ¬ãƒ™ãƒ«ã«å¿œã˜ã¦ãれをã©ã®ã‚ˆã†ã«ä½¿ã†ã‹ã‚’ã¾ã¨ã‚ã¦ã¿ã¾ã™ã€‚
MySQLã®ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³é–¢é€£ç”¨èªž
説明ã«å…¥ã‚‹å‰ã«ã€äº‹å‰ã«MySQLã®ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³é–¢é€£ç”¨èªžã®ç†è§£ãŒå¿…è¦ã§ã™ã€‚下記ã®ç”¨èªžã«ã¤ã„ã¦ã‚ã¾ã‚Šã‚ˆãã‚ã‹ã‚‰ãªã„å ´åˆã¯ã€å¤§ã¾ã‹ã§è‰¯ã„ã®ã§ç†è§£ã—ã¦ãŠã„ã¦ãã ã•ã„。
MySQLã®REPEATABLE-READ
MySQLã®ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³åˆ†é›¢ãƒ¬ãƒ™ãƒ«ã¯REPEATABLE READãŒæ¨™æº–ã§ã™ã€‚通常 REPEATABLE READã§ã¯ãƒ•ァントムリードを回é¿ã§ãã¾ã›ã‚“ãŒã€MySQLã®REPEATABLE READã¯ãƒã‚¯ã‚¹ãƒˆã‚ーãƒãƒƒã‚¯ã¨ã„ã†ä»•組ã¿ã«ã‚ˆã£ã¦ãƒ•ァントムリードãŒèµ·ããªã„よã†ã«ãªã£ã¦ã„ã¾ã™ã€‚ãã®ãŸã‚ã€ã•らã«åˆ†é›¢ãƒ¬ãƒ™ãƒ«ã®é«˜ã„ SERIALIZABLE ã¨ã»ã¼åŒã˜ã‚‚ã®ã§ã™ã€‚
トランザクション分離レベルã¯4ã¤ã‚りã¾ã™ãŒã€READ_UNCOMMITEDã¯ã»ã¨ã‚“ã©ä½¿ç”¨ã•れãªã„ã®ã§ã“ã“ã§ã¯çœã„ã¦èª¬æ˜Žã—ã¾ã™ã€‚
InnoDBã®ãƒãƒƒã‚¯
ã¯ã˜ã‚ã«InnoDBã®åŸºæœ¬çš„ãªãƒãƒƒã‚¯ã«ã¤ã„ã¦èª¬æ˜Žã—ã¾ã™ã€‚InnoDBã¯MVCCã¨ã“れらã®ãƒãƒƒã‚¯ã‚’使ã£ã¦ã€ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³åˆ†é›¢ãƒ¬ãƒ™ãƒ«ã‚’実装ã—ã¦ã„ã¾ã™ã€‚
行ãƒãƒƒã‚¯ (row-level locking)
InnoDBã¯è¡Œãƒãƒƒã‚¯ã‚’サãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã™ã€‚行ãƒãƒƒã‚¯(row lock)ã«ã¯Shared lock(共有ãƒãƒƒã‚¯S)ã¨Exclusive lock(排他ãƒãƒƒã‚¯X)ã®2種類ãŒã‚りã¾ã™ã€‚
トランザクションT1ã«ã‚ˆã£ã¦å…±æœ‰ãƒãƒƒã‚¯(S)ãŒå–å¾—ã•れãŸãƒ¬ã‚³ãƒ¼ãƒ‰Rã¯ã€åˆ¥ã®ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³T2ã‹ã‚‰å…±æœ‰ãƒãƒƒã‚¯(S)ã¯ã§ãã¾ã™ãŒã€æŽ’ä»–ãƒãƒƒã‚¯(X)ã¯ã§ãã¾ã›ã‚“。ã¾ãŸã€ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³T1ã«ã‚ˆã£ã¦æŽ’ä»–ãƒãƒƒã‚¯(X)ãŒå–å¾—ã•れãŸãƒ¬ã‚³ãƒ¼ãƒ‰Rã¯ã€åˆ¥ã®ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³T2ã‹ã‚‰å…±æœ‰ãƒãƒƒã‚¯(S)も排他ãƒãƒƒã‚¯(X)ã‚‚ã§ãã¾ã›ã‚“。
2ã¤ã®ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³ãŒåŒã˜ãƒ¬ã‚³ãƒ¼ãƒ‰ã®ãƒãƒƒã‚¯ã‚’å–å¾—ã—よã†ã¨ã—ãŸã¨ãã®ãƒãƒƒã‚¯ã®å¯å¦ã‚’表ã—ãŸã®ãŒInnoDBソースコードã®ä»¥ä¸‹ã®éƒ¨åˆ†ã§ã™ã€‚「TRUEã€ã®çµ„ã¿åˆã‚ã›ã§ã¯äº’ã„ã«ç«¶åˆã›ãšåŒæ–¹ã¨ã‚‚å–å¾—ã§ãã¾ã™ã€‚「FALSEã€ã®çµ„ã¿åˆã‚ã›ã§ã¯ã€å¾Œã‹ã‚‰å–å¾—ã—よã†ã¨ã—ãŸæ–¹ã¯ã€å…ˆã«å–å¾—ã•れãŸãƒãƒƒã‚¯ãŒè§£æ”¾ã•れるã¾ã§ãƒãƒƒã‚¯ã‚’å–å¾—ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。ã¾ã 説明ã—ã¦ã„ãªã„IXã‚„ISã¨ã„ã†ãƒãƒƒã‚¯ãŒã‚りã¾ã™ãŒã€ã“ã“ã§ã¯Xã¨Sã®çµ„ã¿åˆã‚ã›ã®ã¿è¦‹ã¦ãã ã•ã„。
//mysql-5.6.20/storage/innobase/lock/lock0lock.cc : 323 static const byte lock_compatibility_matrix[5][5] = { /** IS IX S X AI */ /* IS */ { TRUE, TRUE, TRUE, FALSE, TRUE}, /* IX */ { TRUE, TRUE, FALSE, FALSE, TRUE}, /* S */ { TRUE, FALSE, TRUE, FALSE, FALSE}, /* X */ { FALSE, FALSE, FALSE, FALSE, FALSE}, /* AI */ { TRUE, TRUE, FALSE, FALSE, FALSE} };
共有ãƒãƒƒã‚¯ã¨æŽ’ä»–ãƒãƒƒã‚¯ãれãžã‚Œã®ä½¿ã„é“ã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚
共有ãƒãƒƒã‚¯ | èªå– |
---|---|
排他ãƒãƒƒã‚¯ | èªå–ã€æ›´æ–°ã€å‰Šé™¤ |
GAPãƒãƒƒã‚¯
GAPãƒãƒƒã‚¯ã¯ã€ãƒ¬ã‚³ãƒ¼ãƒ‰ã¨ãƒ¬ã‚³ãƒ¼ãƒ‰ã®é–“ã®ç©ºé–“ã‚’ãƒãƒƒã‚¯ã—ã¾ã™ã€‚ã“れã§Insertをブãƒãƒƒã‚¯ã—ã€è¡Œãƒãƒƒã‚¯ã§æ›´æ–°ã‚’ブãƒãƒƒã‚¯ã™ã‚‹ã“ã¨ã§ã€ãƒ•ァントムリードを防æ¢ã—ã¾ã™ã€‚具体的ã«ã¯ã€å¾Œã‚å´ã®ãƒ¬ã‚³ãƒ¼ãƒ‰ã«GAPãƒãƒƒã‚¯ã‚’行ã„ã¾ã™ã€‚GAPãƒãƒƒã‚¯ã¯å˜ä½“ã§ä½¿ç”¨ã™ã‚‹å ´åˆã¨ã€è¡Œãƒãƒƒã‚¯ã¨çµ„ã¿åˆã‚ã›ã¦ä½¿ç”¨ã™ã‚‹å ´åˆãŒã‚りã¾ã™ã€‚行ãƒãƒƒã‚¯ã¨çµ„ã¿åˆã‚ã›ãŸã‚‚ã®ã‚’ãƒã‚¯ã‚¹ãƒˆã‚ーãƒãƒƒã‚¯(Next key lock)ã¨å‘¼ã‚“ã§ã„ã¾ã™ã€‚
GAPãƒãƒƒã‚¯å˜ä½“ã€ãƒã‚¯ã‚¹ãƒˆã‚ーãƒãƒƒã‚¯ã€GAPãƒãƒƒã‚¯ã‚’å«ã¾ãªã„通常ã®è¡Œãƒãƒƒã‚¯ã®3種類をinnodb_monitorã§è¦‹ã‚‹ã¨ã€ä¸‹è¨˜ã®ã‚ˆã†ã«è¡¨ç¤ºã•れã¾ã™ã€‚*1
GAPãƒãƒƒã‚¯å˜ä½“
.`test` trx id 134515465 lock mode S locks gap before rec
ãƒã‚¯ã‚¹ãƒˆã‚ーãƒãƒƒã‚¯
.`test` trx id 134515465 lock mode S locks
GAPãƒãƒƒã‚¯ã‚’å«ã¾ãªã„通常ã®è¡Œãƒãƒƒã‚¯(row lock)
.`test` trx id 134515465 lock mode S locks rec but not gap
èªã¿å–ã£ãŸãƒ¬ã‚³ãƒ¼ãƒ‰ã™ã¹ã¦ã«ãƒã‚¯ã‚¹ãƒˆã‚ーãƒãƒƒã‚¯ã‚’行ã„ã€æœ€å¾Œã«èªã¿å–ã£ãŸãƒ¬ã‚³ãƒ¼ãƒ‰ã«GAPãƒãƒƒã‚¯ã‹ãƒã‚¯ã‚¹ãƒˆã‚ーãƒãƒƒã‚¯*2を行ã†ã“ã¨ã§ã€æ¤œç´¢ç¯„å›²å†…ã®æ›´æ–°ã¨æŒ¿å…¥ãƒ–ãƒãƒƒã‚¯ã‚’実ç¾ã—ã¾ã™ã€‚
ãŸã¨ãˆã°ã€ãƒ¦ãƒ‹ãƒ¼ã‚¯ãªã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ãƒ•ィールド id ã®1ã‹ã‚‰15ã¾ã§ãƒ¬ã‚³ãƒ¼ãƒ‰ãŒæŒ¿å…¥ã•れãŸãƒ†ãƒ¼ãƒ–ルãŒã‚ã‚‹ã¨ã—ã¾ã™ã€‚ãã“ã«REPEATABLE-READã§ select id from table where id <= 10 LOCK IN SHARE MODE
ã¨ã™ã‚‹ã¨ã€ã¾ãšã€id 1ã‹ã‚‰10ã¾ã§10個ã®ãƒ¬ã‚³ãƒ¼ãƒ‰ã¯ç¢ºå®Ÿã«ãƒã‚¯ã‚¹ãƒˆã‚ーãƒãƒƒã‚¯ãŒè¡Œã‚れã¾ã™ã€‚11ã¯ã€ãƒ¦ãƒ‹ãƒ¼ã‚¯ã‚ー㧠<= ã¨ã—ã¦ã„ã‚‹ã®ã§èªã¾ãªãã¦ã‚‚検索終了を判æ–ã§ããã†ãªã®ã§ã™ãŒã€11ã‚‚ãƒã‚¯ã‚¹ãƒˆã‚ーãƒãƒƒã‚¯ã•れã¾ã™ã€‚(11ã®ãƒãƒƒã‚¯ã«ã¤ã„ã¦ã¯ã€ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ã‚„検索æ¡ä»¶ã®æ›¸ãæ–¹ã«ã‚ˆã£ã¦å¤‰ã‚りã¾ã™ã€‚MySQLã§ã¯ã€ã»ã¼ãƒãƒƒã‚¯ã•れるã¨è€ƒãˆã¦ãã ã•ã„。)
GAPãƒãƒƒã‚¯å˜ä½“ã§ãƒãƒƒã‚¯ã•れãŸãƒ¬ã‚³ãƒ¼ãƒ‰ã¯ã€å‰ã®ç©ºé–“ãŒãƒãƒƒã‚¯ã•れã¦ã„ã‚‹ã ã‘ã§ãƒ¬ã‚³ãƒ¼ãƒ‰ãã®ã‚‚ã®ã¯ãƒãƒƒã‚¯ã•れã¦ã„ã¾ã›ã‚“。以下ã®ä¾‹ã§ã¯ã€åŒã˜ãƒ¬ã‚³ãƒ¼ãƒ‰(0: 1:ã§ç¤ºã•れãŸãƒ•ィールドã®å†…容ãŒåŒã˜)ã«å¯¾ã—ã¦ç•°ãªã‚‹2ã¤ã®ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³ãŒGAPãƒãƒƒã‚¯(X)ã¨å…±æœ‰ãƒãƒƒã‚¯(S)ã‚’å–å¾—ã—ã¦ã„ã¾ã™ã€‚
//トランザクション1
.`test` trx id 134515525 lock_mode X locks gap before rec
Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 4; hex 80000010; asc ;;
1: len 4; hex 80000003; asc ;;.`test` trx id 134515526 lock mode S
Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 4; hex 80000010; asc ;;
1: len 4; hex 80000003; asc ;;
ãªãŠã€æ¤œç´¢ãŒEND OF RECORDSã¾ã§åˆ°é”ã—ãŸå ´åˆã¯ã€GAPãƒãƒƒã‚¯ã‚’明示ã™ã‚‹ãƒ¬ã‚³ãƒ¼ãƒ‰ãŒå˜åœ¨ã—ã¾ã›ã‚“。ãã®å ´åˆã¯ã€æœ€å¾Œã®ãƒ¬ã‚³ãƒ¼ãƒ‰ã®ã•らã«å¾Œã‚ã«ã‚る終端を示ã™ãƒ¬ã‚³ãƒ¼ãƒ‰(supremum)ãŒãƒãƒƒã‚¯ã•れã¾ã™ã€‚
.`test` trx id 134515465 lock mode S
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
MySQLã®handlerインターフェースã«ã¯ã€ãƒã‚¯ã‚¹ãƒˆã‚ーãƒãƒƒã‚¯ã‚’æ˜Žç¤ºçš„ã«æŒ‡ç¤ºã™ã‚‹æ–¹æ³•ã¯å˜åœ¨ã—ã¾ã›ã‚“ãŒã€åˆ†é›¢ãƒ¬ãƒ™ãƒ«ã«REPEATABLE READã‹SERIALIZABLEãŒæŒ‡å®šã•れã¦ã„ã‚‹ã¨ã€è¡Œãƒãƒƒã‚¯ã«æ›¿ãˆã¦ãƒã‚¯ã‚¹ãƒˆã‚ーãƒãƒƒã‚¯ãŒä½¿ç”¨ã•れã¾ã™ã€‚
余談ã§ã™ãŒã€SQLã®æ‚©ã¿ã«ã€Œãƒãƒƒã‚¯ã•れるレコードã®ç¯„囲ã¯ã©ã“ã«ãªã‚‹ã®ã‹ãŒã‚ã‹ã‚Šã«ãã„ã€ã¨ã„ã£ãŸã‚‚ã®ãŒã‚りã¾ã™ã€‚èªã¿å–ã‚Šæ–¹æ³•ã‚„ç¯„å›²ã‚’ã‚ªãƒ—ãƒ†ã‚£ãƒžã‚¤ã‚¶ãŒæ±ºã‚ã‚‹ãŸã‚ã§ã™ã€‚Transactdã®å ´åˆã¯ãã®ã‚ˆã†ãªæ‚©ã¿ã¯ã‚りã¾ã›ã‚“。ãれらã¯ã‚³ãƒ¼ãƒ‰ã‚’書ãäººãŒæ±ºã‚ã‚‹ã‹ã‚‰ã§ã™ã€‚
インテンションãƒãƒƒã‚¯ (Intention Locks)
インテンションãƒãƒƒã‚¯ã¯ã€multiple granularity locking (複数粒度ãƒãƒƒã‚¯)ã¨MySQLã®ãƒ‰ã‚ュメントã«è¨˜ã•れã¦ã„ã¾ã™ãŒã€å®Ÿéš›ã«ã“ã®ã‚ˆã†ãªãƒãƒƒã‚¯ãŒã‚ã‚‹ã‚ã‘ã§ã¯ã‚りã¾ã›ã‚“。テーブルã«ã“ã®ãƒãƒƒã‚¯ã‚’明示ã™ã‚‹ã¨ã€ä»¥é™ã®è¡Œæ“作ã«å¯¾ã—ã¦ã€è¡Œã®å…±æœ‰ãƒãƒƒã‚¯(S)ã¾ãŸã¯æŽ’ä»–ãƒãƒƒã‚¯(X)ã®å–å¾—ãŒè¡Œã‚れる仕組ã¿ã®ã“ã¨ã§ã™ã€‚
行ãƒãƒƒã‚¯ã«åˆã‚ã›ã¦ã€ã‚¤ãƒ³ãƒ†ãƒ³ã‚·ãƒ§ãƒ³ãƒãƒƒã‚¯ã«ã‚‚共有ãƒãƒƒã‚¯(IS)ã¨æŽ’ä»–ãƒãƒƒã‚¯(IX)ã®2種類ãŒã‚りã¾ã™ã€‚ã¨ã‚‚ã«ãƒ†ãƒ¼ãƒ–ルã«å¯¾ã—ã¦ãƒãƒƒã‚¯ã‚’明示ã—ã¾ã™ã€‚
- 共有ãƒãƒƒã‚¯(IS)ã¯ã€ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³T内ã§ãƒ†ãƒ¼ãƒ–ルtã®è¤‡æ•°ã®è¡Œã«å¯¾ã—ã¦å…±æœ‰ãƒãƒƒã‚¯(S)ã®å–得を試ã¿ã‚‹ã€‚
- 排他ãƒãƒƒã‚¯(IX)ã¯ã€ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³T内ã§ãƒ†ãƒ¼ãƒ–ルtã®è¤‡æ•°ã®è¡Œã«å¯¾ã—ã¦æŽ’ä»–ãƒãƒƒã‚¯(X)ã®å–得を試ã¿ã‚‹ã€‚
インテンションãƒãƒƒã‚¯ã®ä½¿ã‚れ方を簡å˜ã«èª¬æ˜Žã™ã‚‹ã¨ã€ã“れã‹ã‚‰æ›´æ–°ã‚„削除を行ã†éš›ã«ã¯æŽ’ä»–ãƒãƒƒã‚¯(IX)ã‚’è¨å®šã—ã€æ›´æ–°ã‚„削除をã•れãŸããªã„èªã¿å–りを行ã†éš›ã«ã¯å…±æœ‰ãƒãƒƒã‚¯(IS)ã‚’è¨å®šã—ã¾ã™ã€‚(SQLæ–‡ã§æ˜Žç¤ºçš„ã«ã‚¤ãƒ³ãƒ†ãƒ³ã‚·ãƒ§ãƒ³ãƒãƒƒã‚¯ã‚’æ“作ã™ã‚‹æ–¹æ³•ã¯ã‚りã¾ã›ã‚“。MySQLãŒSQLæ–‡ã‹ã‚‰ãƒ†ãƒ¼ãƒ–ルãƒãƒƒã‚¯ã‚¿ã‚¤ãƒ—を決ã‚ã€ãã®ã‚¿ã‚¤ãƒ—ã‹ã‚‰InnoDBãŒã‚¤ãƒ³ãƒ†ãƒ³ã‚·ãƒ§ãƒ³ãƒãƒƒã‚¯ã‚¿ã‚¤ãƒ—を決定ã—ã¾ã™ï¼‰
Multi-Versioning
InnoDBã®å„レコードã«ã¯ã€æœ€å¾Œã«è¿½åŠ ã¾ãŸã¯æ›´æ–°ãƒ»å‰Šé™¤ã—ãŸãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³ã®IDãŒè¨˜éŒ²ã•れã¾ã™ã€‚更新・削除ã«ã‚ˆã£ã¦å¤ããªã£ãŸãƒãƒ¼ã‚¸ãƒ§ãƒ³ï¼ˆæ—§ãƒãƒ¼ã‚¸ãƒ§ãƒ³ï¼‰ã®ãƒ¬ã‚³ãƒ¼ãƒ‰ã¯ã€ãƒ†ãƒ¼ãƒ–ルスペースã®ãƒãƒ¼ãƒ«ãƒãƒƒã‚¯ã‚»ã‚°ãƒ¡ãƒ³ãƒˆã«ä¿æŒã•れã¾ã™ã€‚
- スナップショットã¯ã€è‡ªåˆ†ã®ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³IDã¨åŒã˜ã‹ã€ã‚ˆã‚Šå‰ã®ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³IDã§æœ€å¾Œã«ã‚³ãƒŸãƒƒãƒˆã•れãŸãƒ¬ã‚³ãƒ¼ãƒ‰ã®é›†åˆã€‚
- スナップショットã®èªã¿å–りã¯ãƒãƒƒã‚¯ã¯ä¸è¦ã€‚ã¾ãŸã€ãƒãƒƒã‚¯ã®å–得や変更ã¯ã§ããªã„。
å‰è¿°ã®å…±æœ‰ãƒãƒƒã‚¯(S)ã¨æŽ’ä»–ãƒãƒƒã‚¯(X)ã®ã„ãšã‚Œã§ã‚‚ãªã„LOCK_NONE(ãƒãƒƒã‚¯ãªã—)ã®èªã¿å–りã¯ã€ã‚¹ãƒŠãƒƒãƒ—ショットãŒä½¿ã‚れã¾ã™ã€‚
Consistent Reads
トランザクションT1ã«ãŠã„ã¦ã€ä»–ã®ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³ã«ã‚ˆã£ã¦å¤‰æ›´ã•れãŸå€¤ã«å½±éŸ¿ã•れるã“ã¨ãªãã€T1内ã§åŽŸå§‹æ€§ãŒä¿è¨¼ã•れãŸä¸€è²«æ€§ã®ã‚ã‚‹èªã¿å–りãŒã§ãã‚‹ã“ã¨ã‚’Consistent reads(一貫性èªã¿å–り)ã¨è¨€ã„ã¾ã™ã€‚
ãŸã¨ãˆã°ã€å£²ä¸Šä¼ç¥¨ã®ãƒ˜ãƒƒãƒ€ãƒ¼ã¨æ˜Žç´°ã¯ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³ã«ã‚ˆã£ã¦ä¸€å¼ã§ã‚¢ãƒˆãƒŸãƒƒã‚¯ãªæ›¸ãè¾¼ã¿ãŒè¡Œã‚れるã¨ã—ã¾ã™ã€‚èªã¿å–りã«ãŠã„ã¦ä¸€è²«æ€§ãŒãªã„ã¨ã€ãƒ˜ãƒƒãƒ€ãƒ¼ã¨æ˜Žç´°ã§ç•°ãªã‚‹ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’èªã‚“ã§ã—ã¾ã†ã“ã¨ãŒèµ·ã“りã¾ã™ã€‚T1ãŒãƒ˜ãƒƒãƒ€ãƒ¼ã‚’èªã¿å–ã‚Šã€æ¬¡ã«æ˜Žç´°ã‚’èªã¿å–ã‚‹å‰ã«ã€T2ã«ã‚ˆã£ã¦å¤‰æ›´ã•れãŸä¼ç¥¨ãŒã‚³ãƒŸãƒƒãƒˆã•れãŸå ´åˆãªã©ã§ã™ã€‚Consistent readsã¯ã‚¢ãƒˆãƒŸãƒƒã‚¯ãªç‰¹æ€§ã¨ä½µã›ã¦ã€ã“ã®ã‚ˆã†ãªå•題を解決ã™ã‚‹ãŸã‚ã«ã¨ã¦ã‚‚é‡è¦ãªæ©Ÿèƒ½ã§ã™ã€‚
InnoDBã®Consistent readsã«ã¯ã€2ã¤ã®æ–¹æ³•ãŒã‚りã¾ã™ã€‚
- Consistent Nonlocking Reads (ãƒãƒƒã‚¯ãªã—一貫性èªã¿å–り)
- Consistent locking Reads (ãƒãƒƒã‚¯ã‚ング一貫性èªã¿å–り)
Consistent Nonlocking Reads
Consistent Nonlocking Readsã¯ãƒžãƒ«ãƒãƒãƒ¼ã‚¸ãƒ§ãƒ³æ©Ÿèƒ½ã‚’使ã£ã¦ã€ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³ã‚’é–‹å§‹ã—ãŸæ™‚点ã®ã‚¹ãƒŠãƒƒãƒ—ショットã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ã“ã¨ã§å®Ÿç¾ã—ã¾ã™ã€‚ä»–ã®ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³ã«ã‚ˆã£ã¦ã‚³ãƒŸãƒƒãƒˆæ¸ˆã¿ã®æŒ¿å…¥ãƒ»æ›´æ–°ã•れãŸãƒ¬ã‚³ãƒ¼ãƒ‰ãŒã‚ã£ã¦ã‚‚ã€ã‚¹ãƒŠãƒƒãƒ—ショットã«ã¯ãれã¯ãªã„ã®ã§ã€Consistent readsを実ç¾ã—ã¾ã™ã€‚ã¾ãŸã€ãƒãƒƒã‚¯ä¸è¦ãªã®ã§ Consistent Nonlocking Readsã§ã™ã€‚
InnoDBã§Consistent Nonlocking Readsを行ã†ã«ã¯ã€ãƒãƒƒã‚¯ã‚’è¦æ±‚ã—ãªã„èªã¿å–りを行ã†ã“ã¨ã§å®Ÿç¾ã—ã¾ã™ã€‚(SQLã§ã¯ã€SELECT ... FOR UPDATE ã‹ SELECT ... LOCK IN SHARE MODEを使ã‚ãªã„èªã¿å–り)ãŸã ã—ã€åˆ†é›¢ãƒ¬ãƒ™ãƒ«ãŒSERIALIZABLEã®å ´åˆã¯ã€ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³å†…ã®ã™ã¹ã¦ã®èªã¿å–り時ã«å…±æœ‰ãƒãƒƒã‚¯(S)ã‚’è¦æ±‚ã—ã¦ã—ã¾ã†ã®ã§ã€Consistent Nonlocking Readsã¯è¡Œãˆã¾ã›ã‚“。
以下ã¯ã€SERIALIZABLEãŒLOCK_Sã‚’å¼·è¦ã™ã‚‹éƒ¨åˆ†ã®InnoDBã®ã‚³ãƒ¼ãƒ‰ã®æŠœç²‹ã§ã™ã€‚(mysql-5.6.20)
// /mysql-5.6.20/storage/innobase/handler/ha_innodb.cc : 12191 if (trx->isolation_level == TRX_ISO_SERIALIZABLE && prebuilt->select_lock_type == LOCK_NONE && thd_test_options( thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { /* To get serializable execution, we let InnoDB conceptually add 'LOCK IN SHARE MODE' to all SELECTs which otherwise would have been consistent reads. An exception is consistent reads in the AUTOCOMMIT=1 mode: we know that they are read-only transactions, and they can be serialized also if performed as consistent reads. */ prebuilt->select_lock_type = LOCK_S; prebuilt->stored_select_lock_type = LOCK_S; }
ã“ã®ã€Consistent Nonlocking Readsã«ã¯2ã¤æ³¨æ„点ãŒã‚りã¾ã™ã€‚
- READ-COMMITEDã®å ´åˆã¯ã€ã‚¹ãƒŠãƒƒãƒ—ショットã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ãŒãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³å†…ã§å¤‰ã‚る。
- ã‚¹ãƒŠãƒƒãƒ—ã‚·ãƒ§ãƒƒãƒˆã¯æ›´æ–°ã§ããªã„ã€‚æ›´æ–°ã¯æœ€æ–°ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã«å¯¾ã—ã¦è¡Œã†ãŒã€ã‚¹ãƒŠãƒƒãƒ—ショットã¨ã¯å€¤ãŒç•°ãªã‚‹ã“ã¨ãŒã‚る。
REPEATABLE-READã®ã¨ãã¯ã€ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³ã®æœ€åˆã‹ã‚‰æœ€å¾Œã¾ã§åŒã˜ã‚¹ãƒŠãƒƒãƒ—ショットã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã™ã€‚ã¨ã“ã‚ãŒã€READ-COMMITEDã®ã¨ãã¯1ã¤ã®SQLæ–‡ã®ä¸ã§ã®ã¿åŒã˜ã‚‚ã®ã§ã™ã€‚トランザクションä¸ã§ã‚ã£ã¦ã‚‚ã€1文目ã¨2文目ã§ã¯ç•°ãªã‚‹ã‚¹ãƒŠãƒƒãƒ—ショット(ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ï¼‰ãŒä½¿ã‚れるå¯èƒ½æ€§ãŒã‚りã¾ã™ã€‚(1文内ã ã‘ã®Consistent Nonlocking Reads)
スナップショットã¯ã‚³ãƒŸãƒƒãƒˆæ¸ˆã®ç¢ºå®šã—ãŸå†…容ãªã®ã§ã€ãã®è¡Œã‚’ãƒãƒƒã‚¯ã—ã¦å¤‰æ›´ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“ã€‚ãƒˆãƒ©ã‚¶ã‚¯ã‚·ãƒ§ãƒ³å†…ã§æ›´æ–°ãŒå¿…è¦ãªå ´åˆã¯ã€ã‚¹ãƒŠãƒƒãƒ—ショットã§ã¯ãªãã€æœ€æ–°ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ãƒãƒƒã‚¯ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ã‚‚ã—ã€æœ€æ–°ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ãŒã€è‡ªåˆ†ã®ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³IDより新ã—ã„ã‚‚ã®ã§ã‚ã£ãŸå ´åˆã€ãã®å†…容ã¯ã‚¹ãƒŠãƒƒãƒ—ショットã¨ã¯ç•°ãªã‚‹ã‚‚ã®ã«ãªã‚Šã¾ã™ã€‚ãã®ãŸã‚ã€ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³ã«æ›´æ–°ã‚’å«ã‚€å ´åˆã€ã‚¹ãƒŠãƒƒãƒ—ショットを使ã£ãŸConsistent Nonlocking Readsã¨ã®æ··åˆã¯ã€REPEATABLE-READを満ãŸã™ã“ã¨ãŒã§ãã¾ã›ã‚“。
下図ã¯ã€REPEATABLE-READã®ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³ã«ãŠã„ã¦ã€ã‚¹ãƒŠãƒƒãƒ—ã‚·ãƒ§ãƒƒãƒˆã®æ§˜åを図ã«ã—ãŸã‚‚ã®ã§ã™ã€‚
トランザクション2ãŒConsistent Nonlocking Reads ã§èªã¿å–りを行ã£ãŸã‚ã¨ã€record 2ã‚’æ›´æ–°ã™ã‚‹ã«ã¯ã€ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³3(trx_id = 3)ã«ã‚ˆã£ã¦æ›´æ–°ã•ã‚ŒãŸæœ€æ–°ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’èªã¿å–ã£ã¦æŽ’ä»–ãƒãƒƒã‚¯(X)ã‚’å–å¾—ã—ãªãã¦ã¯ãªã‚Šã¾ã›ã‚“。最新ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã¯Consistent Nonlocking Readsã§èªã¿å–ã£ãŸãƒãƒ¼ã‚¸ãƒ§ãƒ³ã¨ã¯ç•°ãªã‚Šã¾ã™ã€‚絶対ã«ã€ãƒãƒƒã‚¯ãªã—READã«ã‚ˆã£ã¦å¾—られãŸå€¤ã‚’å…ƒã«æ›´æ–°ã—ã¦ã¯ã„ã‘ã¾ã›ã‚“。
Consistent locking Reads
Consistent locking Readsã¨ã„ã†ãƒ¯ãƒ¼ãƒ‰ã¯MySQLã®ãƒ‰ã‚ュメントã«ã¯ã‚りã¾ã›ã‚“ãŒã€Nonlockingã¨å¯¾æ¯”ã™ã‚‹ãŸã‚ã«ä¾¿å®œçš„ã«ã“ã†å‘¼ã‚“ã§ã„ã¾ã™ã€‚
Consistent locking Readsã¯ã€ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³å†…ã§èªã¿å–ã£ãŸãƒ¬ã‚³ãƒ¼ãƒ‰ã‚’ã™ã¹ã¦ãƒã‚¯ã‚¹ãƒˆã‚ーãƒãƒƒã‚¯ã—ã¦ã€æ›´æ–°ã¨æŒ¿å…¥ã‚’ブãƒãƒƒã‚¯ã™ã‚‹ã“ã¨ã§ã€Consistent readを実ç¾ã™ã‚‹æ–¹æ³•ã§ã™ã€‚(ã“ã®æ–¹æ³•ã¯ã€æ›´æ–°ã‚’行ã„ã¤ã¤ä¸€è²«æ€§ã®ã‚ã‚‹èªã¿å–りãŒã§ãã¾ã™ãŒã€ãƒãƒƒã‚¯ãŒå¤šããªã‚‹ãŸã‚トランザクションã®åŒæ™‚実行性能ã¯å¤§ãã低下ã—ã¦ã—ã¾ã„ã¾ã™ã€‚)
実ã¯ã“ã®Consistent locking ReadsãŒã€SERIALIZABLE ã§ã™ã€‚å‰è¿°ã®ã¨ãŠã‚Šã€SERIALIZABLE を指定ã™ã‚‹ã¨ãƒãƒƒã‚¯ã‚’指定ã—ã¦ã„ãªã„èªã¿å–りã«ãŠã„ã¦ã‚‚ã€ãƒã‚¯ã‚¹ãƒˆã‚ーãƒãƒƒã‚¯(S)を自動ã§å–å¾—ã—ã¾ã™ã€‚
ãれ以外ã®åˆ†é›¢ãƒ¬ãƒ™ãƒ«ã§ã¯ã€SELECT ... FOR UPDATE ã‚„ SELECT ... LOCK IN SHARE MODE を使ã£ã¦ãƒãƒƒã‚¯ã‚’指定ã—ãªã„ã¨èªã¿å–りã«ãƒãƒƒã‚¯ã‚’ã‹ã‘ã¾ã›ã‚“。Consistent locking Readsã«ã™ã‚‹ã«ã¯æ˜Žç¤ºçš„ã«ãƒãƒƒã‚¯ã‚’行ã†å¿…è¦ãŒã‚りã¾ã™ã€‚ã¡ãªã¿ã«ã€REPEATABLE-READã§ã™ã¹ã¦ã®èªã¿å–りã«ãƒãƒƒã‚¯ã‚’指定をã™ã‚‹ã¨ã€SERIALIZABLEã¨åŒã˜ã«ãªã‚Šã¾ã™ã€‚
READ_COMMITEDã§ã¯ã€ãƒãƒƒã‚¯æŒ‡å®šèªã¿å–り時ã«ãƒã‚¯ã‚¹ãƒˆã‚ーãƒãƒƒã‚¯ã«æ›¿ãˆã¦é€šå¸¸ã®è¡Œãƒãƒƒã‚¯ãŒä½¿ç”¨ã•れã¾ã™ã€‚READ_COMMITEDã¯ãƒ•ァントムリードを防æ¢ã§ããªãã¦ã‚‚よã„ã®ã§ã“れã§ã‚ˆã„ã®ã§ã™ãŒã€Consistent locking Readsã«ã¯ãªã‚Šã¾ã›ã‚“。
ãƒãƒƒã‚¯ä»˜èªã¿å–り時ã®ãƒãƒƒã‚¯å¯¾è±¡
クエリーã«ãƒžãƒƒãƒã—ãªã„レコードã®ãƒãƒƒã‚¯ä¿æŒã¨é–‹æ”¾ã«ã¤ã„ã¦èª¬æ˜Žã—ã¾ã™ã€‚
ã‚¯ã‚¨ãƒªãƒ¼ã®æ¤œç´¢å¯¾è±¡ã¯ã€ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ã‚’使ã£ãŸç‰¹å®šã®ãƒ¬ã‚³ãƒ¼ãƒ‰ç¯„囲(ã¾ãŸã¯è¤‡æ•°ã®ç¯„囲)ã€ã¾ãŸã¯å…¨ãƒ¬ã‚³ãƒ¼ãƒ‰ã®ã©ã¡ã‚‰ã‹ã§ã™ã€‚ãã®éš›ã«ã€ç¯„囲内ã§ã¯ã‚ã‚‹ã‘れã©ã‚‚æ¡ä»¶ã«ãƒžãƒƒãƒã—ãªã„レコードã®ãƒãƒƒã‚¯ã¯ã©ã†ãªã‚‹ã®ã§ã—ょã†ã‹ï¼Ÿ
ãれã¯åˆ†é›¢ãƒ¬ãƒ™ãƒ«ã«ã‚ˆã£ã¦ä»¥ä¸‹ã®ã‚ˆã†ã«ãªã‚Šã¾ã™ã€‚
SERIALIZABLE REPEATABLE-READ | ãƒãƒƒã‚¯ã‚’ä¿æŒ(ファントムリードを防æ¢ã™ã‚‹ãŸã‚) |
READ_COMMITED | ãƒãƒƒã‚¯ã‚’解放 |
ã“ã®ä¿æŒã™ã‚‹ã‹å¦ã‹ã®å®Ÿè£…ã¯ã€InnoDBã®ha_innobase::unlock_row()内ã«ã‚りã¾ã™ã€‚MySQLã‚‚Transactdもアンマッãƒã®æ™‚ã¯ã€unlock_row()を呼ã³å‡ºã—ã¾ã™ãŒã€InnoDBãŒREPEATABLE-READã¨SERIALIZABLEã®ã¨ãã¯ç„¡è¦–ã—ã¦ãƒãƒƒã‚¯ã‚’解放ã—ãªã„よã†ã«ãªã£ã¦ã„ã¾ã™ã€‚以下ã¯ãれを実装ã™ã‚‹InnoDBã®ã‚½ãƒ¼ã‚¹ã‚³ãƒ¼ãƒ‰æŠœç²‹ã§ã™ã€‚
// /mysql-5.6.20/storage/innobase/handler/ha_innodb.cc : 7222 switch (prebuilt->row_read_type) { case ROW_READ_WITH_LOCKS: if (!srv_locks_unsafe_for_binlog && prebuilt->trx->isolation_level > TRX_ISO_READ_COMMITTED) { break; } /* fall through */ case ROW_READ_TRY_SEMI_CONSISTENT: row_unlock_for_mysql(prebuilt, FALSE); break; case ROW_READ_DID_SEMI_CONSISTENT: prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT; break; }
row_read_typeãŒROW_READ_WITH_LOCKSã§ã‚ã‚‹ã¨ãã¯ã€ç›´å‰ã®èªã¿å–りã§ãƒãƒƒã‚¯ã‚’ã—ã¦ã„ã‚‹ã“ã¨ã‚’示ã—ã¾ã™ã€‚isolation_levelãŒTRX_ISO_READ_COMMITTEDより大ãã„å ´åˆã¯breakã—ã¦æ¬¡ã®ã‚¢ãƒ³ãƒãƒƒã‚¯é–¢æ•° row_unlock_for_mysql()ãŒå‘¼ã³å‡ºã•れã¾ã›ã‚“。
MySQLã®ãƒãƒƒã‚¯åˆ¶å¾¡
ã“ã“ã¾ã§ã¯InnoDBã®ãƒãƒƒã‚¯æ©Ÿèƒ½ã«ã¤ã„ã¦èª¬æ˜Žã—ã¾ã—ãŸã€‚ãれã¨ã¯åˆ¥ã«MySQLã«ã¯ãƒ†ãƒ¼ãƒ–ルãƒãƒƒã‚¯æ©Ÿèƒ½ãŒã‚りã¾ã™ã€‚ã¾ãŸã€MySQLãŒã©ã®ã‚ˆã†ã«ã€InnoDBã®ãƒãƒƒã‚¯ã‚’制御ã™ã‚‹ã‹èª¬æ˜Žã—ã¾ã™ã€‚
LOCK TABLES statement
LOCK TABLES statementã¯ã€InnoDBã®ãƒãƒƒã‚¯ã¨ã¯ç„¡é–¢ä¿‚ã§ã™ã€‚LOCK TABLESã¯ã€MySQLã®ç®¡ç†ã™ã‚‹ãƒ†ãƒ¼ãƒ–ルãƒãƒƒã‚¯ãƒžãƒãƒ¼ã‚¸ãƒ£ã®æ©Ÿèƒ½ã‚’利用ã—ã¦å®Ÿç¾ã™ã‚‹ã‚‚ã®ã§ã™ã€‚MySQLã®ãƒ†ãƒ¼ãƒ–ルæ“作ã¯handlerインターフェースを通ã˜ã¦è¡Œã„ã¾ã™ãŒã€handlerインターフェースã§ãƒ†ãƒ¼ãƒ–ルã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ã«ã¯äº‹å‰ã«å¿…ãšãƒ†ãƒ¼ãƒ–ルã®ãƒãƒƒã‚¯ã‚’å–å¾—ã—ãªã‘れã°ãªã‚Šã¾ã›ã‚“。
LOCK TABLES ... READã¯ã€ãƒãƒƒã‚¯ãƒžãƒãƒ¼ã‚¸ãƒ£ã‹ã‚‰æ›¸ãè¾¼ã¿ã‚’ブãƒãƒƒã‚¯ã™ã‚‹TL_READãƒãƒƒã‚¯(自身も他者もREADå¯ WRITEä¸å¯)ã‚’å–å¾—ã—ã¾ã™ã€‚以é™ã“ã®ãƒ†ãƒ¼ãƒ–ルã¯READãƒãƒƒã‚¯ã®å–å¾—ã®ã¿è¨±å¯ã•れã¾ã™ã€‚
LOCK TABLES ... WRITEã¯TL_WRITE排他ãƒãƒƒã‚¯(自身ã¯READ WRITEå¯ã€ä»–者ã¯READ WRITEä¸å¯)ã‚’å–å¾—ã—ã¦ã€ä»¥é™ã“ã®ãƒ†ãƒ¼ãƒ–ルã®ã™ã¹ã¦ã®ãƒãƒƒã‚¯å–得をブãƒãƒƒã‚¯ã—ã¾ã™ã€‚ã™ãªã‚ã¡ã€èªã¿å–りも書ãè¾¼ã¿ã‚‚ã§ããªããªã‚Šã¾ã™ã€‚
å–å¾—ã—ãŸãƒãƒƒã‚¯ã¯ã€UNLOCK TABLESã§é–‹æ”¾ã•れã¾ã™ã€‚
ã“ã®LOCK TABLESã¯ã€è¡Œãƒ¬ãƒ™ãƒ«ã®ãƒãƒƒã‚¯ã§ã¯ãテーブルå˜ä½ã®ãƒãƒƒã‚¯ãªã®ã§ã€æ›¸ãè¾¼ã¿ã®ã‚る複数トランザクションã®åŒæ™‚実行ã¯ã§ãã¾ã›ã‚“ã€‚åˆ†é›¢ãƒ¬ãƒ™ãƒ«ã®æ¦‚念もãªãトランザクションã¯å 有ã§ã™ã€‚ã‚ãˆã¦åˆ†é›¢ãƒ¬ãƒ™ãƒ«é¢¨ã«åå‰ã‚’ã¤ã‘る㨠EXCLUSIVE ã§ã™ã€‚
トランザクションã¯LOCK TABLES...ã§è‡ªå‹•ã§é–‹å§‹ã•れã¦ã„ã¾ã™ã€‚AUTOCOMMITãŒæœ‰åйã ã¨æ–‡ã®çµ‚了ã§COMMITã•れã€å¾Œã§ROLLBACKã§ããªããªã£ã¦ã—ã¾ã„ã¾ã™ã€‚複数ã®SQL文を発行ã™ã‚‹ã¨ãã¯LOCK TABLESã®å‰ã«ã€SET AUTOCOMMIT=0 ã§ç„¡åйã«ã—ã¦ãŠãã¾ã—ょã†ã€‚UNLOCK TABLESã®å‰ã«COMMITã¾ãŸã¯ROLLBACKã™ã‚‹ã“ã¨ã§ã€ã‚¢ãƒˆãƒŸãƒƒã‚¯ãªå‡¦ç†ãŒã§ãã¾ã™ã€‚
Transactdã§ãƒ†ãƒ¼ãƒ–ルをãƒãƒƒã‚¯ã™ã‚‹
å°‘ã—ã ã‘Transactdã§ã®å‡¦ç†ã‚’説明ã—ã¾ã™ã€‚
Transactdã§ã¯ã€ãƒ†ãƒ¼ãƒ–ルをオープンã™ã‚‹ã¨ãã®modeパラメータã«ã€TD_OPEN_EXCLUSIVE ã‹ TD_OPEN_READONLY_EXCLUSIVEを指定ã™ã‚‹ã“ã¨ã§ã€WRITEã¾ãŸã¯READã®ãƒ†ãƒ¼ãƒ–ルãƒãƒƒã‚¯ã‚’行ã†ã“ã¨ãŒã§ãã¾ã™ã€‚
MySQLã¯LOCK TABLES呼ã³å‡ºã—時ã«ã™ã¹ã¦ã®ãƒ†ãƒ¼ãƒ–ルã®åˆ—挙ãŒå¿…è¦ã§ã€å¾Œã‹ã‚‰ãƒ†ãƒ¼ãƒ–ãƒ«ã‚’è¿½åŠ ã—ãŸã‚Šã§ãã¾ã›ã‚“ãŒã€Transactdã¯å¾Œã‹ã‚‰ã„ãã¤ã§ã‚‚è¿½åŠ ã§ãã¾ã™ã€‚ã¾ãŸã€é€šå¸¸ãƒ¢ãƒ¼ãƒ‰ã¨EXCLUSIVEモードを混在ã•ã›ã¦ã‚ªãƒ¼ãƒ—ンã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚ã•らã«ã€ãれらã®ãƒ†ãƒ¼ãƒ–ãƒ«ãŒæ··åœ¨ã—ãŸãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³ã‚‚ãã®ã¾ã¾è¡Œãˆã¾ã™ã€‚SQLæ–‡ã«ã¯ã‚¢ãƒˆãƒŸãƒƒã‚¯ãªå‡¦ç†ã«ç‹¬ç‰¹ã®ç™–ãŒã‚りã¾ã™ãŒã€Transactdã«ã¯ãã®ã‚ˆã†ãªç‰¹åˆ¥ãªã“ã¨ã¯ä½•ã‚‚ã‚りã¾ã›ã‚“。
// テーブル1を排他ãƒãƒƒã‚¯ã§ã‚ªãƒ¼ãƒ—ン。 LOCK TABLES ... WRITEã¨åŒã˜ table* tb1 = db->openTable(name1, TD_OPEN_EXCLUSIVE); // テーブル2ã‚’READãƒãƒƒã‚¯ã§ã‚ªãƒ¼ãƒ—ン。 LOCK TABLES ... READã¨åŒã˜ table* tb2 = db->openTable(name2, TD_OPEN_READONLY_EXCLUSIVE); //ãƒãƒƒã‚¯ãƒ¢ãƒ¼ãƒ‰ãŒç•°ãªã‚‹ãƒ†ãƒ¼ãƒ–ãƒ«ãŒæ··åœ¨ã—ãŸãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³ã‚‚OKï¼ db->beginTrn(); ... tb2->seek(); ... tb1->update(); ... db->endTrn();
分離レベルã¨ãƒãƒƒã‚¯åˆ¶å¾¡
分離レベルã«å¿œã˜ã¦InnoDBãŒã©ã®ã‚ˆã†ã«èªã¿å–り時ã«ãƒãƒƒã‚¯ã‚’ã™ã‚‹ã‹ã‚’表ã«ã¾ã¨ã‚ã¾ã™ã€‚
èªã¿å–りã«ã¯ã€ãƒãƒƒã‚¯ãªã—ã¨æœ‰ã‚Š(SELECT...FOR UPDATE(X)ã¾ãŸã¯ SELECT...LOCK IN SHARE MODE(S)を使ã£ãŸèªã¿å–り)ãŒã‚りã¾ã™ã®ã§ã€ãれãžã‚Œã‚’トランザクションä¸ã«ä½¿ã†ã¨ã©ã®ã‚ˆã†ãªèªã¿å–り処ç†ã‚’ã™ã‚‹ã‹ãŒæ•´ç†ã§ãã¾ã™ã€‚ä½µã›ã¦ãƒãƒƒã‚¯æœ‰ã‚Šã®éš›ã«ã‚¢ãƒ³ãƒžãƒƒãƒãƒ¬ã‚³ãƒ¼ãƒ‰ã®ãƒãƒƒã‚¯é–‹æ”¾ã‚’行ã†ã‹ã©ã†ã‹ã‚‚åŠ ãˆã¦ãŠãã¾ã—ãŸã€‚
ãªãŠã€ã“ã“ã§ã®MySQLã®ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³ã¯ã€ START TRANSACTIONã§é–‹å§‹ã—COMMITã§çµ‚了ã™ã‚‹ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³ã¨è€ƒãˆã¦ãã ã•ã„。(1æ–‡ã§ã®è‡ªå‹•トランザクションも基本的ã«ã¯åŒã˜ã§ã™ãŒã€æ›´æ–°ã‚’å«ã¾ãªã„å ´åˆã€ãƒãƒƒã‚¯ã‚’ã—ãªã„ãªã©ã®æœ€é©åŒ–ãŒMySQL内部ã§è‡ªå‹•çš„ã«è¡Œã‚れã¾ã™ã€‚)
MySQLã®åˆ†é›¢ãƒ¬ãƒ™ãƒ«ã¨èªã¿å–りãƒãƒƒã‚¯ã‚¿ã‚¤ãƒ—表 | ||||
分離レベル | ãƒãƒƒã‚¯ãªã—READ | ãƒãƒƒã‚¯æœ‰READ*3 | アンマッãƒãƒ¬ã‚³ãƒ¼ãƒ‰ã®ãƒãƒƒã‚¯è§£æ”¾ | |
---|---|---|---|---|
SERIALIZABLE | ã§ããªã„ | Next key lock | ã—ãªã„ | |
REPEATABLE-READ | Consistent Nonlocking Readsトランザクション内ã§åŒä¸€ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã®ã‚¹ãƒŠãƒƒãƒ—ショット | Next key lock | ã—ãªã„ | |
READ-COMMITED | Consistent Nonlocking Reads1ã¤ã®SQL文内ã§åŒä¸€ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã®ã‚¹ãƒŠãƒƒãƒ—ショット | row lock | ã™ã‚‹ |
ãªãŠã€æ›´æ–°ã‚„削除を行ã†å ´åˆã¯ã€å¯¾è±¡ãƒ¬ã‚³ãƒ¼ãƒ‰ã®èªã¿å–り時ã«è‡ªå‹•ã§æŽ’ä»–ãƒãƒƒã‚¯(X)ã®å–å¾—ãŒãƒˆãƒ©ã‚¤ã•れã€å–å¾—ã§ãれã°å®Ÿè¡Œã•れã¾ã™ã€‚
ã¾ã¨ã‚
ã“ã“ã¾ã§è¦‹ã¦ããŸInnoDBã®ä»•様やãƒãƒƒã‚¯ã®ç‰¹æ€§ã‹ã‚‰ã€MySQLã®SQLæ–‡ã§ãƒŸãƒƒã‚·ãƒ§ãƒ³ã‚¯ãƒªãƒ†ã‚£ã‚«ãƒ«ãªã‚¢ãƒ—リケーションを書ãå ´åˆã«å¤§åˆ‡ãªã“ã¨ã‚’ã¾ã¨ã‚ã¾ã™ã€‚
- 分離レベルã®ãƒ‡ãƒ•ォルトã¯ã€REPEATABLE-READã«ã™ã‚‹ã€‚(以下ã®å‰ææ¡ä»¶ï¼‰
- ã‚¢ãƒˆãƒŸãƒƒã‚¯ãªæ“作ã¯ã€ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³ã§(START TRANSACTION ... COMMIT)ã§è¡Œã†ã€‚
- 複数ã®SQLæ–‡ã«ã‚ˆã‚‹èªã¿å–りã§ä¸€è²«æ€§ãŒå¿…è¦ãªã‚‰ã€æ›´æ–°ãŒç„¡ãã¨ã‚‚トランザクション内ã§(START TRANSACTION ... COMMIT)ã§èªã¿å–る。
- 行ãƒãƒƒã‚¯ã¯ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³å†…ã§ã‚ã£ã¦ã‚‚ã€SELECT...FOR UPDATE(X)ã¾ãŸã¯ SELECT...LOCK IN SHARE MODE(S)を使ã£ã¦æ˜Žç¤ºçš„ã—ãªã‘れã°è¡Œã‚れãªã„。ãŸã ã—ã€åˆ†é›¢ãƒ¬ãƒ™ãƒ«ã‚’SERIALIZABLEã«ã™ã‚Œã°ã€æ˜Žç¤ºã—ãªã„èªã¿å–りも共有ãƒãƒƒã‚¯(S)ãŒå–å¾—ã§ãる。
- (REPEATABLE-READã®)トランザクション内ã«ãŠã„ã¦ã€ãƒãƒƒã‚¯ãªã—èªã¿å–ã‚Šã¨æ›´æ–°å‡¦ç†ã®æ··åœ¨ã«æ³¨æ„ã™ã‚‹ã€‚ã“ã®çµ„ã¿åˆã‚ã›ã¯ã€REPEATABLE-READã§ã¯ãªãã€ç•°ãªã£ãŸå€¤ã‚’èªã‚€ã“ã¨ãŒã‚る。å—ã‘入れられãªã„å ´åˆã¯ã€ã™ã¹ã¦ã®èªã¿å–りをãƒãƒƒã‚¯ä»˜èªã¿å–りã«ã™ã‚‹ã‹ã€SERIALIZABLEã«ã™ã‚‹ã€‚
- ファントムリードãŒå•題ã«ãªã‚‰ãªã„トランザクションã§ã‚れã°ã€åŒæ™‚実行性をå‘上ã™ã‚‹ãŸã‚ã«READ-COMMITEDを使ã†ã€‚
- ãƒ†ãƒ¼ãƒ–ãƒ«ã‚’å æœ‰ã—ãŸã„ã¨ãã¯ã€SET AUTOCOMMIT=0ã®å¾Œã§ã€LOCK TABLES ... を呼ã³ã€å‡¦ç†çµ‚了後ã«COMMITã¾ãŸã¯ROLLBACKã—ã¦ã‹ã‚‰ã€UNLOCK TABLESを呼ã³å‡ºã™ã€‚テーブルãƒãƒƒã‚¯ã¯ãƒ†ãƒ¼ãƒ–ãƒ«ã‚’å æœ‰ã—ã¦ã—ã¾ã†ã®ã§ã€ãƒžãƒ«ãƒãƒ¦ãƒ¼ã‚¶ãƒ¼ç’°å¢ƒã§ã¯ç‰¹åˆ¥ãªçжæ³ä»¥å¤–使用ã—ã¦ã¯ã„ã‘ãªã„。
ã„ã‹ãŒã ã£ãŸã§ã—ょã†ã‹ï¼Ÿ
ã“れらをç†è§£ã—実践ã™ã‚‹ã“ã¨ãŒãƒŸãƒƒã‚·ãƒ§ãƒ³ã‚¯ãƒªãƒ†ã‚£ã‚«ãƒ«ãªã‚¢ãƒ—リケーションã®ç¬¬ä¸€æ©ã«ãªã‚‹ã¨æ€ã„ã¾ã™ã€‚何ã‹å‚考ã«ãªã‚Œã°ã„ã„ãªã¨æ€ã„ã¾ã™ã€‚
次回ã€ãã®2ã§ã¯Transactdã®InnoDBãƒãƒƒã‚¯åˆ¶å¾¡ã«ã¤ã„ã¦è©³ã—ãæ›¸ããŸã„ã¨æ€ã„ã¾ã™ã€‚
*1:å‚考コード /mysql-5.6.20/storage/innobase/lock/lock0lock.cc : 5011 lock_rec_print()
*2:ã©ã¡ã‚‰ã«ãªã‚‹ã‹ã¯æ¤œç´¢æ¡ä»¶ã«ã‚ˆã£ã¦å¤‰ã‚りã¾ã™
*3:SELECT...FOR UPDATE(X)ã¾ãŸã¯ SELECT...LOCK IN SHARE MODE(S)を使ã£ãŸèªã¿å–り
PlanetMySQL Voting: Vote UP / Vote DOWN