ãªã¬ãŒã·ã§ãã«ããŒã¿ããŒã¹ãžã®ç«¶äºåã®ããã¢ã¯ã»ã¹ã®åé¡ã¯ãã¢ããªã±ãŒã·ã§ã³ãœãããŠã§ã¢éçºè ã ãã§ãªããã»ãšãã©ãã¹ãŠã®ã¢ããªã±ãŒã·ã§ã³ãœãããŠã§ã¢éçºè ãçŽé¢ããŠããŸãã ãã®é åã«å¯Ÿãããã®éèŠã®çµæã¯ãå€æ°ã®äœæãããã¢ãŒããã¯ãã£ãã¿ãŒã³ã®ååšã§ãã ããã«ããããã®ãããªããã°ã©ã ã®éçºã®å€§ããªè€éãã«ããŸã察åŠã§ããŸãã 以äžã§ã¯ããã®ãããªã¬ã·ããšããããã®å®è£ ãåºã¥ããŠããã¡ã«ããºã ã«ã€ããŠèª¬æããŸãã ç©èªã¯Javaã³ãŒãã®äŸã§èª¬æãããŸãããã»ãšãã©ã®è³æã¯èšèªåºæã§ã¯ãããŸããã ãã®èšäºã®ç®çã¯ããããã¯ãå®å šã«ç¶²çŸ ããã®ã§ã¯ãªããäž»é¡ã®çŽ¹ä»ãšããŠããªã¬ãŒã·ã§ãã«ããŒã¿ããŒã¹ãžã®ç«¶åã¢ã¯ã»ã¹ã®åé¡ã説æããããšã§ãã
競äºåã®ããã¢ã¯ã»ã¹ã®åé¡
ç¶æ³ãèæ ®ããŠãã ããã ç¹å®ã®äŒèšã·ã¹ãã ã§ã¯ãæžé¡ã®ä¿ç®¡äžã«ååã®æ®é«ã®å€åãåæ ããå¿ èŠããããŸãã è°è«ãããå®è³ªçã«ããããã«ãPostgreSQLã§å®è¡ããäŸãæäŸããŸãã äŒèšã·ã¹ãã ãšãã¹ãããŒã¿ã®ããŒã¿ããŒã¹æ§é ã¯æ¬¡ã®ãšããã§ãã
CREATE TABLE stocks ( id integer PRIMARY KEY, name varchar(256) NOT NULL, quantity decimal(10,2) NOT NULL DEFAULT 0.0 ); CREATE TABLE documents ( id integer PRIMARY KEY, quantity decimal(10,2) NOT NULL DEFAULT 0.0, processed boolean NOT NULL DEFAULT false, stock integer REFERENCES stocks ); INSERT INTO stocks (id, name, quantity) VALUES (1, '', 56.4), (2, '', 26.8); INSERT INTO documents (id, quantity, stock) VALUES (1, 15.6, 1), (2, 26.1, 1);
ç§ãã¡ã®ããã¥ã¡ã³ããå庫ããååãååŽãã責任ããããšããŸãããã ã¢ããªã±ãŒã·ã§ã³ã³ãŒãã¯ããã¥ã¡ã³ããšæ®ãã®ããŒã¿ãããŒãããèšç®ãå®è¡ããŠãããŒã¿ããŒã¹ã«ããŒã¿ãä¿åããŸãã ãã®ã¢ã¯ã·ã§ã³ã1ã€ã®ã¢ããªã±ãŒã·ã§ã³ã«ãã£ãŠå®è¡ãããå Žåããã¹ãŠãæ£åžžã«è¡ãããŸãã
SELECT quantity, processed, stock FROM documents WHERE id = 1;
quantity | processed | stock ----------+-----------+------- 15.60 | f | 1
SELECT name, quantity FROM stocks WHERE id = 1;
name | quantity ------+---------- | 56.40
èå¥åã1ã®ããã¥ã¡ã³ãã®ããŒã¿ãšã察å¿ããããã¥ã¡ã³ãã®æ®ãã®ããŒã¿ãããŒããããŸãã æ®ãã®æ°ããå€ã¯ã56.40-15.60 = 40.80ãæžãèœãšããŠèšç®ãããããŒã¿ã¯ææžã®åŠçã«é¢ããã¡ã¢ãšãšãã«ä¿åãããŸããã
UPDATE stocks SET quantity = 40.80 WHERE id = 1; UPDATE documents SET processed = true WHERE id = 1;
ããããã·ã³ã°ã«ãŠãŒã¶ãŒã·ã¹ãã ã¯é·ãéå»ã§ãã çŸåšããŠãŒã¶ãŒã䞊ã¶ã¹ãããžãã¹ã¢ããªã±ãŒã·ã§ã³ãæ³åããããšã¯äžå¯èœã§ãã ãããã£ãŠã2ã€ã®ããã¥ã¡ã³ããåæã«åŠçãããç¶æ³ãèããŠã¿ãŸãããã æåã®å Žåãšåæ§ã«ãã¢ããªã±ãŒã·ã§ã³ã¯ããŒã¿ããŒã¹ããããŒã¿ãèªã¿åããŸãã
æåã®ã¢ããªã±ãŒã·ã§ã³
SELECT quantity, processed, stock FROM documents WHERE id = 1;
quantity | processed | stock ----------+-----------+------- 15.60 | f | 1
SELECT name, quantity FROM stocks WHERE id = 1;
name | quantity ------+---------- | 56.40
2çªç®ã®ã¢ããªã±ãŒã·ã§ã³
SELECT quantity, processed, stock FROM documents WHERE id = 2;
quantity | processed | stock ----------+-----------+------- 26.10 | f | 1
SELECT name, quantity FROM stocks WHERE id = 1;
name | quantity ------+---------- | 56.40
ãããŠãããã§æãããªåé¡ãçºçããŸããæåã®ã¢ããªã±ãŒã·ã§ã³ã¯56.40-15.60 = 40.80ãèšç®ãã2çªç®ã®ã¢ããªã±ãŒã·ã§ã³ã¯56.40-26.10 = 30.30ãèšç®ããŸãã ãããŠããããã®çµæã®ãããããããŒã¿ããŒã¹ã«æžã蟌ãŸããŸãã æåŸã®æŽæ°èŠæ±ãå®è¡ããã察象ã ããã¯æããã«ãŠãŒã¶ãŒãæåŸ ãããã®ã§ã¯ãããŸããã ãã®çš®ã®åé¡ã¯ã䞊åããã°ã©ãã³ã°ã§ããç¥ãããŠããã競åç¶æ ãšåŒã°ããŸãã ãã®ã±ãŒã¹ã¯ãäžè¬åãread-modify-writeã®è€åã¢ã¯ã·ã§ã³ã§ãã
åŠçããããã¥ã¡ã³ãïŒåŠçæžã¿ãã£ãŒã«ãïŒããã§ãã¯ããå®éã®ã¢ããªã±ãŒã·ã§ã³ã§ãããè¡ããªããã°ãªããªãå Žåããã§ãã¯ã«ãããããããããã¥ã¡ã³ãã2ååŠçãããå¯èœæ§ããããŸãã ãã¹ãŠã競åç¶æ ã§ããããŸãããç°ãªãçš®é¡ã®check-then-actæäœã§ãã ããã«ãæŽæ°èŠæ±ã®ééã§ã¯ãããŒã¿ããŒã¹ã¯äžè²«æ§ã®ãªãç¶æ ã«ãããŸããã€ãŸããããã¥ã¡ã³ãã¢ã¯ã·ã§ã³ã¯æ¢ã«å®äºããŠããŸãããããã¥ã¡ã³ãã¯åŠçæžã¿ãšããŠããŒã¯ãããŠããŸããã
ãã®çµæãããŒã¿ããŒã¹ãžã®äžæ£ãªç«¶åã¢ã¯ã»ã¹ã§çºçããæãäžè¬çãªåé¡ã2ã€ãããŸãã ããã¯ãèªã¿åã/å€æŽ/æžã蟌ã¿ã®ç«¶åç¶æ ãçºçããå Žåã«çºçããå€æŽã®æ倱ã§ãã ãããŠãæŽæ°ãªã¯ãšã¹ãéã®ããŒã¿ã®äžè²«æ§ã®ãªãç¶æ ã
DBMSã¡ã«ããºã
ãªã¬ãŒã·ã§ãã«ããŒã¿ããŒã¹ãžã®ç«¶äºåã®ããã¢ã¯ã»ã¹ã®ããã®ç¹å®ã®ã¬ã·ããè°è«ããã«ã¯ãDBMSãšããã°ã©ãã³ã°ããŒã«ãæäŸããäœã¬ãã«ã®ã¡ã«ããºã ã«ç²ŸéããŠããå¿ èŠããããŸãã ãããã¯ãå®è£ ã®ããŒã¹ãšãªãæè¡èŠçŽ ã§ãã äž»ãªèŠçŽ ã¯ããã©ã³ã¶ã¯ã·ã§ã³ãšããã¯ã§ãã ãããã«ã€ããŠããã«èª¬æããŸãã
ãã©ã³ã¶ã¯ã·ã§ã³ãšåé¢ã¬ãã«
ãã©ã³ã¶ã¯ã·ã§ã³ã¯ããã©ã³ã¶ã¯ã·ã§ã³ãããŒã«ããã¯ãŸãã¯ç¢ºèªããæ©èœãåããããŒã¿ããŒã¹ãšå¯Ÿè©±ããããã®åäžã®æäœã·ãŒã±ã³ã¹ã§ãã ãã©ã³ã¶ã¯ã·ã§ã³ã¯ãå€æŽã®äžè²«æ§ã®åé¡ã解決ããæ段ã«ãªãå¯èœæ§ããããã¬ãŒã¹ã®ç¶æ³ãèš±å¯ããŸããã æåãŸãã¯äž¡æ¹ã®åé¡ã解決ããããã®ãã©ã³ã¶ã¯ã·ã§ã³ã®é©åæ§ã¯ãåé¢ã¬ãã«ã«ãã£ãŠç°ãªããŸãã åé¢ã¯ãåäžã®æäœã«ãã£ãŠè¡ãããå€æŽã競åããæäœã«ã©ã®ããã«/ãã€è¡šç€ºãããããå®çŸ©ããããããã£ã§ãã
SQLæšæºã§ã¯ãéã³ãããèªã¿åããã³ãããèªã¿åããç¹°ãè¿ãèªã¿åããã·ãªã¢ã«åã®4ã€ã®åé¢ã¬ãã«ãå®çŸ©ããŠããŸãã ãããã¯ãã¹ãŠãæäœèš±å®¹ã¬ãã«ã®æç±æãåããŠããŸãã ãããã®ã¬ãã«ã®åºæ¬çãªããããã£ã¯ãååããæãããªã¯ãã§ãã ããŸããŸãªDBMSããããŸããŸãªæ¹æ³ã§åé¢ã¿ã€ãã®ãµããŒããå®è£ ããå ŽåããããŸãã äž»ãªããšã¯ãåå®è£ ã§ã¯ãã¬ãã«ã§èŠå®ãããŠãããããå³ãããªãåé¢ãèš±å¯ããªãããšã§ãã ããšãã°ãPostgreSQLã¯å éšã§2ã€ã®åé¢ã¬ãã«ã®ã¿ããµããŒãããŸãïŒã³ãããã®èªã¿åããšã·ãªã¢ã©ã€ãºå¯èœã§ãã ãããã®åé¢ã¬ãã«ã䜿çšããŠãäžèšã®äŸã§èª¬æããåé¡ã解決ããããšãæ€èšããŠãã ããã
Read Committed Isolation LevelïŒPostgreSQLã§ããã©ã«ãã§äœ¿çšïŒã䜿çšãããšãããŒã¿ç¶æ ã®äžè²«æ§ã®åé¡ã解決ã§ããŸãã ããã¯ããã©ã³ã¶ã¯ã·ã§ã³å ã§è¡ããããã¹ãŠã®å€æŽããçŸåšã®ãã©ã³ã¶ã¯ã·ã§ã³ã®åŸã競åãããã©ã³ã¶ã¯ã·ã§ã³ããèŠããããã«ãªããšããäºå®ã«ããéæãããŸãã
BEGIN; SELECT quantity, processed, stock FROM documents WHERE id = 1; SELECT name, quantity FROM stocks WHERE id = 1; -- UPDATE stocks SET quantity = 40.80 WHERE id = 1; UPDATE documents SET processed = true WHERE id = 1; COMMIT;
ãããããã®ãããªãã©ã³ã¶ã¯ã·ã§ã³ã¯ã競äºåã®ãããªãã¬ãŒã·ã§ã³ã®å®è¡ã«ããã競åã®ç¶æ ã«é¢ããåé¡ã解決ããŸããã ãã®ãããªç¶æ³ã§ã¯ãå¥ã®ã¬ãã«ã®åé¢ã圹ç«ã¡ãŸã-ã·ãªã¢ã©ã€ãºå¯èœã ããã¯å¯èœãªè§£æ±ºçã§ãããããã ãã§ã¯ãããŸããã PostgreSQLã®Serializableåé¢ã¬ãã«ã®å®è£ ã®åäœã¯ãååãšå®å šã«ã¯äžèŽããŠããŸããã ã€ãŸããSerializableåé¢ã¬ãã«ãæã€ãã¹ãŠã®ãã©ã³ã¶ã¯ã·ã§ã³ã¯é 次å®è¡ãããŸããã 代ããã«ããã©ã³ã¶ã¯ã·ã§ã³ãã³ããããããšãã«ãããŒã¿ãå€æŽããããšãã«ç«¶åããã§ãã¯ããã競åãããã©ã³ã¶ã¯ã·ã§ã³ã«ãã£ãŠããŒã¿ãæ¢ã«å€æŽãããŠããå ŽåãçŸåšã®ãã©ã³ã¶ã¯ã·ã§ã³ã¯å€±æããŸãã
BEGIN ISOLATION LEVEL SERIALIZABLE; SELECT quantity, processed, stock FROM documents WHERE id = 1; SELECT name, quantity FROM stocks WHERE id = 1; -- UPDATE stocks SET quantity = 40.80 WHERE id = 1; UPDATE documents SET processed = true WHERE id = 1; COMMIT;
äžèšã®ãã©ã³ã¶ã¯ã·ã§ã³ã¯ãã¬ãŒã¹ã®ç¶æ³ãšããŒã¿ã®äžè²«æ§ã®äž¡æ¹ã«é¢ããåé¡ã解決ããŸãã ãã®ã¢ãããŒãã®ç¹åŸŽã¯ããã®ãã©ã³ã¶ã¯ã·ã§ã³ãå®è¡ããã³ãŒããããã©ã³ã¶ã¯ã·ã§ã³ã®å®äºåŸã«ã®ã¿æåã«ã€ããŠåŠç¿ããããšã§ãã ãããŠã倱æã®çµæãšããŠããã©ã³ã¶ã¯ã·ã§ã³ãæåããããã¢ã¯ã·ã§ã³ã®å®è¡ãæåŠãã決å®ãäžããããŸã§ããã¹ãŠã®ã¢ã¯ã·ã§ã³ãšèšç®ãç¹°ãè¿ãå¿ èŠããããŸãã ç¹°ãè¿ãã®ããã«å€§éã®ãªãœãŒã¹ãæ¶è²»ãããããããã®åäœã¯å€§ããªç«¶åè² è·ã§ã¯äžååã§ãã ãã®åäœã¯ã楜芳çåæå®è¡å¶åŸ¡ãšåŒã°ããŸãã
äžèšã®äŸã¯ãããžãã¹ããžãã¯ãã¢ããªã±ãŒã·ã§ã³ã³ãŒãã«å®å šã«å®è£ ãããããŒã¿ããŒã¹ãã¹ãã¬ãŒãžãšããŠã®ã¿æ©èœãããšããåæã«åºã¥ããŠããŸãã
ããã©ãŒãã³ã¹ã«åœ±é¿ãããã©ã³ã¶ã¯ã·ã§ã³ã®äœ¿çšã«ãããéèŠãªè©³çŽ°ã¯ããã®é·ãã§ãã ãã©ã³ã¶ã¯ã·ã§ã³ã¯é·ãããŠã¯ãªããŸããããã©ã³ã¶ã¯ã·ã§ã³ãéãå®äºããã»ã©ãã·ã¹ãã ã®ããã©ãŒãã³ã¹ãåäžããŸãã ãã®ã³ã¡ã³ãã¯ãå°æ°ã®ãŠãŒã¶ãŒãããã¢ããªã±ãŒã·ã§ã³ã§ããã¥ã¡ã³ãã®ç·šéãå®è¡ããã³ãŒãã«ãšã£ãŠéèŠã§ã¯ãªãå ŽåããããŸãã ãã ããããšãã°ãããŒã¿ããŒã¹ãšå¯Ÿè©±ããå€æ°ã®ã¯ã©ã€ã¢ã³ãã§äœ¿çšãããWebãµãŒãã¹ã®ç¶æ³ã§ã¯ãããã¯éèŠã§ãã
ããã¯
䞊åããã°ã©ãã³ã°ã§ã¯ãããã¯ã¡ã«ããºã ã䜿çšããŠå®è¡ã¹ã¬ãããå¶åŸ¡ããŸãã ããã¯ã䜿çšãããšãç¹å®ã®é åãžã®ã¢ã¯ã»ã¹ãã·ãªã¢ã«åã§ããŸãã DBMSã¯ãããŒã¿ãžã®ã¢ã¯ã»ã¹ãå¶åŸ¡ããããã¯ã¡ã«ããºã ããµããŒãããŠããŸãã PostgreSQLã®äŸã䜿çšããŠããã®ã¡ã«ããºã ã®å¯èœæ§ãèããŠã¿ãŸãããã
PostgreSQLã¯å€ãã®çš®é¡ã®ããã¯ããµããŒãããŠããŸãã äž»ãªç¹åŸŽã¯ãçŸåšã®çš®é¡ã®ããã¯ãšç«¶åããå€ãã®çš®é¡ã®ããã¯ã§ãã 競åãšã¯ã競åããã¿ã€ãã®ããã¯ãšäžç·ã«çŸåšã®ããã¯ããã£ããã£ã§ããªãããšãæå³ããŸãã ããã«ãããã¯ã¯æ瀺çãšæé»çã«åããããŸãã æ瀺çããã¯ãšã¯ãlockããŒã¯ãŒããšãæŽæ°ãŸãã¯å ±æãã€ãŸããŠãŒã¶ãŒãæå®ããå ±æã®ããã®ã¯ãšãªä¿®é£Ÿåã䜿çšããŠãã¯ãšãªã§å®è¡ãããããã¯ã§ãã æé»çããã¯ã¯ãããŸããŸãªèŠæ±ïŒéžæãæŽæ°ãæ¿å ¥ãå€æŽãªã©ïŒã®éã«ãã£ããã£ãããããã¯ã§ãã PostgerSQLã¯ãã¢ããã€ã¶ãªããã¯ãšåŒã°ããå¥ã®çš®é¡ã®ããã¯ããµããŒãããŠããŸãã
ããã¯ã¯ããªã¯ãšã¹ããå®è¡ãããŠããçŸåšã®ãã©ã³ã¶ã¯ã·ã§ã³ãçµäºãããŸã§ãã£ããã£ãããŸãã ããšãã°ãä»®æ³äŒèšã·ã¹ãã ã§ã¯ãæäœãå®è¡ãããæ®ãã®éšåã«å¯Ÿå¿ããstocksããŒãã«ã®è¡ãšããã¥ã¡ã³ãããŒãã«ã®è¡ã§æä»ããã¯ãååŸããããšãå¯èœã§ãããããã«ãã£ãŠçŸåšã®ãã©ã³ã¶ã¯ã·ã§ã³ã®ã¿ããã®ããŒã¿ã«ã¢ã¯ã»ã¹ã§ããããšãä¿èšŒããŸãã
BEGIN; SELECT quantity, processed, stock FROM documents WHERE id = 1 FOR UPDATE; SELECT name, quantity FROM stocks WHERE id = 1 FOR UPDATE; -- UPDATE stocks SET quantity = 40.80 WHERE id = 1; UPDATE documents SET processed = true WHERE id = 1; COMMIT;
äžèšã®ã³ãŒãã¯ãããã¥ã¡ã³ãããã³æ ªåŒããŒãã«ã®è¡ã®ããã¯ããã£ããã£ããŸãã ãã®å ŽåãæŽæ°çšã®ããŒã¯ãŒããã¯ãšãªã«è¿œå ãããéžæããŒã¿ãéžæãããŸãã ããã¯ãæŽæ°ã®ããã®è¡ã®æ瀺çãªãããã¯ã§ãã ãã®å ŽåãããŒãã«å šäœããããã¯ããŠãå¹æã¯ãããŸããã äžè¬ã«ãããŒãã«ãããã¯ããå¿ èŠãããã®ã¯ãããŒã¿ãå«ã倧èŠæš¡ãªæäœã®å Žåã®ã¿ã§ããããããã¯éåžžã«ãŸããªã±ãŒã¹ã§ãã ããããªããšããã¹ãŠã®åŒã³åºããã·ãªã¢ã«åãããããã競åã¢ã¯ã»ã¹ã§ããã©ãŒãã³ã¹ã®åé¡ãçºçããŸãã
ãã§ã«ããã¯ãããŠããé åã®ããã¯ããã£ããã£ããããšãããšãããã¯ã解é€ããããŸã§ãªã¯ãšã¹ãããããã¯ãããŸãïŒããã©ã«ãïŒããŸãã¯ããããããã¯ã®å Žåããšã©ãŒã¡ãã»ãŒãžãè¿ãããŸãã ãããã¯ãããèŠæ±ããå¶åŸ¡ãè¿ãééãèšå®ããããšããããã¯ãååŸã§ããªãããšã«é¢ããã¡ãã»ãŒãžãããã«åä¿¡ããããšãã§ããŸãïŒnowaitïŒã
競äºã³ã³ãããŒã«ã®çš®é¡
競åå¶åŸ¡ã¯ã競åãµã€ãã§ã®äžŠåå®è¡ã¹ã¬ãããçžäºäœçšããã«ãŒã«ã§ãã 競äºç®¡çã¯ãèšç®çµæã®æ£ç¢ºæ§ãä¿èšŒããå¿ èŠããããŸãã è¿œå ã®ç®æšã¯ãç¹å®ã®ã±ãŒã¹ã§å¯èœãªéãè¿ éã«çµæãååŸããããšã§ãã 競åå¶åŸ¡ã¯éåžžã競ååŠçã®æéã«å¿ããŠã楜芳çïŒæ¥œèŠ³çïŒãæ²èŠ³çïŒæ²èŠ³çïŒãããã³éšåç楜芳çïŒå楜芳çïŒã®ã¿ã€ãã«åé¡ãããŸãã
楜芳çãªç«¶äºå¶åŸ¡ã«ã¯ãã¢ã¯ã·ã§ã³ã®æœåšçãªç«¶åã®ãã§ãã¯ãå«ãŸããŸãã ããšãã°ããŠãŒã¶ãŒã¯ãªããžããªã«ããŒã¿ãèŠæ±ããŠå€æŽãããã®åŸãå€æŽãä¿åããããšããŸãã ãªããžããªå ã®ããŒã¿ã®çŸåšã®ããŒãžã§ã³ããå€æŽãè¡ãããããŒã¿ã®ããŒãžã§ã³ã«å¯Ÿå¿ããå Žåã競åã¯çºçãããããŒã¿ãä¿åã§ããŸãã å察ã®å Žåã競åãçºçããã¢ã¯ã·ã§ã³ãåå®è¡ããããã¢ã¯ã·ã§ã³ãæåŠããããšã§åŠçãããŸãã 楜芳çãªç«¶äºå¶åŸ¡ã¯ã競äºåã®ããã¢ã¯ã»ã¹ã«å¯Ÿãã競äºãæ¯èŒçå°ãªãè¯å¥œãªããã©ãŒãã³ã¹ãæäŸããŸãã
æ²èŠ³çãªç«¶äºç®¡çã«ã¯ãã¢ã¯ã·ã§ã³ãå®è¡ããåã«æœåšçãªç«¶åããã§ãã¯ããããšãå«ãŸããŸãã ã€ãŸããä¿è·ãããé åã§ç«¶åããå®è¡ã¹ã¬ãããã·ãªã¢ã«åãããŸãã ããã«ããã競äºåã®ããã¢ã¯ã»ã¹ã®ããã®é«ã競äºåã§çç£æ§ãåäžããŸãã
éšåçã«æ¥œèŠ³çã¯ãäž¡æ¹ã®ã¢ãããŒããåæã«é©çšãããæ··ååã§ãã
建ç¯ãã¿ãŒã³
ãã®æç¹ã§ãèªè ã¯ç«¶åã¢ã¯ã»ã¹ã®åé¡ãšãããã解決ããDBMSã¡ã«ããºã ã®äžè¬çãªæŠå¿µãç解ããŠããã¯ãã§ãã ãã®ã»ã¯ã·ã§ã³ã§ã¯ãããŒã¿ããŒã¹ãžã®ç«¶äºçã¢ã¯ã»ã¹ã®åé¡ã«å¯Ÿãããœãªã¥ãŒã·ã§ã³ãè¡šãã¢ãŒããã¯ãã£ãã¿ãŒã³ã«çŠç¹ãåœãŠãŸãã 以äžã¯å®å šãªèª¬æã§ã¯ãªããäžè¬çãªã¢ã€ãã¢ãšäŸã§ãã 詳现ãªèª¬æã«ã€ããŠã¯ãèšäºã®äžéšã«ãããªã³ã¯ãã¯ãªãã¯ããŠãã ããã
DBMSã䜿çšããå ŽåãããŒã¿ã¯ã¢ããªã±ãŒã·ã§ã³ã®ã¡ã¢ãªã«èªã¿èŸŒãŸãããããã䜿çšããŠããŸãã¯ããããä»ããŠã¢ã¯ã·ã§ã³ãå®è¡ãããŸããã¢ã¯ã·ã§ã³ã®çµæã¯ãååãšããŠä¿åãçŽãå¿ èŠããããŸãã ãã®éãäœãå€æŽãããããç¥ãããã«ãããŒã¿ã®å€æŽã«é¢ããæ å ±ãä¿åããå¿ èŠããããŸãã ããã«ãäœæããã³åé€ããããªããžã§ã¯ãã«é¢ããæ å ±ãä¿åããå¿ èŠããããŸãã ãã¡ãããããŒã¿ããŒã¹å ã®ãã¹ãŠã®å€æŽãããã«åæ ã§ããŸãã ãã®å Žåã次ã®åé¡ãçºçããŸããã·ã¹ãã ãã©ã³ã¶ã¯ã·ã§ã³ã«ã¯éåžžã«é·ãæéãããããããŒã¿ããŒã¹ãžã®å€æŽã«å¯Ÿããããã¯ããã©ã³ã¶ã¯ã·ã§ã³å šäœã«ããã£ãŠä¿æãããããã競åã¢ã¯ã»ã¹äžã«ç«¶åãçºçããŸãã ããŒã¿ããŒã¹ãšã®å¯Ÿè©±ã¯å€ãã®å°ããªéšåã«åå²ãããŸããããããå¹æããããŸããã ããŒã¿å€æŽã®è¿œè·¡ã®åé¡ã解決ããããã«ãäœæ¥åäœãã¿ãŒã³ã«ã€ããŠèª¬æããŸãã ãã®ãã¿ãŒã³ã¯ããã¹ãŠã®å€æŽã远跡ããå€æŽãããŒã¿ããŒã¹ã«é©çšããŠããã®ç¶æ ãè¡ã£ãå€æŽãšäžèŽããããªããžã§ã¯ããèšè¿°ããŸãã
public class UnitOfWork { private List<DomainObject> newObjects; private List<DomainObject> updatedObjects; private List<DomainObject> deletedObjects; /** * * @return */ public DomainObject create() { DomainObject domainObject = new DomainObject(); newObjects.add(domainObject); return domainObject; } /** * * @param domainObject */ public void update(DomainObject domainObject) { updatedObjects.add(domainObject); } /** * * @param domainObject */ public void remove(DomainObject domainObject) { deletedObjects.add(domainObject); } /** * */ public void commit() { // SQL INSERT insert(newObjects); // SQL UPDATE udpate(updatedObjects); // SQL DELETE delete(deletedObjects); } // insert, update, delete }
äžèšã¯ãäœæ¥åäœãã¿ãŒã³ã®æãåçŽãªå®è£ ã§ãã DomainObjectsã¯ãé©åãªã¢ã¯ã·ã§ã³ãå®è¡ããããšãã«UnitOfWorkãªããžã§ã¯ãã«ç»é²ã§ããŸãã ããžãã¹ãã©ã³ã¶ã¯ã·ã§ã³ãå®äºããåŸãã¢ããªã±ãŒã·ã§ã³ã¯UnitOfWorkãªããžã§ã¯ãã®commitã¡ãœãããåŒã³åºããŸãã
éåžžãããžãã¹ãã©ã³ã¶ã¯ã·ã§ã³ã«ã¯é·ãæéãããããŸãã ååãšããŠãè€æ°ã®ã·ã¹ãã ãã©ã³ã¶ã¯ã·ã§ã³ã«æ¡åŒµãããŸãã ãã®çç±ã¯ãã§ã«äžã§è¿°ã¹ã-é·ãããã¯ãã£ããã£ã®åé¡ã DBMSåæã¡ã«ããºã ã¯1ã€ã®ã·ã¹ãã ãã©ã³ã¶ã¯ã·ã§ã³å ã§ã®ã¿æ©èœãããããç¬èªã®åæã¡ã«ããºã ãå®è£ ããå¿ èŠããããŸããããã¯ãããã€ãã®ã·ã¹ãã ãã©ã³ã¶ã¯ã·ã§ã³ã®äžã§åäœããŸãã ãã®åé¡ã解決ããããã«ã楜芳çããã³æ²èŠ³çãªã¿ã€ãã®ç«¶åå¶åŸ¡ãå®è£ ãã2ã€ã®æ¥œèŠ³çãªãã©ã€ã³ããã¯ããã³æ²èŠ³çãªãã©ã€ã³ããã¯ãã¿ãŒã³ã«ã€ããŠèª¬æããŸãã
ãŠãŒã¶ãŒãç·šéãã©ãŒã ãéããŠãããã¥ã¡ã³ãã§æ°åéäœæ¥ããçµæãä¿åãããšããŸãã ããã¯ãããžãã¹ãã©ã³ã¶ã¯ã·ã§ã³ã®å žåçãªäŸã§ãã
楜芳çãªç«¶äºç®¡çã®ç¶æ³ãèæ ®ããŠãã ããã ç·šéçµæã®ä¿åäžã«ç«¶åãæ€åºãããå ŽåããŠãŒã¶ãŒã«ã¯å€æŽãããããŒã¿ãšè¿œå ã®ã¢ã¯ã·ã§ã³ãéžæãããã€ã¢ãã°ãéç¥ãããŸãã Optimistic Offline Lockãã¿ãŒã³ã¯ãäžè¬çãªå ŽåãããŒãžã§ã³ç®¡çãããããŒã¿ã¡ã«ããºã ã«äŸåããå€æŽå¶åŸ¡ã¡ã«ããºã ãèšè¿°ããŸãã å€æŽãä¿åããããã³ã«ãããŒã¿ããŒã¹å ã®ããŒã¿ã®ããŒãžã§ã³ããå€æŽãè¡ãããããŒãžã§ã³ãšæ¯èŒãããŸãã ãããã®ããŒãžã§ã³ãçããå ŽåãçŸåšã®ããŒãžã§ã³ãå€æŽãããçµæãä¿åãããŸããããã§ãªãå Žåã競åãçºçããã¢ã¯ã·ã§ã³ãç¹°ãè¿ãããã£ã³ã»ã«ããããšã§åŠçãããŸãã
public class DomainObject { private Integer id; private Integer version; private Object data; // } public class UnitOfWork { // , public void update(List<DomainObject> updatedObjects) throws SQLException { PreparedStatement ps = connection.prepareStatement( "update domain_objects set data = ?, version = version + 1 " + "where id = ? and version = ?" ); for (DomainObject domainObject: updatedObjects) { ps.setObject(1, domainObject.getData()); ps.setInt(2, domainObject.getId()); ps.setInt(3, domainObject.getVersion()); if (ps.executeUpdate() == 0) { throw new RuntimeException(" "); } } } }
äžèšã®ã³ãŒãã¯ãäžèšã®Optimistic Offline Lockãã¿ãŒã³ã䜿çšããupdateã¡ãœããã®å®è£ ã瀺ããŠããŸãã ãã®å®è£ ã§ã¯ãå€æŽããããªããžã§ã¯ãã®ãªã¹ãã¯ããŒãžã§ã³æ€èšŒãšãšãã«ä¿åãããŸãã ããŒãžã§ã³ãå€æŽãããå ŽåãããŒãã«ã®åäžã®ã¬ã³ãŒãã¯æŽæ°ãããããã®äŸã§ã¯äŸå€ãã¹ããŒãããŸãã ãã®äŸå€ã¯ã競åããå®è¡ã¹ã¬ããã«ãã£ãŠã¬ã³ãŒããæ¢ã«æŽæ°ãããŠãã競åã«å¯Ÿå¿ããŠããŸãã
æ²èŠ³çãªç«¶åå¶åŸ¡ã®å Žåãæ²èŠ³çãªãªãã©ã€ã³ããã¯ãã¿ãŒã³ã®å®è£ ã以äžã«ç€ºããŸãã
class DomainObject { private Integer id; private Boolean blocked; private Object data; // } public class UnitOfWork { // , public void update(List<DomainObject> updatedObjects) throws SQLException { PreparedStatement updateStatement = connection.prepareStatement( "update domain_objects set data = ?, blocked = false " + "where id = ? and blocked = true" ); for (DomainObject domainObject: updatedObjects) { updateStatement.setObject(1, domainObject.getData()); updateStatement.setInt(2, domainObject.getId()); updateStatement.executeUpdate(); } } public DomainObject get(Integer id) throws SQLException { PreparedStatement updateStatement = connection.prepareStatement( "update domain_objects set blocked = true " + "where id = ? and blocked = false" ); updateStatement.setInt(1, id); if (updateStatement.executeUpdate() == 1) { PreparedStatement selectStatement = connection.prepareStatement( "select * from domain_objects where id = ?" ); selectStatement.setInt(1, id); ResultSet result = selectStatement.executeQuery(); //result // DomainObject result return new DomainObject(); } else { throw new RuntimeException(" "); } } }
æ瀺ãããã³ãŒãã§ã¯ãããŒã¿ããŒã¹ããããŒã¿ãåä¿¡ãããšããããã¯ããããã£ãŒã«ãã«ããã¯ãèšå®ãããŸãã æ¢ã«èšå®ãããŠããå Žåã¯äŸå€ãã¹ããŒãããããã§ãªãå Žåã¯çµæãè¿ãããŸãã ããã«ããªããžã§ã¯ããæŽæ°ãããšãããã¯ããªã»ãããããŸãã ãã®å®è£ ã¯ããã¹ãŠã®ã¬ãã«ã®ãã©ã³ã¶ã¯ã·ã§ã³åé¢ã§æ©èœããŸãã ããã¯ã®ãã£ããã£åŸã«ããŒã¿ãä¿åãããå Žåã
æ瀺ãããå®è£ ã¯ã説æã説æããã ãã§ãããå®éã®ã¢ããªã±ãŒã·ã§ã³ã§ã®äœ¿çšãç®çãšããŠããŸããïŒ
ããžãã¹ã¬ãã«ã®ããã¯ã¢ãŠãããªã·ãŒ
ããããã³ã°ããªã·ãŒã¯ãããŒã¿ãžã®åæã¢ã¯ã»ã¹ã管çããã«ãŒã«ã§ãã ãã®æ®µèœã§ã¯ãDBMSããã³ãã©ãããã©ãŒã åæã¡ã«ããºã ãžã®ã¯ãšãªã®ã¬ãã«ã§ã¯ãªããããžãã¹ã¬ãã«ã§ããã¯ã®ããªã·ãŒãæ±ããŸãã ããã¯ããªã·ãŒã¯ããžãã¹ããžãã¯ã«é¢é£ããŠããå¿ èŠãããããšã«æ³šæããŠãã ããã ãããŠãããªãã¯ç«¶äºã®ããã«åŸã§è³ªåããããšã¯ã§ããŸãããããšãã°ãç¹å®ã®ããã¥ã¡ã³ããåç¬ã§ç·šéããå¿ èŠãããããšãã¹ã³ãŒãã瀺ãã·ã¹ãã ã§ã¯ãããžãã¹ããžãã¯ããã®èŠä»¶ã®ç¥èãæã£ãŠããå¿ èŠããããŸããããžãã¹ãšãªã¢ã®ãã®ãããªèŠä»¶ã®å®è£ ã®å Žåãåæã¡ã«ããºã ã®å©ããåããŠã®ã¿ãã¢ããªã±ãŒã·ã§ã³ã§ã®ããžãã¹ã¬ãã«ã®å®è£ ã¯ããã€ãã®éšåã«åå²ãããŸãããããã¯ããŸãè¯ããããŸããããŸãããã®ãããªã·ã¹ãã ã®ãµããŒãã¯è€éã§ãããããçµã¿èŸŒã¿ã®DBMSããã·ãŒãžã£ã䜿çšããŠããã©ãŒãã³ã¹ãæé©åãããªãã·ã§ã³ã¯éåžžã«äžè¬çã§ããã第äºã«ãé·ãã·ã¹ãã ãã©ã³ã¶ã¯ã·ã§ã³ã«ã¯åé¡ããããŸããã€ãŸããã¢ããªã±ãŒã·ã§ã³ãããžãã¹ãã©ã³ã¶ã¯ã·ã§ã³ãšåæã«ã·ã¹ãã ãã©ã³ã¶ã¯ã·ã§ã³ãéãããŸãŸã«ã§ããªãããã«ããããšãã§ããŸãããããžãã¹ãã©ã³ã¶ã¯ã·ã§ã³ã®è²¬ä»»ç¯å²ã¯ãã¢ããªã±ãŒã·ã§ã³ã®ããžãã¹ããžãã¯ã«ãããŸãããããã£ãŠãããžãã¹ãã©ã³ã¶ã¯ã·ã§ã³ã®ããã¯ããªã·ãŒã¯ãããžãã¹ããžãã¯ãšã¯å¥ã«èæ ®ããããšã¯ã§ããŸããã
(en)
Patterns of Enterprise Application Architecture (Martin Fowler, David Rice, Matthew Foemmel, Edward Hieatt, Robert Mee, Randy Stafford)
PostgreSQL Concurrency Control
Concurrency control
Isolation level