不管是開發、測試,仍是DBA,都不免會涉及到數據庫的操做,好比:建立某張表,添加某個字段、添加數據、更新數據、刪除數據、查詢數據等等。php
正常狀況下還好,但若是操做數據庫時出現失誤,好比:mysql
還有不少不少場景,我就不一一列舉了。nginx
若是出現線上環境數據庫誤操做怎麼辦?有沒有後悔藥?面試
答案是有的,請各位看官仔細往下看。sql
一般開發人員寫好sql語句以後,習慣經過聊天工具,好比:qq、釘釘、或者騰訊通等,發給團隊老大
或者DBA
在線上環境執行。但因爲有些聊天工具,對部分特殊字符
會自動轉義,並且有些消息因爲內容太長
,會被自動分紅多條消息。數據庫
這樣會致使團隊老大或者DBA複製出來的sql不必定是正確的。服務器
他們須要手動拼接成一條完整的sql
,有時甚至須要把轉義後的字符替換回之前的特殊字符,無形之中會浪費不少額外的時間。即便最終sql拼接好了,真正執行sql的人,內心必定很虛。併發
因此,強烈建議你把要在線上執行的sql語句用郵件
發過去,能夠避免使用聊天工具的一些弊端,減小一些誤操做的機會。並且有個存檔,方便從此有問題的時候回溯緣由。不少聊天工具只保留最近7天
的歷史記錄,郵件會保留更久一些。編輯器
別用聊天工具發sql語句!高併發
別用聊天工具發sql語句!
別用聊天工具發sql語句!
重要的事情說三遍,它真的能減小一些誤操做。
有些時候,開發人員寫的sql語句很長,使用了各類join
和union
,並且使用美化工具,將一條sql變成了多行。在複製sql的時候,本身都沒法肯定sql是否完整。(爲了裝逼,把本身也坑了,哈哈哈)
線上環境有時候須要經過命令行鏈接數據庫,好比:mysql,你把sql語句複製過來後,在命令行界面執行,因爲屏幕滾動太快,這時根本沒法肯定sql是否都執行成功。
針對這類問題,強烈建議把sql語句壓縮成一行
,去掉多餘的換行符
和空格
,能夠有效的減小一些誤操做。
sql壓縮工具
推薦使用:https://tool.lu/sql/
須要特別說明的是:本文的操做數據主要指修改
和刪除
數據。
不少時候,因爲咱們人爲失誤,把where條件寫錯了。但沒有怎麼仔細檢查,就把sql語句直接執行了。影響範圍小還好,若是影響幾萬、幾十萬,甚至幾百萬行數據,咱們可能要哭了。
針對這種狀況,在操做數據以前,把sql先改爲select count(*)
語句,好比:
update order set status=1 where status=0;
改爲:
select count(*) from order where status=0;
查一下該sql執行後影響的記錄行數,作到本身心中有數。也給本身一次測試sql是否正確,確認是否執行的機會。
即便經過上面的select
語句確認了sql語句沒有問題,執行後影響的記錄行數是對的。
也建議你不要馬上執行,建議在正在執行的時候,加上limit
+ select出的記錄行數
。例如:
update order set status=1 where status=0 limit 1000;
假設有一次性更新的數據太多,全部相關記錄行都會被鎖住,形成長時間的鎖等待,而形成用戶請求超時。
此外,加limit
能夠避免一次性操做太多數據,對服務器的cpu形成影響。
還有一個最重要的緣由:加limit
後,操做數據的影響範圍是徹底可控的。
不少人寫update
語句時,若是要修改狀態,就只更新狀態,無論其餘的字段。好比:
update order set status=1 where status=0;
這條sql會把status
等於0的數據,所有更新成1。
後來發現業務邏輯有問題,不該該這麼更新,須要把status
狀態回滾。
這時你可能會很天然想到這條sql:
update order set status=0 where status=1;
但仔細想一想又有些不對。
這樣不是會把有部分之前status
就是1的數據更新成0?
這回真的要哭了,嗚嗚嗚。
這時,送你一個好習慣:在更新數據的時候,同時更新修改人
和修改時間
字段。
update order set status=1,edit_date=now(),edit_user='admin' where status=0;
這樣在恢復數據時就能經過修改人
和修改時間
字段過濾數據了。
修改人修改時間
後面須要用到的修改時間
經過這條sql語句能夠輕鬆找到:
select edit_user ,edit_date from `order` order by edit_date desc limit 50;
固然,若是是高併發系統不建議這種批量更新方式,可能會鎖表必定時間,形成請求超時。
有些同窗可能會問:爲何要同時更新修改人,只更新修改時間不行嗎?
主要有以下的緣由:
在業務開發中,刪除數據是必不可少的一種業務場景。
有些人開發人員習慣將表設計成物理刪除
,根據主鍵只用一條delete
語句就能輕鬆搞定。
他們給出的理由是:節省數據庫的存儲空間
。
想法是好的,可是現實很殘酷。
若是有條極重要的數據刪錯了,想恢復怎麼辦?
此時只剩八個字:沒有數據,恢復不了。(PS:或許經過binlog二進制文件能夠恢復)
若是以前設計表的時候用的邏輯刪除
,上面的問題就變得好辦了。刪除數據時,只需update
刪除狀態便可,例如:
update order set del_status=1,edit_date=now(),edit_user='admin' where id=123;
假如出現異常,要恢復數據,把該id的刪除狀態還原便可,例如:
update order set del_status=0,edit_date=now(),edit_user='admin' where id=123;
若是隻是修改了少許的數據,或者只執行了一兩條sql語句,經過上面的修改人
和修改時間
字段,在須要回滾時,能快速的定位到正確的數據。
可是若是修改的記錄行數不少,而且執行了多條sql,產生了不少修改時間
。這時,你可能就要犯難了,無法一次性找出哪些數據須要回滾。
爲了解決這類問題,能夠將表作備份。
可使用以下sql備份:
create table order_bak_2021031721 like`order`;
insert into order_bak_2021031721 select * from`order`;
先建立一張如出一轍的表,而後把數據複製到新表中。
也能夠簡化成一條sql:
create table order_bak_2021031722 select * from`order`;
建立表的同時複製數據到新表中。
此外,建議在表名中加上
bak
和時間
,一方面是爲了經過表名快速識別出哪些表是備份表,另外一方面是爲了備份屢次時好作區分。由於有時須要執行屢次sql才能把數據修復好,這種狀況建議把表備份屢次,若是出現異常,把數據回滾到最近的一次備份,能夠節省不少重複操做的時間。
恢復數據時,把sql語句改爲select
語句,先在備份庫找出相關數據,每條數據對應一條update
語句,還原到老表中。
有時候,咱們要先用一條sql查詢出要更新的記錄的id,而後經過這些id更新數據。
批量更新以後,發現不對,要回滾數據。但因爲有些數據已更新,此時使用相同的sql相同的條件,卻查不出上次相同的id了。
這時,咱們開始慌了。
針對這種狀況,咱們能夠先將第一次查詢的id存入一張臨時表
,而後經過臨時表
中的id做爲查詢條件更新數據。
若是要恢復數據,只用經過臨時
表中的id做爲查詢條件更新數據便可。
修改完,3天以後,若是沒有出現問題,就能夠把臨時表
刪掉了。
咱們在寫sql時爲了方便,習慣性不帶數據庫名稱。好比:
update order set status=1,edit_date=now(),edit_user='admin' where status=0;
假若有多個數據庫中有相同的表order
,表結構如出一轍,只是數據不同。
order
因爲執行sql語句的人一個小失誤,進錯數據庫了。
use trade1;
而後執行了這條sql語句,結果悲劇了。
有個很是有效的預防這類問題的方法是加數據庫名
:
update `trade2`.`order` set status=1,edit_date=now(),edit_user='admin' where status=0;
這樣即便執行sql語句前進錯數據庫了,也沒什麼影響。
不少時候,咱們少不了對錶字段的操做,好比:新加、修改、刪除字段,但每種狀況都不同。
新加的字段必定要容許爲空。爲何要這樣設計呢?
正常狀況下,若是程序新加了字段,通常是先在數據庫中加字段,而後再發程序的最新代碼。
爲何是這種順序?
由於若是先發程序,而後在數據庫中加字段。在該程序剛部署成功,但數據庫新字段還沒來得及加的這段時間內,最新程序中,全部使用了新加字段的增刪改查sql都會報字段不存在的異常。
好了,就按先在數據庫中加字段,再發程序的順序。
若是數據庫中新加的字段非空,最新的程序還沒發,線上跑的仍是老代碼,這時若是有insert
操做,就會報字段不能爲空的異常。由於新加的非空字段,老代碼是無法賦值的。
因此說新加的字段必定要容許爲空。
除此以外,這種設計更多的考慮是爲了程序發佈失敗時的回滾操做。若是新加的字段容許爲空,則能夠不用回滾數據庫,只需回滾代碼便可,是否是很方便?
刪除字段是不容許的,特別是必填字段必定不能刪除。
爲何這麼說?
假設開發人員已經把程序改爲不使用刪除字段了,接下來如何部署呢?
insert
請求時,因爲數據庫中該字段是必填的,會報必填字段不能爲空的異常。增刪改查
,都會報字段不存在的異常。因此,線上環境必填字段必定不能刪除的。
修改字段要分爲這三種狀況:
修改字段名稱也不容許,跟刪除必填字段的問題差很少。
增刪改查
,都會報字段不存在的異常。增刪改查
,一樣也會報字段不存在的異常。因此,線上環境字段名稱必定不要修改。
修改字段類型時必定要兼容以前的數據。例如:
字段長度建議改大,一般狀況下,不建議改小。若是必定要改小,要先確認該字段可能會出現的最大長度,避免insert
操做時出現字段太長的異常。
此外,建議改大也須要設置一個合理的長度,避免數據庫資源浪費。
本文分享了10種減小數據庫誤操做的方法,並不是全部場景都適合你。特別是在一些高併發,或者單表數據量很是大的場景,你須要根據實際狀況酌情選擇。但我敢確定的是讀完這篇文章,你必定會有一些收穫,由於大部分方法對你來講是適用的,可能會讓你少走不少彎路,強烈建議收藏。
若是這篇文章對您有所幫助,或者有所啓發的話,幫忙關注一下,您的支持是我堅持寫做最大的動力。
求一鍵三連:點贊、轉發、在看。
關注公衆號:【蘇三說技術】,在公衆號中回覆:面試、代碼神器、開發手冊、時間管理有超讚的粉絲福利,另外回覆:加羣,能夠跟不少BAT大廠的前輩交流和學習。