為什么阿里巴巴禁止使用存儲(chǔ)過(guò)程?
點(diǎn)擊上方“JAVA”,星標(biāo)公眾號(hào)

之所以有這個(gè)題目,我既不是故意吸引眼球,也不想在本文對(duì)存儲(chǔ)過(guò)程進(jìn)行教科書(shū)般論述?!栋⒗锇桶蚃ava開(kāi)發(fā)手冊(cè)》是這樣規(guī)定的:

這事兒要從去年在武漢出差時(shí)一位同事的發(fā)問(wèn)說(shuō)起,問(wèn)題是這樣的:
我覺(jué)得存儲(chǔ)過(guò)程挺好用的,你為什么不建議用呢
當(dāng)時(shí)我好似胸有萬(wàn)言,但終究沒(méi)用一個(gè)實(shí)在的例子回答同事,只是從結(jié)論上大侃一通,代碼相對(duì)于SQL,復(fù)用、擴(kuò)展、通用性都要更強(qiáng)。想必同事并不信服。
現(xiàn)在想來(lái),我最近正碰到的問(wèn)題,算是一個(gè)可以回答同事的例子吧。
最近項(xiàng)目中有個(gè)新需求,需要校驗(yàn)一個(gè)用戶是否有Job,Certification,Disclosure這三個(gè)業(yè)務(wù)數(shù)據(jù)。
翻看了代碼發(fā)現(xiàn),系統(tǒng)的用戶個(gè)人頁(yè)面的C#代碼調(diào)用了三個(gè)存儲(chǔ)過(guò)程,去抓取用戶的Job,Certification,Disclosure數(shù)據(jù)。
我的新需求,自然需要復(fù)用這三個(gè)存儲(chǔ)過(guò)程,否則:
若每一處都寫(xiě)一次抓取數(shù)據(jù)的業(yè)務(wù)邏輯代碼,若業(yè)務(wù)邏輯發(fā)生變化,難以追查和維護(hù)所有讀取Job,Certification,Disclosure的SQL。
那就動(dòng)手改。但沒(méi)想到的是問(wèn)題來(lái)了。
為了講述問(wèn)題,我簡(jiǎn)化代碼,假設(shè)系統(tǒng)現(xiàn)有的存儲(chǔ)過(guò)程如下:
CREATEPROCEDURE?[dbo].[GetJobs]
(
@PersonId?int,
@OrganizaitionId?int
)
AS
BEGIN
SELECT?JobId,JobName,JobType?FROM?Job?WHERE?PersonId = @PersonId?AND?OrganizaitionId = @OrganizaitionId
END
我在新的存儲(chǔ)過(guò)程中調(diào)用它,我需要獲得該person的jobs的數(shù)量,即GetJobs返回結(jié)果集的count。
為了實(shí)現(xiàn)這一目的,首先想到的是使用臨時(shí)表,將返回結(jié)果集存入臨時(shí)表,再對(duì)其進(jìn)行count(*)的計(jì)數(shù)操作:
CREATEPROCEDURE?[dbo].[MyProc]
(
@PersonId?int,
@OrganizaitionId?int,
)
AS
BEGIN
CREATETABLE#Temp(
PersonId?int,
OrganizaitionId?int
)
INSERTINTO#Temp EXEC dbo.GetJobs
@PersonId = @PersonId,
@ParentOrgId = @ParentOrgId
SELECTCOUNT(*)?FROM#Temp
END
這種辦法簡(jiǎn)單有效,但它存在嚴(yán)重的維護(hù)問(wèn)題。未來(lái)如果被調(diào)用的存儲(chǔ)過(guò)程的返回結(jié)果集字段有變動(dòng),那么MyProc中的臨時(shí)表結(jié)構(gòu)也需要隨之變化。這是令人難以接受的。
那么將MyProc中的INSERT INTO換為SELECT INTO呢?很遺憾,答案是不行。SQL本身并不支持這種用法。
給現(xiàn)有存儲(chǔ)過(guò)程GetJobs加output參數(shù)?本例中因?yàn)镚etJobs已被其他多處代碼或SQL scripts調(diào)用,所以對(duì)現(xiàn)有現(xiàn)有存儲(chǔ)過(guò)程進(jìn)行改動(dòng)會(huì)有不小風(fēng)險(xiǎn)。
我搜遍網(wǎng)絡(luò),一位MS MVP的大神的文章幾乎總結(jié)了所有存儲(chǔ)過(guò)程之間傳遞數(shù)據(jù)的方法: How to Share Data between Stored Procedures。他在文章中也無(wú)可奈何地說(shuō)道
Keep in mind that compared to languages such as C# and Java, Transact-SQL is poorly equipped for code reuse, why solutions in T?SQL to reuse code are clumsier.
最終我沒(méi)能找到一種滿意的辦法,無(wú)奈之下我在新寫(xiě)的存儲(chǔ)過(guò)程中將查詢Jobs的語(yǔ)句寫(xiě)一了次。
存儲(chǔ)過(guò)程在很多場(chǎng)景時(shí)有其優(yōu)勢(shì),比如性能。但對(duì)于業(yè)務(wù)邏輯的通用方法,非常不推薦將其寫(xiě)在存儲(chǔ)過(guò)程中,代碼復(fù)用、擴(kuò)展與客戶端語(yǔ)言比,相差甚遠(yuǎn)。也許終究能實(shí)現(xiàn),但代價(jià)與風(fēng)險(xiǎn)比客戶端語(yǔ)言要高,得不償失。
天知道還有沒(méi)有機(jī)會(huì)和那位前同事再討論這一話題呢。
作者 |?楊洋的圍脖啊
關(guān)注我的另一個(gè)公眾號(hào),回復(fù):阿里
掃描上方二維碼關(guān)注并回復(fù):阿里
就有申請(qǐng)地址啦!
