當前位置: 妍妍網 > 碼農

為什麽阿裏禁止使用儲存過程?

2024-03-20碼農

來源:segmentfault.com/a/1190000011138993

之所以有這個題目,我既不是故意吸引眼球,也不想在本文對儲存過程進行教科書般論述。【 阿裏巴巴Java開發手冊 】是這樣規定的:

再結合我最近計畫中遇到的儲存過程問題,所以今天我打算來聊一聊這個問題。

這事兒要從去年在武漢出差時一位同事的發問說起,問題是這樣的:

我覺得儲存過程挺好用的,你為什麽不建議用呢?

當時我好似胸有萬言,但終究沒用一個實在的例子回答同事,只是從結論上大侃一通,程式碼相對於SQL,復用、擴充套件、通用性都要更強。想必同事並不信服。

現在想來,我最近正碰到的問題,算是一個可以回答同事的例子吧。

最近計畫中有個新需求,需要校驗一個使用者是否有Job,Certification,Disclosure這三個業務數據。

翻看了程式碼發現,系統的使用者個人頁面的C#程式碼呼叫了三個儲存過程,去抓取使用者的Job,Certification,Disclosure數據。

我的新需求,自然需要復用這三個儲存過程,否則:

若每一處都寫一次抓取數據的業務邏輯程式碼,若業務邏輯發生變化,難以追查和維護所有讀取Job,Certification,Disclosure的SQL。

如果我在C#程式碼中呼叫這已有的三個儲存過程,事情本該非常快就能結束。我也是這麽做的。

但code reviewer認為,我的需求中,並不需要Job,Certification,Disclosure這三個業務物件的數據。我只是需要給定使用者是否有Job,Certification,Disclosure而已。

所以我應將是否有無Job,Certification,Disclosure的判斷邏輯寫在資料庫,最終透過網路從資料庫傳到web伺服器的僅是true或false,節省網路流量,這樣最好不過了。

也對。除開網路效能,從介面設計的角度講,介面的傳入和返回值,都應是你本身需要的數據,不應帶有大量不需要或者需要caller去預處理的數據。從介面語意表達就可知呼叫的目的,這樣程式碼可讀性也會有大大提高。

那就動手改。但沒想到的是問題來了。

為了講述問題,我簡化程式碼,假設系統現有的儲存過程如下:

CREATEPROCEDURE [dbo].[GetJobs] ( @PersonId int, @OrganizaitionId int) ASBEGINSELECT JobId,JobName,JobType FROM Job WHERE PersonId = @PersonId AND OrganizaitionId = @OrganizaitionId END

我在新的儲存過程中呼叫它,我需要獲得該person的jobs的數量,即GetJobs返回結果集的count。

為了實作這一目的,首先想到的是使用臨時表,將返回結果集存入臨時表,再對其進行 count(*) 的計數操作:

CREATEPROCEDURE [dbo].[MyProc] ( @PersonId int, @OrganizaitionId int, ) ASBEGINCREATETABLE#Temp( PersonId int, OrganizaitionId int)INSERTINTO#Temp EXEC dbo.GetJobs @PersonId = @PersonId, @ParentOrgId = @ParentOrgIdSELECTCOUNT(*) FROM#Temp END

這種辦法簡單有效,但它存在嚴重的維護問題。未來如果被呼叫的儲存過程的返回結果集欄位有變動,那麽MyProc中的臨時表結構也需要隨之變化。這是令人難以接受的。

那麽將MyProc中的INSERT INTO換為SELECT INTO呢?很遺憾,答案是不行。SQL本身並不支持這種用法。

給現有儲存過程GetJobs加output參數?本例中因為GetJobs已被其他多處程式碼或SQL scripts呼叫,所以對現有現有儲存過程進行改動會有不小風險。

我搜遍網路,一位MS MVP的大神的文章幾乎總結了所有儲存過程之間傳遞數據的方法: How to Share Data between Stored Procedures。他在文章中也無可奈何地說道

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.

最終我沒能找到一種滿意的辦法,無奈之下我在新寫的儲存過程中將查詢Jobs的語句寫一了次。

儲存過程在很多場景時有其優勢,比如效能。但對於業務邏輯的通用方法,非常不推薦將其寫在儲存過程中,程式碼復用、擴充套件與客戶端語言比,相差甚遠。也許終究能實作,但代價與風險比客戶端語言要高,得不償失。

天知道還有沒有機會和那位前同事再討論這一話題呢。

>>

END

精品資料,超贊福利,免費領

微信掃碼/長按辨識 添加【技術交流群

群內每天分享精品學習資料

最近開發整理了一個用於速刷面試題的小程式;其中收錄了上千道常見面試題及答案(包含基礎並行JVMMySQLRedisSpringSpringMVCSpringBootSpringCloud訊息佇列等多個型別),歡迎您的使用。

👇👇

👇點選"閱讀原文",獲取更多資料(持續更新中