高并發(fā)是開發(fā)者面臨的一項(xiàng)挑戰(zhàn)。使用Read Uncommitted隔離層級(jí)和重試機(jī)制,可以大幅提高系統(tǒng)的性能。
在高并發(fā)系統(tǒng)中,鎖異常始終是一個(gè)問(wèn)題。多名用戶或進(jìn)程同時(shí)訪問(wèn)常常導(dǎo)致資源的爭(zhēng)用,導(dǎo)致鎖沖突,并導(dǎo)致異常和性能瓶頸。該問(wèn)題不僅會(huì)打斷開發(fā)流程,還會(huì)妨礙用戶體驗(yàn)。解決這個(gè)問(wèn)題對(duì)于確保流暢的、無(wú)中斷的服務(wù)至關(guān)重要,同時(shí)優(yōu)化資源利用率,面對(duì)不斷增加的高并發(fā)應(yīng)用的需求。
鎖異常是處理大量寫操作和事務(wù)時(shí)最常見(jiàn)的異常。接下來(lái),我們使用樂(lè)觀鎖來(lái)解決這個(gè)問(wèn)題。
Spring Boot中的樂(lè)觀鎖是一種確保多用戶環(huán)境中數(shù)據(jù)完整性的并發(fā)控制機(jī)制。它支持多個(gè)客戶端同時(shí)讀取和更新數(shù)據(jù),同時(shí)最小化沖突。這是通過(guò)將版本號(hào)或時(shí)間戳與數(shù)據(jù)庫(kù)中的每條記錄相關(guān)聯(lián)來(lái)實(shí)現(xiàn)的。當(dāng)客戶端更新記錄時(shí),將檢查版本號(hào)以檢測(cè)自數(shù)據(jù)最初讀取以來(lái),其他客戶端是否對(duì)其進(jìn)行了更改。如果檢測(cè)到?jīng)_突,系統(tǒng)可以通過(guò)回滾事務(wù)并拋出異常來(lái)處理它,這個(gè)異常可以用于重試嘗試。樂(lè)觀鎖是Spring Boot的JPA(Java 持久化 API)的關(guān)鍵功能,用于以安全和高效的方式管理數(shù)據(jù)庫(kù)記錄。
首先,我們需要在實(shí)體中添加由spring boot管理的列,如下面的代碼所示。
@Entity@Datapublic class YourEntity { @Id @GeneratedValue private Long id; // 其他字段 @Version private Long version; // 樂(lè)觀鎖版本列}
在上面的代碼注釋中,當(dāng)對(duì)特定行進(jìn)行更新時(shí),@Version會(huì)自動(dòng)更改版本號(hào)。所以,處理此行的其他事務(wù)會(huì)發(fā)現(xiàn)版本號(hào)已經(jīng)更改,并將引發(fā)異常。我們可以捕獲此異常來(lái)重試事務(wù),如下代碼所示。
@Servicepublic class MyService { @Autowired private YourEntityRepository yourEntityRepository; // 假設(shè)有實(shí)體倉(cāng)庫(kù) @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Retryable( value = {OptimisticLockingException.class}, maxAttempts = 3, backoff = @Backoff(delay = 200)) public YourEntity yourBusinesslogicTransactionMethod(Long entityId) { YourEntity entity = yourEntityRepository.findById(entityId).orElse(null); if (entity == null) { throw new EntityNotFoundException("Entity with ID " + entityId + " not found."); } // 更新數(shù)據(jù) entity.setName("UpdatedName"); // 存儲(chǔ)到數(shù)據(jù)庫(kù) try { yourEntityRepository.save(entity); // not using native query, only using default JPA methods } catch (OptimisticLockingException ex) { // 如果出現(xiàn)樂(lè)觀鎖異常,則表示發(fā)生了并發(fā)更新。 // @Retryable注釋將觸發(fā)指定次數(shù)的重試。 throw ex; } catch (Exception ex) { // 處理其他異常 } return entity; }}
在上面代碼中,我們捕獲異常,如果發(fā)現(xiàn)鎖異常,則重試事務(wù)。隔離層級(jí)通常與事務(wù)性注釋一起使用。
Spring Boot中的隔離層級(jí)通過(guò)定義并發(fā)事務(wù)所做更改的可見(jiàn)性來(lái)控制數(shù)據(jù)庫(kù)系統(tǒng)中的事務(wù)如何相互交互。隔離層級(jí)包括如下類型:
READ_UNCOMITTED:支持讀取其他事務(wù)未提交的更改,提供最小的隔離。
READ_COMMITTED:支持只讀取已提交的更改,防止臟讀取。
REPEATABLE_READ:確保在當(dāng)前事務(wù)完成之前,其他事務(wù)的更改不可見(jiàn),從而消除不可重復(fù)的讀取。
SERIALIZABLE:提供與其他事務(wù)的完全隔離,防止對(duì)數(shù)據(jù)的任何并發(fā)訪問(wèn)。
READ_UNCOMITTED隔離層級(jí)提供了最高的并發(fā)性。因此,在上面的代碼中,我們首先讀取一行,然后嘗試更新該行,在更新過(guò)程中,如果值發(fā)生了更改,JPA將檢查版本列,這意味著在我們讀取后,其他寫入操作也更改了值。JPA在版本號(hào)更改時(shí)拋出鎖異常。我們捕獲此異常并重試事務(wù)。下次事務(wù)將讀取更新后的值。
在Retry注釋的幫助下,我們可以輕松配置重試策略,如重試嘗試、重試嘗試和嘗試重試的異常之間的持續(xù)時(shí)間。
版本注釋與JPA默認(rèn)查詢完美配合。因此,在讀取和更新期間,請(qǐng)嘗試使用默認(rèn)的JPA查詢,不要使用本機(jī)查詢。如果使用本機(jī)查詢,則需要自己更新版本列數(shù)據(jù)。
當(dāng)請(qǐng)求數(shù)量非常高,而每行的并發(fā)請(qǐng)求較少時(shí),這種方法非常好。在例子中,我們沒(méi)有每行的高并發(fā)性。對(duì)于一行,并發(fā)請(qǐng)求的可能性幾乎為零,但我們?nèi)匀坏玫搅随i異常,因?yàn)槲覀儧](méi)有指定任何隔離級(jí)別,默認(rèn)隔離級(jí)別是READ_COMMITTED。
樂(lè)觀鎖在不確定數(shù)據(jù)庫(kù)鎖行為的情況下很有價(jià)值。不用依賴數(shù)據(jù)庫(kù)的鎖定機(jī)制,而是在應(yīng)用程序代碼中處理數(shù)據(jù)并發(fā)沖突。
在樂(lè)觀鎖中,只有正在更新的行被鎖定,而不是整個(gè)表。當(dāng)事務(wù)更新一行時(shí),通常會(huì)增加與該行相關(guān)的版本號(hào)或時(shí)間戳,并且在更新過(guò)程中,會(huì)檢查版本或時(shí)間戳。如果另一個(gè)事務(wù)同時(shí)修改了同一行,則會(huì)檢測(cè)到并發(fā)沖突,您可以根據(jù)需要進(jìn)行處理。
樂(lè)觀鎖不會(huì)自動(dòng)鎖定相鄰行或多行。它的設(shè)計(jì)目的是通過(guò)只鎖定特定更新操作中涉及的行來(lái)最大限度地減少對(duì)并發(fā)訪問(wèn)的影響。其他事務(wù)可以繼續(xù)讀取或修改同一表中不相關(guān)的行,而不會(huì)被阻止。
根據(jù)事務(wù)和數(shù)據(jù)庫(kù)系統(tǒng)的隔離級(jí)別,帶有WHERE子句的讀取查詢可能會(huì)鎖定行。但是,確切的鎖定行為會(huì)根據(jù)所使用的隔離級(jí)別而有所不同。在樂(lè)觀的鎖定場(chǎng)景中,重要的是要仔細(xì)考慮隔離級(jí)別,以最大限度地降低阻塞其他事務(wù)的風(fēng)險(xiǎn)。
優(yōu)化高并發(fā)任務(wù)時(shí),策略方法是必不可少的。在Spring Boot應(yīng)用程序中,可利用隔離層級(jí)并采用高效的重試機(jī)制以及樂(lè)觀鎖,在性能和數(shù)據(jù)完整性之間取得平衡。
本文鏈接:http://www.www897cc.com/showinfo-26-57896-0.html事半功倍,提高IntelliJ IDEA代碼質(zhì)量的神級(jí)插件
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com