顧保磊,吳 云
(武漢工程科技學(xué)院,武漢 430200)
基于排隊(duì)的數(shù)據(jù)庫表數(shù)據(jù)插入方法的設(shè)計(jì)與實(shí)現(xiàn)
顧保磊,吳 云
(武漢工程科技學(xué)院,武漢 430200)
目前網(wǎng)絡(luò)版的軟件越來越多,這些軟件都需要使用數(shù)據(jù)庫,都存在多個(gè)用戶同時(shí)訪問數(shù)據(jù)庫表,特別是對(duì)數(shù)據(jù)庫表進(jìn)行插入操作時(shí),由于操作的并行性,容易獲得相同的編號(hào)。主要針對(duì)獲取相同編號(hào)的問題,提出了一種數(shù)據(jù)庫操作并行度較高的方法,即采用公共動(dòng)態(tài)數(shù)組存儲(chǔ)插入信息,排隊(duì)獲取編號(hào),從而避免了同一編號(hào)的多次獲取。
數(shù)據(jù)庫表; 數(shù)據(jù)插入方法; 動(dòng)態(tài)數(shù)組;排隊(duì)
隨著計(jì)算機(jī)硬件及網(wǎng)絡(luò)的飛速發(fā)展,單機(jī)版的軟件需求越來越少;但網(wǎng)絡(luò)版的軟件需求卻越來越多。無論是B/S、C/S模式的網(wǎng)站,還是Android手機(jī)的應(yīng)用APP,都要使用數(shù)據(jù)庫,且存在多個(gè)用戶同時(shí)訪問數(shù)據(jù)庫,甚至對(duì)數(shù)據(jù)庫幾乎同時(shí)進(jìn)行增、刪、改、查等操作[1]。
幾乎每個(gè)數(shù)據(jù)表中都有編號(hào)(id)字段,且該字段是整型類型、記錄內(nèi)容具有不相同的特征:
(1)通過SQL語句“select max(id) from tablename”獲取當(dāng)前數(shù)據(jù)表的id字段最大的值[2],再令其加1,這種做法的算法復(fù)雜度較低,但在頻繁刪除、插入記錄的表中,容易出現(xiàn)由于大量未使用的編號(hào)而使插入記錄的編號(hào)急劇上升的問題。
(2)通過各種算法檢測有、無由于刪除記錄而產(chǎn)生未使用的編號(hào)。若有,確定其中一個(gè)未使用的編號(hào),若無,則獲取最大編號(hào)并加1,這種做法雖然解決了表中編號(hào)急劇上升的問題,但算法復(fù)雜度明顯增加,系統(tǒng)開銷也增加。
上述兩種做法都先進(jìn)行一次或多次查詢和數(shù)據(jù)處理,再將結(jié)果和相關(guān)數(shù)據(jù)插入表中。在多個(gè)用戶同時(shí)進(jìn)行增、刪、改、查、操作時(shí),將出現(xiàn)異常錯(cuò)誤。
出現(xiàn)上述異常主要是由于多個(gè)用戶同時(shí)對(duì)數(shù)據(jù)庫進(jìn)行插入和特殊的查詢造成的,屬數(shù)據(jù)庫并發(fā)操作問題[3],即出現(xiàn)A用戶對(duì)數(shù)據(jù)表T執(zhí)行查詢語句,獲得編號(hào)后,執(zhí)行相應(yīng)的插入語句之前,B用戶也對(duì)數(shù)據(jù)表T執(zhí)行查詢語句獲得了相同的編號(hào);此時(shí),如果數(shù)據(jù)表T的編號(hào)字段有唯一性檢查,B用戶進(jìn)行插入操作時(shí),將出現(xiàn)異常錯(cuò)誤。
針對(duì)該問題,很多數(shù)據(jù)庫軟件本身提供一種解決方案,即鎖。一般需要在事務(wù)中對(duì)數(shù)據(jù)表加“X鎖”,待使用查詢語句并處理獲得數(shù)據(jù)表id的值插入數(shù)據(jù)以后,再解鎖[4]。鎖屬于數(shù)據(jù)庫的高級(jí)應(yīng)用,這種做法需要的步驟比較多,也較麻煩,且并發(fā)性不好[5]。
有沒有簡單且比較容易實(shí)現(xiàn)的做法呢?排隊(duì)是一個(gè)常見的解決方法。
排隊(duì),即如果有用戶正在對(duì)數(shù)據(jù)庫表進(jìn)行插入操作,包括為插入語句服務(wù)的查詢操作時(shí),任何其他對(duì)數(shù)據(jù)庫表進(jìn)行插入操作及相關(guān)操作全部暫停,并按請求的先后順序排隊(duì)等候;如果當(dāng)前的插入操作結(jié)束,則按排隊(duì)的先后,喚醒等候的插入操作。算法的流程圖如圖1所示。對(duì)數(shù)據(jù)庫的所有數(shù)據(jù)表進(jìn)行插入排隊(duì),雖然算法簡單且解決了上述問題,但卻降低了數(shù)據(jù)庫操作的并行性,使數(shù)據(jù)庫操作效率嚴(yán)重降低。
圖1 對(duì)數(shù)據(jù)庫所有的表進(jìn)行插入操作排隊(duì)流程圖
為提高并行操作的效率,經(jīng)研究發(fā)現(xiàn),如果不同的用戶同時(shí)對(duì)不同的數(shù)據(jù)庫表進(jìn)行插入操作,不會(huì)產(chǎn)生重復(fù)編號(hào)的問題,即無需排隊(duì)。只有不同用戶對(duì)同一數(shù)據(jù)庫表同時(shí)進(jìn)行插入操作時(shí)才需要排隊(duì),雖在一定程度上增加了算法的復(fù)雜度[6],但在數(shù)據(jù)庫操作的并行性方面有明顯的提高。算法的流程圖如圖2所示。
圖2 對(duì)同一數(shù)據(jù)庫表同時(shí)進(jìn)行插入操作排隊(duì)流程圖
經(jīng)進(jìn)一步研究發(fā)現(xiàn),插入記錄的操作分為編號(hào)的查詢獲取和數(shù)據(jù)插入兩個(gè)階段。不同用戶對(duì)同一個(gè)數(shù)據(jù)表的同時(shí)插入操作產(chǎn)生問題主要是因?yàn)榫幪?hào)。不能獲取同一編號(hào),即只需通過一定的算法確保不同的用戶插入操作獲取不同的編號(hào),且在數(shù)據(jù)插入后,整個(gè)數(shù)據(jù)庫表中的編號(hào)具有唯一性。算法的流程圖如圖3所示。
圖3 對(duì)同一數(shù)據(jù)庫表同時(shí)進(jìn)行獲取編號(hào)的操作排隊(duì)流程圖
該算法進(jìn)一步提高了數(shù)據(jù)庫插入操作的并行性,且算法的復(fù)雜程度沒有明顯的增加。
為了能以最快的速度獲得唯一的編號(hào),這里對(duì)同一數(shù)據(jù)庫表的插入請求采用排隊(duì)獲取編號(hào)的方法,具體算法流程如圖4所示。
圖4 對(duì)同一數(shù)據(jù)庫表同時(shí)進(jìn)行獲取編號(hào)的操作排隊(duì)流程圖
上述算法中,創(chuàng)建了一個(gè)公共的動(dòng)態(tài)數(shù)組,在用戶請求對(duì)數(shù)據(jù)庫表進(jìn)行插入數(shù)據(jù)時(shí),增加一個(gè)元素(自定義insertstate類對(duì)象),包括排隊(duì)的編號(hào),發(fā)出插入請求的用戶名,需要插入數(shù)據(jù)的數(shù)據(jù)庫表名稱、插入的SQL語句,獲取的插入編號(hào),操作狀態(tài)等;插入操作完成后,刪除動(dòng)態(tài)數(shù)組中相應(yīng)記錄。
3.1 動(dòng)態(tài)數(shù)組ArrayList類
ArrayList類是C#.NET處理的動(dòng)態(tài)數(shù)組,可封裝集合類[7];這是一個(gè)由包含單一數(shù)據(jù)值的數(shù)據(jù)項(xiàng)組成的集合, 具有動(dòng)態(tài)增加和減少元素的優(yōu)點(diǎn)。ArrayList中數(shù)據(jù)項(xiàng)是通過Add()方法添加的,通過RemoveAt()方法刪除。定義創(chuàng)建一個(gè)公共的動(dòng)態(tài)數(shù)組insertarray的代碼如下:
public static ArrayListinsertarray
= new ArrayList();
下面是insertstate類的定義,其對(duì)象是insertarray的元素:
public class insertstate
{ publicinsertstate(){}
publicinsertstate(int id, String username,
Stringtabelname,String strsql,inttableid,intopstate)
{ this.id = id;this.username= username;this.tabelname = tabelname;
this.strsql = strsql;this.tableid = tableid; this. opstate= opstate;
}
private intid; //排隊(duì)的編號(hào)
private String username; //發(fā)出插入請求的用戶名
private String tabelname; //需要插入數(shù)據(jù)的表名稱
private String strsql; //插入的SQL語句
private inttableid; //獲取的編號(hào)
private intopstate; //操作狀態(tài)
}
當(dāng)G用戶對(duì)表T1發(fā)出插入數(shù)據(jù)請求時(shí),動(dòng)態(tài)數(shù)組內(nèi)容如表1,可采用:
int x1=getnum(”T1”);//獲取排隊(duì)的狀態(tài),-2表示已獲取,-1表示正在執(zhí)行獲取操作,大于等于1的值表示排隊(duì)的序號(hào)。
insertstatetemp = new insertstate
(7,“G”,”T1”,”……”,-2,x1);
insertarray.Add(temp);
語句將獲取編號(hào)的請求送入動(dòng)態(tài)數(shù)組進(jìn)行排隊(duì),并用while等語句不斷對(duì)狀態(tài)檢測,直至執(zhí)行完獲取編號(hào)的操作,排隊(duì)結(jié)束。
表1 動(dòng)態(tài)數(shù)組內(nèi)容
編號(hào)用戶名表名插入語句獲取的編號(hào)狀態(tài)1AT1……31-22BT2……41-23CT1……-2-14DT1……-215ET2……-2-16FT2……-21
while(x1> 0) { Thread.Sleep(50);
//暫停50毫秒
x1 = checkstate(temp);//獲取狀態(tài)
}
設(shè)對(duì)表T1執(zhí)行獲取編號(hào)操作結(jié)束,在將獲取的編號(hào)值寫入動(dòng)態(tài)數(shù)組的同時(shí),必須也將排隊(duì)中的同一表的狀態(tài)都減1,此時(shí)用戶D的執(zhí)行狀態(tài)為0,表示處于執(zhí)行的就緒狀態(tài)。
if(x1==0) {plusstate(temp);//將處于就緒狀態(tài)的狀態(tài)減1,表示進(jìn)入執(zhí)行狀態(tài)
//執(zhí)行獲取編號(hào)操作
}
獲取編號(hào)后,排隊(duì)即結(jié)束,可以并行執(zhí)行插入語句。插入操作完成后,采用
insertarray.RemoveAt(count);//將第count個(gè)元素移除
語句將相應(yīng)元素刪除。
3.2 獲取插入編號(hào)
針對(duì)某數(shù)據(jù)表進(jìn)行獲取編號(hào)(id字段)操作,首先用SQL語句“select max(id) from tablename”和“select count (*) from tablename”[8]獲取當(dāng)前數(shù)據(jù)庫表的最大編號(hào)和記錄個(gè)數(shù),如果記錄數(shù)小于最大編號(hào),如表2所示,即存在未使用的編號(hào)2,5;如果記錄數(shù)等于最大編號(hào),如表3所示,即不存在未使用的編號(hào)。
表2 數(shù)據(jù)庫表T1
表3 數(shù)據(jù)庫表T2
(1)如表2所示,存在沒有使用過的id編號(hào)2和5,首先確定并返回編號(hào)2,到公共的動(dòng)態(tài)數(shù)組insertarray(如表4所示)中檢測,發(fā)現(xiàn)存在表T1且編號(hào)為2的元素,則以編號(hào)2為開始,重新查找新的未使用的編號(hào),確定并返回編號(hào)5,到公共的動(dòng)態(tài)數(shù)組insertarray中再檢測,動(dòng)態(tài)數(shù)組insertarray中不存在表T1且編號(hào)為2的元素,則將該數(shù)值寫入相應(yīng)的元素中,如表5所示。
(2)如表3所示不存在沒有使用過的編號(hào),返回表中id字段的最大值4,將最大值4加1得到編號(hào)5,再到公共的動(dòng)態(tài)數(shù)組insertarray(如表4所示)中檢測,發(fā)現(xiàn)存在表T2且編號(hào)為5的元素,則以5再加1得到編號(hào)6,再次到公共的動(dòng)態(tài)數(shù)組insertarray中檢測,動(dòng)態(tài)數(shù)組insertarray中不存在表T2且編號(hào)為6的元素,則將該數(shù)值寫入相應(yīng)的元素中,如表5所示。
表4 公共的動(dòng)態(tài)數(shù)組insertarray
編號(hào)用戶名表名插入語句獲取的編號(hào)狀態(tài)1AT1……2-22CT2……5-23ET1……-2-14FT2……-2-1
表5 公共的動(dòng)態(tài)數(shù)組insertarray
編號(hào)用戶名表名插入語句獲取的編號(hào)狀態(tài)1AT1……2-22CT2……5-23ET1……5-14FT2……6-1
本文主要以具有惟一性的編號(hào)(id)字段為例來討論數(shù)據(jù)庫表查詢和插入并行操作的過程,對(duì)于可能多次獲取同一個(gè)編號(hào)而產(chǎn)生錯(cuò)誤的原因,以及解決該問題的思路及其具體的實(shí)現(xiàn)方法。這種解決問題的思路也適用于實(shí)時(shí)性較高的字段,如注冊賬戶的名稱等,是一個(gè)較常見的問題,具有一定的通用性。
[1] 于亮.異地并行數(shù)據(jù)庫設(shè)計(jì)應(yīng)用——餐飲管理系統(tǒng)[J].神州,2012(18):180.
[2] mysql插入記錄后獲取插入數(shù)據(jù)的id值[EB/OL].[ 2014-05-08].http://www.ddvip.com/tech/100020696.html.
[3] 趙永霞,高翠芬,熊燕,等.數(shù)據(jù)庫原理與應(yīng)用技術(shù)[M].武漢:華中科技大學(xué)出版社,2013.
[4] 張小志,吳慶雙.SQL Server2008 數(shù)據(jù)庫應(yīng)用教程[M].北京:人民郵電出版社,2016.
[5] 袁曉潔,孫國榮.數(shù)據(jù)庫原理和實(shí)踐教程GBase 8t Based on Information剖析與應(yīng)用[M].北京:電子工業(yè)出版社,2016.
[6] 嚴(yán)蔚敏,陳文博.數(shù)據(jù)結(jié)構(gòu)及應(yīng)用算法教程(修訂版)[M].北京:清華大學(xué)出版社,2011.
[7] 胡秋霞,田杰.淺談asp.net中ArrayList類的使用[J].電腦知識(shí)與技術(shù)(學(xué)術(shù)交流),2007(20):422-447.
[8] Ryan Stephens,Ron Plew,Arie D.Jones著. SQL入門經(jīng)典(第5版)[M].井中月,郝記生譯.北京:人民郵電出版社,2015.
Research on queuing based data insertion method of the database Table
GU Bao-lei,WU Yun
(Wuhan University of Engineering Science,Wuhan 430200,China)
At present, more and more software are network version, and all of these require the database. There are many users to access the database table at the same time especially when the database table inserting operation. So it is very access to the same number because of operational parallelism. This paper mainly aims at the problem of getting the same number, and proposes a higher degree of parallelism database operational way which can avoid multiple accessing to the same number by using public dynamic array to store insert data on the same database table.
database; the insertion method of database table; dynamic array; queue
2016-06-30.
2016-11-04.
顧保磊(1952-),男,教授,E-mail:dz_gubaolei@126.com.
2095-7386(2016)04-0078-04
10.3969/j.issn.2095-7386.2016.04.015
TP311
A