優秀的程式應該儘可能地規避問題。因此,以後在服務商系統里,當定義包含漢字的欄位時,使用 nvarchar2,而非 varchar2。 因此,在服務商系統作為我司系統的小眾系統的背景下,Oracle的技術特性我們不一一曉知是可以理解和接受的。而如何在不一一曉知這些技術特性的情況下,能夠規避這些技術特性... ...
Oracle資料庫varchar2欄位擴容-始末
今天,有後端小伙伴提了個sql工單。對我司服務商系統Oracle資料庫的一個mer_name欄位擴容。
alter table T_MER_SETTLE modify mer_name VARCHAR2(100)
審批前,我查了一下當前這個mer_name欄位的長度是 VARCHAR2(64)。
基於對我司客戶名稱的長度通常不超過64字的瞭解,我下意識里感到奇怪:莫非存在長度超過64個文字的客戶名稱?這種情況應該很少吧?什麼公司的名字能有這麼長呢?
然後,我找當事人來詢問。他言說,當時開發需求時,看到企業表裡的mer_name是varchar2(100),就沿襲使用varchar2了,加上對系統里企業名稱長度通常不會超過64個漢字的認識,就把新表的mer_name定義為varchar2(64)。 今天生產環境的告警顯示,在向這個T_MER_SETTLE表插入數據時出現“欄位值超長”持久化失敗的bug,這才得知Oracle的varchar2(64)與mysql的varchar(64)不同,mysql的varchar(64)能存最多64個字元,而Oracle的varchar2(64)則不同。在資料庫字元集是UTF-8的情況下,varchar2在存漢字時,是每個漢字占3個位元組。也就是說,這個varchar2(64)最多可以存64/3=21個漢字。
本著解決問題優先的原則,我審批了sql工單並執行sql。
優秀的程式應該儘可能地規避問題
欄位擴容,這是我們日常開發中經常遇到的小事。我們服務商系統類似對varchar2欄位擴容的案例,幾乎每月都發生。那麼,針對這個欄位擴容,大家有沒有琢磨過,我們如何在開發時就能規避呢?
優秀的程式應該儘可能地規避問題。我們來複盤一下這個事情。
有必要先說明一個情況,我司絕大多數系統以mysql資料庫為主,服務商系統是其中唯一一個使用Oracle資料庫的小眾系統。並且,服務商系統的日常維護或需求迭代較少,由我們技術團隊中的三個同學抽一部分精力兼管。 因此,大家對Oracle資料庫瞭解得並不多,相比mysql,就少多了。
好,繼續來複盤。
開發人員不瞭解varchar2這個技術點,憑著mysql資料庫經驗和對業務的瞭解,定義了 mer_name VARCHAR2(64) 。
我在審批時,也不瞭解varcahr2這個技術點,就去反問開發同學。同樣,其他同學,也未必清楚Oracle的varchar2這個數據類型的細節。
那麼,如何規避呢?
無藥可救了嗎?
不!
我們事後瞭解到,Oracle的nvarchar2不區分字元類型,它將漢字、全形符號與數字、字母、半形符號等均視為一個字元。也就是說,nvarchar2(64)表示可存最大64個字元。註意這裡不是位元組,而是字元。 包括 數字、字母、符號、以及漢字。同時,在存儲含有文字的欄位時,Oracle開發規範里建議使用nvarchar2取代varchar2。
因此,我們可以做什麼?
將資料庫里的mer_name的數據類型全部改為nvarchar2,以及其他的這種varchar2欄位類型使用不當的欄位。
這以後,服務商系統再有迭代開發時,開發者CV時,就不會(或很少)再有varchar2的mer_name了,樂觀一點講,再出現因varchar2數據類型使用不當而導致“欄位值超長”持久化失敗的bug就會扼殺在搖籃里。
【附】Oracle數據類型varchar2與nvarchar2
- varchar - Oracle不建議使用varchar類型(我在DBeaver中新建varchar欄位時自動建成了varchar2,無論是所見即所得的操作方式,還是執行DDL方式)
- varchar2 - varchar2(20) 表示可存最大20個位元組長度的字元串。 數字/字母/半形符號 占一個位元組。 對於全形符號或漢字,則要看字元集,GBK的話,一個漢字占2個位元組;UTF-8的話,一個漢字占3個位元組。
- nvarchar - Oracle中沒有nvarchar這個數據類型
- nvarchar2 - nvarchar2(20) 表示可存最大20個字元。註意這裡不是位元組了,而是字元。 包括 數字、字母、符號、以及漢字。每個字元占2個位元組存儲。
- varchar2是Oracle提供的特定數據類型,Oracle可以保證varchar2在任何版本中該數據類型都可以向上或向下相容。
- nvarchar2雖然更占空間,但是它有更好的相容性。尤其是當欄位包含漢字的情況下,推薦使用nvarchar2。 - - - - - - - - 我們服務商系統Oracle資料庫里,對於mer_name等包含漢字的欄位,大家往往沿襲使用varchar2(100甚至更大),我們在新建表裡涉及到這個欄位時,有開發者會誤以為Oracle的varchar2與mysql里的varchar相同,我們mysql應用里約定mer_name是varchar(32) ,就在Oracle庫里定義成了 varchar2(32) ,結果,服務商系統在生產運行過程中,出現插入mer_name因欄位值超長而持久化資料庫失敗。 - - - - - - - - 優秀的程式應總是儘可能地規避問題。因此,以後在服務商系統里,當定義包含漢字的欄位時,使用 nvarchar2,而非 varchar2。 因此,在服務商系統作為我司系統的小眾系統的背景下,Oracle的技術特性我們不一一曉知是可以理解和接受的。而如何在不一一曉知這些技術特性的情況下,能夠規避這些技術特性帶來的bug,需要我們引起思考和實踐摸索。
【附】欄位值超長,程式異常截圖↓
當看到一些不好的代碼時,會發現我還算優秀;當看到優秀的代碼時,也才意識到持續學習的重要!--buguge
本文來自博客園,轉載請註明原文鏈接:https://www.cnblogs.com/buguge/p/17995321