一坊饶、問題背景:
C++程序中使用oracle occi來鏈接oracle數(shù)據(jù)庫并進(jìn)行相關(guān)操作。整個(gè)程序分成了許多個(gè)模塊殴蓬,其中有個(gè)抽象和封裝oracle數(shù)據(jù)庫的模塊匿级,并且使用了單例模式,其他模塊若想操作oracle數(shù)據(jù)庫科雳,則必須首先獲取oracle鏈接對象根蟹,然后通過對象調(diào)用相關(guān)的方法脓杉。整個(gè)程序設(shè)計(jì)思想是能夠同時(shí)接受大量任務(wù)提交糟秘,并將這些任務(wù)塞到一個(gè)任務(wù)隊(duì)列中。有一個(gè)單獨(dú)的線程負(fù)責(zé)來從隊(duì)列中取任務(wù)球散,然后寫入數(shù)據(jù)庫尿赚。所以從設(shè)計(jì)上來看,最終操作鏈接對象的只有一個(gè)線程,而且任意時(shí)刻鏈接對象只被一個(gè)線程所占用凌净,執(zhí)行一個(gè)SQL命令悲龟。但是當(dāng)同時(shí)有超多30個(gè)任務(wù)一起提交時(shí),程序就會出現(xiàn)數(shù)據(jù)庫相關(guān)的異常:
例如冰寻,ORA-01013:user requested cancel of current operation须教。
二、解決辦法
將創(chuàng)建oracle鏈接環(huán)境的模式由DEFAULT改為THREADED_MUTEXED,即線程安全模式斩芭。
三轻腺、問題緣由
經(jīng)過仔細(xì)查看代碼,發(fā)現(xiàn)是在其他地方又使用了連接對象來進(jìn)行ID相關(guān)的查詢操作划乖,而鏈接環(huán)境模式DEFAULT并不是線程安全的贬养,所以在多線程環(huán)境下,在兩個(gè)線程中同時(shí)使用了同一個(gè)鏈接對象來進(jìn)行數(shù)據(jù)庫相關(guān)操作琴庵,在沒有鎖機(jī)制同步的情況下误算,產(chǎn)生了競爭條件,最終破壞了鏈接對象內(nèi)部的狀態(tài)迷殿,產(chǎn)生了異常儿礼。
四、相關(guān)知識點(diǎn)
對于參數(shù)THREADED_MUTEXED庆寺,occi 文件介紹如下:
THREADED_MUTEXED is a thread safe mode for creating an Environment
object, mutexed internally by OCCI.
其實(shí)就是說蜘犁,如果你的程序是多個(gè)線程可能同時(shí)訪問數(shù)據(jù)庫的話,請使用多線程安全的環(huán)境止邮。
The Programmer must insure that only one OCI call is in process on the environment handle connection at any given time
任意時(shí)間片这橙,在同一個(gè)連接環(huán)境句柄下,只能有一個(gè)OCI命令運(yùn)行
線程安全性就是說OCI中的那些句柄导披,比如環(huán)境句柄屈扎、服務(wù)句柄等,能不能在多個(gè)線程中共享撩匕。遺憾的是鹰晨,結(jié)合OCI的文檔和論壇上他人的描述,我的出結(jié)論是不能共享止毕。多個(gè)線程同時(shí)訪問不會導(dǎo)致程序的崩潰模蜡,OCI內(nèi)部使用互斥體保證句柄的線程安全性,但是不能拿一個(gè)句柄同時(shí)做兩件事扁凛。按照OTN上一個(gè)人說忍疾,在共享句柄上同時(shí)做不同的事情會得到一個(gè)錯誤:ORA-03127: no new operations allowed until the active operation ends。