什么是事務(wù)隔離級(jí)別涛漂?
事務(wù)隔離級(jí)別是對(duì)事務(wù) 4 大特性中隔離性的具體體現(xiàn)奄抽,使用事務(wù)隔離級(jí)別可以控制并發(fā)事務(wù)在同時(shí)執(zhí)行時(shí)的某種行為。
比如叫搁,有兩個(gè)事務(wù)同時(shí)操作同一張表赔桌,此時(shí)有一個(gè)事務(wù)修改了這張表的數(shù)據(jù),但尚未提交事務(wù)渴逻,那么在另一個(gè)事務(wù)中疾党,要不要(或者說能不能)看到其他事務(wù)尚未提交的數(shù)據(jù)呢?
這個(gè)問題的答案就要看事務(wù)的隔離級(jí)別了惨奕,不同的事務(wù)隔離級(jí)別雪位,對(duì)應(yīng)的行為模式也是不一樣的(有些隔離級(jí)別可以看到其他事務(wù)尚未提交的數(shù)據(jù),有些事務(wù)隔離級(jí)別看不到其他事務(wù)尚未提交的數(shù)據(jù))梨撞,這就是事務(wù)隔離級(jí)別的作用雹洗。
Spring 事務(wù)隔離級(jí)別
Sping 中的事務(wù)隔離級(jí)別有 5 種香罐,它們分別是:
- DEFAULT:Spring 中默認(rèn)的事務(wù)隔離級(jí)別,以連接的數(shù)據(jù)庫的事務(wù)隔離級(jí)別為準(zhǔn)队伟;
- READ_UNCOMMITTED:讀未提交穴吹,也叫未提交讀幽勒,該隔離級(jí)別的事務(wù)可以看到其他事務(wù)中未提交的數(shù)據(jù)嗜侮。該隔離級(jí)別因?yàn)榭梢宰x取到其他事務(wù)中未提交的數(shù)據(jù),而未提交的數(shù)據(jù)可能會(huì)發(fā)生回滾啥容,因此我們把該級(jí)別讀取到的數(shù)據(jù)稱之為臟數(shù)據(jù)锈颗,把這個(gè)問題稱之為臟讀;
- READ_COMMITTED:讀已提交咪惠,也叫提交讀,該隔離級(jí)別的事務(wù)能讀取到已經(jīng)提交事務(wù)的數(shù)據(jù),因此它不會(huì)有臟讀問題纲爸。但由于在事務(wù)的執(zhí)行中可以讀取到其他事務(wù)提交的結(jié)果褥琐,所以在不同時(shí)間的相同 SQL 查詢中,可能會(huì)得到不同的結(jié)果炭臭,這種現(xiàn)象叫做不可重復(fù)讀永脓;
- REPEATABLE_READ:可重復(fù)讀,它能確保同一事務(wù)多次查詢的結(jié)果一致鞋仍。但也會(huì)有新的問題常摧,比如此級(jí)別的事務(wù)正在執(zhí)行時(shí),另一個(gè)事務(wù)成功的插入了某條數(shù)據(jù)威创,但因?yàn)樗看尾樵兊慕Y(jié)果都是一樣的落午,所以會(huì)導(dǎo)致查詢不到這條數(shù)據(jù),自己重復(fù)插入時(shí)又失敹遣颉(因?yàn)槲ㄒ患s束的原因)溃斋。明明在事務(wù)中查詢不到這條信息,但自己就是插入不進(jìn)去吸申,這就叫幻讀 (Phantom Read)梗劫;
- SERIALIZABLE:串行化,最高的事務(wù)隔離級(jí)別呛谜,它會(huì)強(qiáng)制事務(wù)排序在跳,使之不會(huì)發(fā)生沖突,從而解決了臟讀隐岛、不可重復(fù)讀和幻讀問題猫妙,但因?yàn)閳?zhí)行效率低,所以真正使用的場景并不多聚凹。
所以割坠,相比于 MySQL 的事務(wù)隔離級(jí)別齐帚,Spring 中多了一種 DEFAULT 的事務(wù)隔離級(jí)別。
事務(wù)隔離級(jí)別與問題的對(duì)應(yīng)關(guān)系如下:
事務(wù)隔離級(jí)別 | 臟讀 | 不可重復(fù)讀 | 幻讀 |
---|---|---|---|
讀未提交(READ UNCOMMITTED) | ? | ? | ? |
讀已提交(READ COMMITTED) | ? | ? | ? |
可重復(fù)讀(REPEATABLE READ) | ? | ? | ? |
串行化(SERIALIZABLE) | ? | ? | ? |
- 臟讀:一個(gè)事務(wù)讀取到了另一個(gè)事務(wù)修改的數(shù)據(jù)之后彼哼,后一個(gè)事務(wù)又進(jìn)行了回滾操作对妄,從而導(dǎo)致第一個(gè)事務(wù)讀取的數(shù)據(jù)是錯(cuò)誤的。
- 不可重復(fù)讀:一個(gè)事務(wù)兩次查詢得到的結(jié)果不同敢朱,因?yàn)樵趦纱尾樵冎虚g剪菱,有另一個(gè)事務(wù)把數(shù)據(jù)修改了。
- 幻讀:一個(gè)事務(wù)兩次查詢中得到的結(jié)果集不同拴签,因?yàn)樵趦纱尾樵冎辛硪粋€(gè)事務(wù)有新增了一部分?jǐn)?shù)據(jù)孝常。
設(shè)置事務(wù)隔離級(jí)別
在代碼中設(shè)置事務(wù)隔離級(jí)別有兩種方式,第一種引入 TransactionTemplate
@Autowired
TransactionTemplate transactionTemplate;
transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
第二種直接在注解上標(biāo)明級(jí)別
@Transactional(isolation = Isolation.DEFAULT)
總結(jié)
Spring 中的事務(wù)隔離級(jí)別比 MySQL 中的事務(wù)隔離級(jí)別多了一種蚓哩,它包含的 5 種隔離級(jí)別分別是:
- Isolation.DEFAULT:默認(rèn)的事務(wù)隔離級(jí)別构灸,以連接的數(shù)據(jù)庫的事務(wù)隔離級(jí)別為準(zhǔn)。
- Isolation.READ_UNCOMMITTED:讀未提交岸梨,可以讀取到未提交的事務(wù)喜颁,存在臟讀。
- Isolation.READ_COMMITTED:讀已提交曹阔,只能讀取到已經(jīng)提交的事務(wù)半开,解決了臟讀,存在不可重復(fù)讀次兆。
- Isolation.REPEATABLE_READ:可重復(fù)讀稿茉,解決了不可重復(fù)讀,但存在幻讀(MySQL 數(shù)據(jù)庫默認(rèn)的事務(wù)隔離級(jí)別)芥炭。
- Isolation.SERIALIZABLE:串行化漓库,可以解決所有并發(fā)問題,但性能太低园蝠。
但需要注意是 Spring 是事務(wù)隔離級(jí)別是建立在連接的數(shù)據(jù)庫支持事務(wù)的基礎(chǔ)上的渺蒿,如果 Spring 項(xiàng)目連接的數(shù)據(jù)庫不支持事務(wù)(或事務(wù)隔離級(jí)別),那么即使在 Spring 中設(shè)置了事務(wù)隔離級(jí)別彪薛,也是無效的設(shè)置茂装。