【MySQL随手记】一个踩坑记录:在安全更新模式下进行数据的修改与删除
目錄
前言
1 MySQL練習(xí)的數(shù)據(jù)準(zhǔn)備
2 Error Code:1175與安全更新模式
2.1 Error Code:1175
2.2 安全更新模式
3? 安全更新模式下的update和delete練習(xí)記錄
3.1 新問題1:Error Code: 1093
3.2 新問題2:要刪除的記錄在其他表中無關(guān)聯(lián)記錄
4 體驗(yàn)一下安全更新模式的好處
附錄:建庫、建表和添加數(shù)據(jù)代碼
前言
最近我入坑了MySQL,跟著教程用裝在windows電腦上的Navicat for MySQL一步步操作,一切都很順利。為了緩解對軟件界面的審美疲勞,我用另一臺ubuntu電腦上的MySQL Workbench做鞏固練習(xí)。體驗(yàn)下來,Workbench除了不支持中文,用起來還是很舒服的,而且還完全免費(fèi)。然而,在做一些數(shù)據(jù)的修改(update)和刪除(delete)時,遇到了Error Code: 1175的問題。在解決問題的過程仍有一些困惑,還請各路大神指教。
1 MySQL練習(xí)的數(shù)據(jù)準(zhǔn)備
我建了一個數(shù)據(jù)庫“college(大學(xué))”,數(shù)據(jù)庫里包含三張數(shù)據(jù)表:department(院系)、teacher(教師)、achievement(成果)。建庫、建表以及添加數(shù)據(jù)的代碼見附錄。
這里說明一下各表的關(guān)聯(lián)關(guān)系,department表的主鍵是dep_id;teacher表的主鍵是tea_id,外鍵是dep_id,引用department表的主鍵dep_id;achievement表的主鍵是tea_id。因此,department具有主外鍵聯(lián)系,teacher和achievement依靠兩個id主鍵聯(lián)系,department和achievement沒有直接聯(lián)系,需要以teacher為中介。
下圖中achievement表里面的teacher_tea_id和外鍵fk_achievement_teacher1_idx都是系統(tǒng)添加的。這個關(guān)系圖的生成是在做完練習(xí)之后,在聯(lián)合查詢時用where語句構(gòu)建了achievement和teacher表主鍵之間的關(guān)系,因此系統(tǒng)生成了這樣的外鍵。(在做查詢前畫這個圖是沒有的)
三張數(shù)據(jù)表的內(nèi)容展示在這里:
2 Error Code:1175與安全更新模式
2.1 Error Code:1175
在練習(xí)中,我想實(shí)現(xiàn)這樣一個需求:將“張三”的職稱改為“研究員”,我照著教程依葫蘆畫瓢寫了這樣一個語句:
update teacher set title='研究員' where name='張三';居然沒有執(zhí)行成功,Workbench報出這樣一條錯誤提示:
Error Code: 1175. You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column.? To disable safe mode, toggle the option in Preferences -> SQL Editor and reconnect.
提示我現(xiàn)在使用的是安全更新模式(safe update mode),該模式下不允許在where子句中用不是“鍵(key)”的列作為條件,想要取消安全模式,需要在SQL Editor的首選項(xiàng)中關(guān)掉該模式并重新連接數(shù)據(jù)庫。
2.2 安全更新模式
把安全更新模式關(guān)掉當(dāng)然是很簡單的,但是任何事物的存在都有其理由。去網(wǎng)上查了一下,對于這個模式作用一般都是下面的說法:
在mysql中,如果在update和delete沒有加上where條件,數(shù)據(jù)將會全部修改。不只是初識mysql的開發(fā)者會遇到這個問題,工作有一定經(jīng)驗(yàn)的工程師難免也會忘記寫入where條件。為了避免失誤造成的數(shù)據(jù)全部修改和刪除,可開啟mysql的安全模式。
感覺蠻有道理的,但是我們的update操作是有where的。從報錯信息中,我們看到在where子句內(nèi)部還有一層限制,那就是必須以充當(dāng)“鍵”的列作為條件。
對于安全更新模式的開啟與關(guān)閉,在Workbench中有兩種方法,一是用SQL語句,二是用客戶端的設(shè)置頁面。
先來看語句,查看安全模式是否開啟、開啟安全模式和關(guān)閉安全模式的語句都是比較簡單的:
# 查看是否開啟 show variables like 'SQL_SAFE_UPDATES'; # 開啟 SET SQL_SAFE_UPDATES = 1; # 關(guān)閉 SET SQL_SAFE_UPDATES = 0;在Workbench客戶端中的設(shè)置方法也不難,按鍵過程是:Edit -> Preferences -> SQL Editor -> 勾選/取消勾選 "Safe Updates",然后重新鏈接數(shù)據(jù)庫。
3? 安全更新模式下的update和delete練習(xí)記錄
作為嚴(yán)謹(jǐn)?shù)募夹g(shù)學(xué)習(xí)者,當(dāng)然不能一關(guān)了之,還是要琢磨一下如何在該模式下實(shí)現(xiàn)符合需求的update和delete操作。這里真正要思考的問題時如何完全依靠數(shù)據(jù)表的主外鍵關(guān)聯(lián)來完成指定條件下數(shù)據(jù)的修改與刪除。在這個過程中,又遇到了新問題。
3.1 新問題1:Error Code: 1093
繼續(xù)實(shí)現(xiàn)上面那個需求:將“張三”的職稱改為“研究員”。我這個技術(shù)小白傻不拉幾地模仿之前學(xué)的子查詢的語句寫了一條更新語句:
# 被模仿的子查詢語句 select * from teacher where tea_id=(select tea_id from teacher where name='張三');# 依葫蘆畫瓢寫的更新語句 update teacher set title='研究員' where tea_id=(select tea_id from teacher where name='張三');上面的語句執(zhí)行起來沒有問題,下面的語句執(zhí)行出錯,報出代碼為1093的錯誤:
Error Code: 1093. You can't specify target table 'teacher' for update in FROM clause
說是不能在FROM子句中為update操作指定目標(biāo)表“teacher”。想想也是,所謂“子查詢”就是查詢里面套著查詢,子查詢操作確實(shí)不該套在更新語句語句里面。
不過,查詢還是要查詢,得不到張三的id怎么通過“鍵”來設(shè)定數(shù)據(jù)修改的條件呢?此時,我突然想到,查詢出來的結(jié)果不也是一個表嗎?把查詢得到的表和要修改的數(shù)據(jù)表進(jìn)行連接(join)不就行了嗎?于是,我又寫了下面的語句:
# 將查詢得到的 虛擬表 和 要修改的表 進(jìn)行內(nèi)連接 update teacher t inner join (select tea_id from teacher where name='張三') t2 set title='研究員' where t.tea_id=t2.tea_id;# 寫成如下形式效果是一樣的 update teacher t, (select tea_id from teacher where name='張三') t2 set title='研究員' where t.tea_id=t2.tea_id;運(yùn)行上面的語句,輸出框終于從紅色的叉變成了綠色的勾,修改生效了!
刪除同樣可以用連接(join)的方式實(shí)現(xiàn),比如這樣一條刪除需求:刪除“ 數(shù)學(xué)系”相關(guān)的全部記錄,這意味著不僅要在要在department表中刪除數(shù)學(xué)系,還要在teacher表和achievement表中刪除與之關(guān)聯(lián)的記錄,包括數(shù)學(xué)系教師及其科研成果。非安全模式和安全模式下的刪除語句如下:
# 這種寫法在 不打開安全模式 的情況下是可行的 delete d,t,a from department d, teacher t, achievement a where d.dep_name='數(shù)學(xué)系' and t.tea_id=a.tea_id;# 安全模式下可以用 連接 的方式實(shí)現(xiàn) delete d,t,a from department d, teacher t, achievement a, (select dep_id from department d where dep_name='數(shù)學(xué)系') d2 where d.dep_id=d2.dep_id and t.dep_id=d.dep_id and t.tea_id=a.tea_id;可以看到,院系表中的“數(shù)學(xué)系”不見了,教師表中的“王五”也被刪掉了,成果表中也少了id為21020的記錄。
3.2 新問題2:要刪除的記錄在其他表中無關(guān)聯(lián)記錄
刪完“數(shù)學(xué)系”的相關(guān)記錄后還想把“機(jī)電系”的也刪掉。當(dāng)然,作為一個練習(xí),我們知道機(jī)電系在其他表中沒有關(guān)聯(lián)記錄,即沒有老師,當(dāng)然也沒有成果。為了模擬實(shí)際應(yīng)用場景,我們假裝不知道這個情況,仍然沿用上面的刪除語句:
delete d,t,a from department d, teacher t, achievement a , (select dep_id from department d where dep_name='機(jī)電系') d2 where d.dep_id=d2.dep_id and t.dep_id=d.dep_id and t.tea_id=a.tea_id;語句執(zhí)行是成功的,沒有報錯。但是 0 row(s) affected,也就是根本沒有刪除成功!
仔細(xì)想了想,我得出這樣的理解,不知道對不對。這里的where子句需要指明t,d,a,d2四表的關(guān)聯(lián)關(guān)系,四個表需要三個等號(=)。由于t表中沒有“機(jī)電系”老師的信息,那么t表和虛擬表d2其實(shí)是無法構(gòu)成關(guān)聯(lián)的,雖然語句中寫的是t和d兩個表主鍵的關(guān)聯(lián)關(guān)系(t.dep_id=d.dep_id),但是d又要與d2有關(guān)聯(lián),因此t和d2應(yīng)該有經(jīng)由d傳遞而來的間接聯(lián)系,然而并沒有,這就不合邏輯了。如此一來,整個where語句的條件無法被滿足,刪除也就不會執(zhí)行了。如果我的理解是錯的,還請看到此文的大神給予指正,小弟感激不盡。
為了解決這個問題,以一個剛?cè)腴T小白的知識儲備,只能是先查一下要刪除記錄的數(shù)據(jù)表是否有關(guān)聯(lián)的記錄,然后在刪除語句中加入需要涉及到的數(shù)據(jù)表。如果看到此文的大佬有更好的解決方法,也請給小弟指點(diǎn)迷津。
這里采用左連接的方式查詢各表的主鍵,因?yàn)閯h除條件來自院系表(d),所以主表是d表。查詢的目的是看t和a能否匹配出數(shù)據(jù),哪個表匹配不出數(shù)據(jù)(得出null),刪除時就不涉及哪個表。
select d.dep_id, t.tea_id t_id, a.tea_id a_id from department d left join teacher t on d.dep_id=t.dep_id left join achievement a on a.tea_id=t.tea_id where dep_name='機(jī)電系';根據(jù)上面查詢得出的結(jié)果,刪除操作應(yīng)該只涉及department表。
delete d from department d, (select dep_id from department d where dep_name='機(jī)電系') d2 where d.dep_id=d2.dep_id;終于刪掉了。
4 體驗(yàn)一下安全更新模式的好處
在這里體會一下在關(guān)閉安全更新模式的情況下可能出現(xiàn)的問題。如上文引用的一般說法,忘記加where條件的可能性估計不大,但是在表比較多的情況下,where子句中漏寫表的關(guān)聯(lián)關(guān)系是有可能的,這也會造成一些可怕的情況。
如果where子句中漏寫了一個關(guān)聯(lián)關(guān)系,仍然會報出1175錯誤,還拿上面多表刪除的語句作為例子,比如這次要刪的“計算機(jī)系”:
# teacher表 和 achievement表 的關(guān)聯(lián)關(guān)系沒有寫 delete d,t,a from department d, teacher t, achievement a inner join (select dep_id from department d where dep_name='計算機(jī)系') d2 where d.dep_id=d2.dep_id and t.dep_id=d.dep_id;報出 Error Code:1175 的錯誤:
下面看看把安全模式關(guān)掉會怎么樣,首先執(zhí)行關(guān)閉語句,再查看一下:
# 關(guān)掉安全更新模式 SET SQL_SAFE_UPDATES = 0; # 查看一下 show variables like 'SQL_SAFE_UPDATES';現(xiàn)在已經(jīng)關(guān)掉了。再執(zhí)行上面where子句沒寫全關(guān)聯(lián)關(guān)系的刪除語句,可怕的情況出現(xiàn)了,下面是執(zhí)行完之后各個數(shù)據(jù)表的情況:
department表是正常的,刪之前只剩下中文系和計算機(jī)系,刪之后應(yīng)該只剩下中文系。teacher表也是對的,刪除后只剩下兩位中文系老師。出問題的是achievement表,居然被刪空了!!!其原因就在于where子句中漏寫了a表和t表的關(guān)聯(lián)關(guān)系,如果安全更新模式是開啟的,就能避免這種災(zāi)難的發(fā)生。
附錄:建庫、建表和添加數(shù)據(jù)代碼
# 創(chuàng)建 數(shù)據(jù)庫 大學(xué) 并 使用 CREATE DATABASE college /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_bin */; USE college;# 創(chuàng)建 數(shù)據(jù)表 院系 并 添加 數(shù)據(jù) CREATE TABLE department (dep_id varchar(2) NOT NULL,dep_name varchar(20) DEFAULT NULL,PRIMARY KEY (dep_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;INSERT INTO department VALUES('10', '中文系'); INSERT INTO department VALUES('20', '數(shù)學(xué)系'); INSERT INTO department VALUES('30', '計算機(jī)系'); INSERT INTO department VALUES('31', '機(jī)電系');# 創(chuàng)建 數(shù)據(jù)表 教師 并 添加 數(shù)據(jù) CREATE TABLE teacher (tea_id varchar(5) NOT NULL,`name` varchar(10) DEFAULT NULL,gender char(3) DEFAULT NULL,title varchar(10) DEFAULT NULL,dep_id varchar(4) DEFAULT NULL,PRIMARY KEY (tea_id),CONSTRAINT fk_tea_dep FOREIGN KEY (dep_id) REFERENCES department (dep_id) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8;INSERT INTO teacher VALUES ('21010', '張三', '男', '教授', '10'); INSERT INTO teacher VALUES ('21011', '李四', '女', '副教授','10'); INSERT INTO teacher VALUES ('21020', '王五', '男', '講師', '20'); INSERT INTO teacher VALUES ('21030', '趙六', '男', '助教', '30');# 創(chuàng)建 數(shù)據(jù)表 科研成果 并 添加 數(shù)據(jù) CREATE TABLE achievement (tea_id varchar(5) NOT NULL,essay_num int(11) DEFAULT NULL,monograph_num int(11) DEFAULT NULL,patent_num int(11) DEFAULT NULL,PRIMARY KEY (tea_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;INSERT INTO achievement VALUES ('21010', 10, 2, 0); INSERT INTO achievement VALUES ('21011', 8, 4, 0); INSERT INTO achievement VALUES ('21020', 5, 1, 1); INSERT INTO achievement VALUES ('21030', 6, 0, 2);總結(jié)
以上是生活随笔為你收集整理的【MySQL随手记】一个踩坑记录:在安全更新模式下进行数据的修改与删除的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【MySQL随手记】字符集编码的查看、指
- 下一篇: linux cmake编译源码,linu