MySQL處理約束的方式

2022-08-05 05:03:16 字數 3585 閱讀 3467

使用mysql,你可以使用允許回滾的事務表,以及不允許回滾的非事務表。因此,在mysql中的約束處理功能與其他dbms中的略有不同。在非事務性表中插入或更新大量行時,當出現錯誤以至於不能回滾所作的變更時,必須處理該情況。

其基本原理在於,在解析將要執行的語句的同時,mysql伺服器會盡量為檢測到的問題生成錯誤資訊,並會在執行語句的同時盡量恢復出現的錯誤。在大多數情況下我們均是這樣作的,但不包括所有情況。

出現錯誤時,mysql可選擇中途中止語句,或盡可能恢復並繼續執行語句。預設情況下,伺服器將採取後一種路線。這意味著,伺服器可能會強制將非法值變為最接近的合法值(例如)。

從mysql 5.0.2開始,提供了數種sql模式,使用它們,能夠對如何接受可能為不良資料值的方式進行更好的控制,也能在出現錯誤時,對是否繼續執行語句或放棄語句進行控制。使用這些選項,能夠將mysql伺服器配置為更為傳統的風格,類似於拒絕不恰當輸入的其他dbms。可以在執行時設定sql模式,這樣,各客戶端就能選擇與其需求最為貼切的行為。

在以下部分,介紹了使用不同約束型別的情況。

1、primary key和unique索引約束

通常情況下,當你試圖insert或update會導致主鍵、唯一鍵或外來鍵衝突的行時,將出現錯誤。如果你正在使用事務性儲存引擎時,如innodb,mysql會自動回滾語句。如果你正在使用非事務性儲存引擎,mysql將在出錯的行上停止執行語句,剩餘的行也不再處理。

如果你希望忽略這類鍵衝突,可使用mysql支援的、用於insert和update的ignore關鍵字。在這種情況下,mysql將忽略任何鍵衝突,並繼續處理下一行。

使用mysql_info() c api函式,能夠獲取關於實際插入或更新行數的資訊。在mysql 4.1和更高版本中,也能使用show warnings語句。目前,只有innodb表支援外來鍵。

2. 對無效資料的約束

在mysql 5.0.2之前,mysql對非法或不當值並不嚴厲,而且為了資料輸入還會強制將它們變為合法值。在mysql 5.0.2和更高版本中,保留了以前的預設行為,但你可以為不良值選擇更傳統的處理方法,從而使得伺服器能夠拒絕並放棄出現不良值的語句。本節介紹了mysql的預設行為(寬大行為),新的嚴格的sql模式,以及它們的區別。

如果你未使用嚴格模式,下述情況是真實的。如果將「不正確」的值插入到列,如將null值插入非null列,或將過大的數值插入數值列,mysql會將這些列設定為「最可能的值」,而不是生成錯誤資訊。

·         如果試圖將超範圍的值儲存到數值列,mysql伺服器將儲存0(最小的可能值)取而代之,或最大的可能值。

·         對於字串,mysql或儲存空字串,或將字串盡可能多的部分儲存到列中。

·         如果打算將不是以數值開頭的字串儲存到數值列,mysql將儲存0。

·         mysql允許將特定的不正確日期值儲存到date和datetime列(如「2000-02-31」或「2000-02-00」)。其觀點在於,驗證日期不是sql伺服器的任務。如果mysql能儲存日期值並準確檢索相同的值,mysql就能按給定的值儲存它。如果日期完全不正確(超出伺服器能儲存的範圍)將在列中儲存特殊的日期值「0000-00-00」取而代之。

·         如果試圖將null值儲存到不接受null值的列,對於單行insert語句,將出現錯誤。對於多行insert語句或insert into ... select語句,mysql伺服器會儲存針對列資料型別的隱含預設值。一般情況下,對於數值型別,它是0,對於字串型別,它是空字串(''),對於日期和時間型別是「zero」。

·         如果insert語句未為列指定值,如果列定義包含明確的default子句,mysql將插入預設值。如果在定義中沒有這類default子句,mysql會插入列資料型別的隱含預設值。

採用前述規則的原因在於,在語句開始執行前,無法檢查這些狀況。如果在更新了數行後遇到這類問題,我們不能僅靠回滾解決,這是因為儲存引擎可能不支援回滾。中止語句並不是良好的選擇,在該情況下,更新完成了「一半」,這或許是最差的情況。對於本例,較好的方法是「僅可能做到最好」,然後就像什麼都未發生那樣繼續。

在mysql 5.0.2和更高版本中,可以使用strict_trans_tables或strict_all_tables sql模式,選擇更嚴格的處理方式。

strict_trans_tables的工作方式:

·         對於事務性儲存引擎,在語句中任何地方出現的不良資料值均會導致放棄語句並執行回滾。

·         對於非事務性儲存引擎,如果錯誤出現在要插入或更新的第1行,將放棄語句。(在這種情況下,可以認為語句未改變表,就像事務表一樣)。首行後出現的錯誤不會導致放棄語句。取而代之的是,將調整不良資料值,並給出告警,而不是錯誤。換句話講,使用strict_trans_tables後,錯誤值會導致mysql執行回滾操作,如果可以,所有更新到此為止。

要想執行更嚴格的檢查,請啟用strict_all_tables。除了非事務性儲存引擎,它與strict_trans_tables等同,即使當不良資料出現在首行後的其他行,所產生的錯誤也會導致放棄語句。這意味著,如果錯誤出現在非事務性表多行插入或更新過程的中途,僅更新部分結果。前面的行將完成插入或更新,但錯誤出現點後面的行則不然。對於非事務性表,為了避免這種情況的發生,可使用單行語句,或者在能接受轉換警告而不是錯誤的情況下使用strict_trans_tables。要想在第1場合防止問題的出現,不要使用mysql來檢查列的內容。最安全的方式(通常也較快)是,讓應用程式負責,僅將有效值傳遞給資料庫。

有了嚴格的模式選項後,可使用insert ignore或update ignore而不是不帶ignore的insert或update,將錯誤當作告警對待。

3. enum和set約束

enum和set列提供了定義僅能包含給定值集合的列的有效方式。但是,從mysql 5.0.2起,enum和set不是實際約束。其原因與不重視not null的原因一樣。請參見2節,「對無效資料的約束」。

enum列總有1個預設值。如果未指定預設值,對於包含null的列,預設值為null;否則,第1個列舉值將被當作預設值。

如果在enum列中插入了不正確的值,或者,如果使用ignore將值強制插入了enum列,會將其設定為保留的列舉值0,對於字串情形,將顯示為空字串。

如果在set列中插入了不正確值,該值將被忽略。例如,如果列能包含值「a」、「b」和「c」,並賦值「a,x,b,y」,結果為「a,b」。

從5.0.2開始,可以對伺服器進行配置,以使用嚴格的sql模式。啟用嚴格模式後,enum或set列的定義可作為對輸入至列的值的約束。如果值不滿足下述條件,將出現錯誤:

·         enum值必須是在列定義中給出的值之一,或內部的數字等同物。該值不能是錯誤值(即,0或空字串)。對於定義為enum('a','b','c')的列,諸如''、'd'和'ax'等,均是非法的,並將被拒。

·         set值必須是空字串,或由1個或多個在列定義中給出的且用逗號隔開的值組成。 對於定義為set('a','b','c')的列,諸如'd'和'a,b,c,d'等,均是非法的,並將被拒。

如果使用了insert ignore或update ignore,在嚴格模式下,可抑制無效值導致的錯誤。在這種情況下,將生成警告而不是錯誤。對於enum,值將作為錯誤成員(0)插入。對於set,會將給定值插入,但無效的子字串將被刪除。例如,'a,x,b,y'的結果是'a,b',就像前面介紹的那樣。

MySQL外來鍵約束方式

mysql外來鍵約束方式 如果表a的主關鍵字是表b中的字段,則該字段稱為表b的外來鍵,表a稱為主表,表b稱為從表。外來鍵是用來實現參照完整性的,不同的外來鍵約束方式將可以使兩張表緊密的結合起來,特別是修改或者刪除的級聯操作將使得日常的維護工作更加輕鬆。這裡以mysql為例,總結一下3種外來鍵約束方式...

mysql如何處理外碼約束

建立測試主表.id 是主鍵.create table test main id int,value varchar 10 primary key id 建立測試子表.create table test sub id int,main id int,value varchar 10 primary k...

mysql如何處理外碼約束

建立測試主表.id 是主鍵.create table test main id int,value varchar 10 primary key id 建立測試子表.create table test sub id int,main id int,value varchar 10 primary k...