小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

基于Oracle數(shù)據(jù)庫鎖機(jī)制,解決集群中的并發(fā)訪問問題

 KILLKISS 2015-09-14

1、需求

應(yīng)用場景是這樣的:

使用Oracle數(shù)據(jù)保存待辦任務(wù),使用狀態(tài)字段區(qū)分任務(wù)是否已經(jīng)被執(zhí)行。多個Worker線程同時執(zhí)行任務(wù),執(zhí)行成功或失敗后,修改狀態(tài)字段的值。

假設(shè)數(shù)據(jù)庫表結(jié)構(gòu)如下所示。

create table Task(     id      varchar2(32),     name    varchar2(32),     flag    varchar2(1),     worker  varchar2(32) );

flag 可取的值包括:0-待辦,1-已辦,-1-失敗待重試。

需要避免的問題:
多個Worker同時工作時,避免出現(xiàn)一個任務(wù)被執(zhí)行多次的情況;避免任務(wù)的狀態(tài)被改錯。

2、分析

2.1、依賴Java語言的機(jī)制

Java語言的鎖機(jī)制可以解決并發(fā)問題,但只能在單機(jī)情況下有效。

在Tomcat(或其他應(yīng)用服務(wù)器)集群環(huán)境下,Java代碼中的鎖機(jī)制是解決不了這個問題的。
Java語言層面的各種同步、鎖機(jī)制是在JVM內(nèi)部的,處理不了跨JVM的情況。

作為鎖的信號量,必須存儲在獨立于JVM的地方??梢允菙?shù)據(jù)庫,可以是Redis。

2.2、Quartz提供的支持

在生產(chǎn)環(huán)境中,為了避免單點故障,Quartz需要集群提供 HA( High Availability,高可用)支持。Quartz集群依賴將任務(wù)信息持久化到數(shù)據(jù)庫中。

有兩個可選的思路:

1、可以設(shè)置單個節(jié)點的worker數(shù)量為1。首先保證了在單個節(jié)點內(nèi)不會有并發(fā)問題。是否能保證集群中同一個Job只有一個實例在跑,需要考察下 Quartz 提供的文檔。

2、在任務(wù)類上使用 @DisallowConcurrentExecution 或者 StatefullJob?;蛟S可以達(dá)到效果,需要實驗。

采用Quartz管理并發(fā)問題,采取的是回避策略,不能充分利用計算資源。

Quartz的集群環(huán)境依賴JDBC存儲,一方面需要通過數(shù)據(jù)庫在節(jié)點間共享信息,另一方面,基于數(shù)據(jù)庫的行集鎖解決了并發(fā)問題。

Quartz 本身已經(jīng)太龐大,不仔細(xì)閱讀文檔,甚至閱讀源代碼,也無從猜測其行為,作為企業(yè)級的 Timer ,它很好用。解決并發(fā)問題,還是找一個更清爽明了的方法吧。

2.3、通過數(shù)據(jù)庫鎖實現(xiàn)

在考慮解決問題的方案前,先回顧一下數(shù)據(jù)庫的事務(wù)隔離級別和Oracle數(shù)據(jù)庫的鎖機(jī)制。

2.3.1、事務(wù)隔離級別

事務(wù)隔離級別是針對當(dāng)前會話來說的。

SQL 92標(biāo)準(zhǔn)定義了4種事務(wù)隔離級別。

1、Read Uncommited : 可以讀到其他會話未提交到。
這是4個級別中最低的。其他會話直接在數(shù)據(jù)上修改,當(dāng)前會話會讀到其他會話實時的修改狀態(tài)。
當(dāng) 會話B 修改了數(shù)據(jù),被當(dāng)前會話讀到,會話B 又回滾了,則當(dāng)前會話讀到了“錯誤”的數(shù)據(jù)。 這稱為“臟讀”。

2、Read Commited :當(dāng)前會話可以讀到其他會話已經(jīng)提交到數(shù)據(jù)。
這種隔離級別避免了“臟讀”。
如果出現(xiàn)這種狀況:

1) 當(dāng)前會話讀取數(shù)據(jù); 2) 會話B 修改并提交了當(dāng)前會話數(shù)據(jù); 3) 當(dāng)前會話再次提交,讀到了會話B修改后的數(shù)據(jù)。 

對于當(dāng)前會話來說,兩次讀取數(shù)據(jù),讀到的不一樣,這稱為“不可重復(fù)讀”。

這是Oracle默認(rèn)的事務(wù)隔離級別。

3、Repeatable Read :當(dāng)前會話看不到其他會話已經(jīng)提交的數(shù)據(jù)修改,但可以看到其他會話新插入的數(shù)據(jù)。

不可重復(fù)讀會出現(xiàn)的問題是:相同的查詢條件,在同一個會話中反復(fù)執(zhí)行,查詢得到記錄條數(shù)會不相同。這稱為“幻讀”。

4、Serializable :其他會話對數(shù)據(jù)的修改都不可見。

需要注意的是,不是其他會話不能修改數(shù)據(jù),而是修改對當(dāng)前會話不可見。

Oracle支持3種事務(wù)隔離級別。

Oracle支持Read Commited、Repeatable Read ,另外,支持 Read Only。
Read Only 是最徹底的掩耳盜鈴。

事務(wù)隔離級別可以幫我們理解問題,但不是解決問題的方法。

解決問題,靠數(shù)據(jù)庫的鎖機(jī)制。

2.3.2、Oracle數(shù)據(jù)庫的鎖機(jī)制

我們需要的是DML鎖,DML鎖的目的在于保證并發(fā)情況下的數(shù)據(jù)完整性。在 Oracle 中,DML鎖包括表級鎖和行級鎖。

select … for update 可以獲得行級鎖。
update執(zhí)行也自動獲得行級鎖。

這樣,我們可以有兩個方法達(dá)到并發(fā)控制的目的:

方法一:

通過select … for update 獲得行級鎖,鎖定若干任務(wù),每條數(shù)據(jù)是一個任務(wù)。

然后執(zhí)行任務(wù),執(zhí)行任務(wù)完成后,更新狀態(tài),提交事務(wù),釋放鎖。

Quartz 本身是使用這種機(jī)制,解決集群中的并發(fā)問題的。

相關(guān)代碼文件包括:

接口定義: org.quartz.impl.jdbcjobstore.Semaphore。 模板方法: org.quartz.impl.jdbcjobstore.DBSemaphore。 實現(xiàn)類: org.quartz.impl.jdbcjobstore.StdRowLockSemaphore。 應(yīng)用: org.quartz.impl.jdbcjobstore.JobStoreSupport。 

關(guān)鍵方法包括:obainLock,releseLock和executeInLock。

方法二:

按如下步驟執(zhí)行:

1、執(zhí)行如下SQL語句,搶占任務(wù)。

update Task t set t.worker = 'worker-1'  where t.worker is null 

可以對如上SQL進(jìn)行改進(jìn),只搶占指定數(shù)量的任務(wù),多余的任務(wù)留給其他 worker 做。

2、逐個執(zhí)行已經(jīng)搶占的任務(wù)。

可以通過如下SQL查詢出已經(jīng)搶占成功的任務(wù)信息。

select * from Task t  where t.worker = 'worker-1' and t.flag < 1

3、執(zhí)行完成后,更改任務(wù)狀態(tài)。

update Task t set t.flag = 1 where id = 'some id'

如果任務(wù)執(zhí)行失敗,放回去。

update Task t set t.flag = -1 , t.worker = null where id = 'some id'

這種方法的要點在第一步。第一步是會出現(xiàn)并發(fā)問題的地方。

Oracle 的update語句會自動獲得行級鎖。我們可以做如下實驗驗證:

1)打開兩個PL/SQL 窗口,模擬兩個會話,每個窗口都將執(zhí)行update語句,更新相同的行。比如:第一個窗口執(zhí)行 update Task set flag=1 where flag=0 and id=‘1’,第二個窗口執(zhí)行 update Task set flag=2 where flag=0 and id=‘1’。 2)先執(zhí)行第一個窗口的update語句,不提交。 3)再執(zhí)行第二窗口的 update 語句,發(fā)現(xiàn)“在等待”。 4)提交或回滾第一個窗口的事務(wù)后,發(fā)現(xiàn)第二窗口停止等待,執(zhí)行了語句,等待提交。兩條語句是串行執(zhí)行的。 

Oracle 本身對 update 的鎖機(jī)制已經(jīng)足以支持我們的工作。

方法三:

增加 version 或 timestamp 字段,使用樂觀鎖。

有了方法二,這種方法偏麻煩。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多