MySQL - - 【視圖】【觸發器】【存儲過程】【函數】【事物】【數據庫鎖】【數據庫備份】

目錄

  • 視圖
  • 觸發器
  • 存儲過程
  • 函數
  • 事物
  • 數據庫鎖
  • 數據庫備份

1 視圖

  • 視圖:是一個虛擬表,其內容由查詢定義。同真實的表同樣,視圖包含一系列帶有名稱的列和行數據
  • 視圖有以下特色;
    • 1 視圖的列能夠來自不一樣的表,是表的抽象和邏輯意義上創建的新關係。
    • 2 視圖是由基本表(實表)產生的表(虛表)。
    • 3 視圖的創建和刪除不影響基本表。
    • 4 對視圖內容的更新(添加、刪除和修改)直接影響基本表。
    • 5 當視圖來自多個基本表時,不容許添加和刪除數據。
  • 1 建立視圖
create view 視圖名稱  as sql 查詢語句
  • 2 使用視圖
select * from 視圖名稱;
  • 3 更新視圖
alter view 視圖名稱 AS SQL語句
  • 4 刪除視圖
drop view ren_view;

2 觸發器

  • 觸發器:監視某種狀況,並觸發某種操做。
  • 觸發器建立語法四要素:
    • 1 監視地點(table)
    • 2 監視事件(insert/update/delete)
    • 3 觸發時間(after/before)
    • 4 觸發事件(insert/update/delete)
  • 建立觸發器語法
create trigger triggerName  after/before  insert/update/delete
     on 表名 for each row #這句話是固定的
 begin
     #須要執行的sql語句
 end
注意1:after/before: 只能選一個 ,after 表示 後置觸發, before 表示前置觸發
注意2:insert/update/delete:只能選一個
  • 建立兩張表
#商品表

create table goods(

  id int primary key auto_increment,

  name varchar(20),

  num int

);

#訂單表

create table order_table(

    oid int primary key auto_increment,

    gid int,

    much int

);
  • 添加3條商品數據
insert into goods(name,num) values('商品1',10),('商品2',10),('商品3',10);
  • 若是咱們在沒使用觸發器以前:假設咱們如今賣了3個商品1,咱們須要作兩件事
    • 1 往訂單表插入一條記錄
insert into order_table(gid,much) values(1,3);
- 2 更新商品表商品1的剩餘數量
update goods set num=num-3 where id=1;
  • 建立一個觸發器:
create trigger tg1 after insert on  order_table
for each row
begin    
  update goods set num = num -3 where id = 1;
end
  • 執行
insert into order_table(gid,much) values(1,3);
  • 會發現商品1的數量變爲7了,說明在咱們插入一條訂單的時候,
  • 觸發器自動幫咱們作了更新操做。
  • 但如今會有一個問題,由於咱們觸發器裏面num和id都是寫死的,因此無論咱們買哪一個商品,最終更新的都是商品1的數量。好比:咱們往訂單表再插入一條記錄:
insert into order_table(gid,much) values(2,3);
  • 執行完後會發現商品1的數量變4了,而商品2的數量沒變,這樣顯然不是咱們想要的結果。咱們須要改改咱們以前建立的觸發器。
  • 咱們如何在觸發器引用行的值,也就是說咱們要獲得咱們新插入的訂單記錄中的gid或much的值。
  • 對於insert而言,新插入的行用new來表示,行中的每一列的值用new.列名來表示。
  • 因此如今咱們能夠這樣來改咱們的觸發器:
create trigger tg2 after insert on order_table
for each row
begin
 update goods set num = num-new.much  where id = new.gid;
end
  • 第二個觸發器建立完畢,咱們先把第一個觸發器刪掉
drop trigger tg1;
  • 再來測試一下,插入一條訂單記錄:
insert into order_table(gid,much) values(2,3)
  • 執行完發現商品2的數量變爲7了,如今就對了。html

  • 如今還存在兩種狀況:
  • 1 當用戶撤銷一個訂單的時候,咱們這邊直接刪除一個訂單,咱們是否是須要把對應的商品數量再加回去呢?
  • 對於delete而言:本來有一行,後來被刪除,想引用被刪除的這一行,用old來表示舊錶中的值,old.列名能夠引用原(舊)表中的值。
  • 那咱們的觸發器就該這樣寫:前端

create trigger tg3 afert delete  on order_table
for each row
bigen
    update goods set num = num + old.much where id = old.gid;-- (注意這邊的變化)
end
  • 2 當用戶修改一個訂單的數量時,咱們觸發器修改怎麼寫?
create trigger tg4 after update on order_table
for each row
begin
    update goods set num = num+old.much-new.much where id = old.gid;
end

3 存儲過程

  • MySQL數據庫在5.0版本後開始支持存儲過程,那麼什麼是存儲過程呢?怎麼建立、查看和刪除存儲過程呢?存儲過程有什麼優勢?
  • 存儲過程:相似於函數(方法),簡單的說存儲過程是爲了完成某個數據庫中的特定功能而編寫的語句集合,該語句集包括SQL語句(對數據的增刪改查)、條件語句和循環語句等。node

  • 1 查看現有的存儲過程mysql

show procedure status;
  • 2 刪除存儲過程
drop procedure 存儲過程名稱;
  • 3 調用 存儲過程
call 存儲過程名稱(參數入/出類型 參數名 數據類型);
  • 4 建立存儲過程linux

  • 體會封裝sql

#1.體會封裝
create procedure p1 ()
begin
    select * from account;  
end
  • SQL 體會參數
create procedure p2(in i int,out n varchar(50))
begin
 select name into n from account where id = i;
end
 
-- 調用
set @name =null;
CALL p2(1,@name);
select @name;
  • 注意1: mysql中有三種出入參數類型:分別爲:1. in 入參類型 2.out 出參類型 3. inout 出入參類型
  • 注意2: into 關鍵字 能夠 將前面字段的查詢結果 執行 給 into 後面的變量.shell

  • in入參示例數據庫

-- 建立存儲過程 in 入參
create procedure p_in (IN num int )
begin
    select num;
    set num=100;
    select num;
end;

-- 調用
set @num=1;
call p_in(@num);
select @num;
-- 總結: IN 參數只是將變量在存儲過程內部作了修改,並無影響到外部,@num仍爲1。
  • out出參示例
-- 建立存儲過程 out 出參
create procedure p_out (out num int )
begin
    select num;
    set num=100;
    select num;
end;

-- 調用
set @num=1;
call p_out(@num);
select @num;
  • inout出入參示例
-- 建立存儲過程 inout 出入參
create procedure p_inout (inout num int )
begin
    select num;
    set num=100;
    select num;
end;

-- 調用
set @num=1;
call p_inout(@num);
select @num;
  • SQL 體會控制
#3.SQL 體會控制
 create procedure p3(in x int,in c char(1))
 begin
    if c ='d' then
         select * from account where money >x;
   else
         select * from account where money <x;     
  end if;
end
  • 體會循環:計算1-100累加的和,而且返回計算結果.
#4.體會循環:計算1-100累加的和,而且返回計算結果.
create procedure p4(inout n int)
begin
      DECLARE sum int default 0; -- 設置總和變量,而且指定初始值0
      declare i int; -- 聲明變量
      set i = 0;    -- 經過set爲變量設置值
    while i<=n DO  -- 開始循環
            set sum = sum +i;
            set i = i+1;
      end while; -- 結束循環
 
    select sum; -- 提供結果
                     
     set n = sum;--將計算結果提供給 輸出變量 n;
end;
                 
 -- 調用:
 set @n = 100;
 call p4(@n);
 select @n;
  • 存儲過程優勢:
    • 一、存儲過程加強了SQL語言靈活性。
      • 存儲過程可使用控制語句編寫,能夠完成複雜的判斷和較複雜的運算,有很強的靈活性;
    • 二、減小網絡流量,下降了網絡負載。
      • 存儲過程在服務器端建立成功後,只須要調用該存儲過程便可,而傳統的作法是每次都將大量的SQL語句經過網絡發送至數據庫服務器端而後再執行
    • 三、存儲過程只在創造時進行編譯,之後每次執行存儲過程都不需再從新編譯。
      • 通常SQL語句每執行一次就編譯一次,因此使用存儲過程可提升數據庫執行速度。
  • 存儲過程缺點:
    • 一、擴展功能不方便
    • 二、不便於系統後期維護

4 函數

  • MySQL提供的內建函數:
1、數學函數
    ROUND(x,y)
        返回參數x的四捨五入的有y位小數的值
        
    RAND()
        返回0到1內的隨機值,能夠經過提供一個參數(種子)使RAND()隨機數生成器生成一個指定的值。

2、聚合函數(經常使用於GROUP BY從句的SELECT查詢中)
    AVG(col)返回指定列的平均值
    COUNT(col)返回指定列中非NULL值的個數
    MIN(col)返回指定列的最小值
    MAX(col)返回指定列的最大值
    SUM(col)返回指定列的全部值之和
    GROUP_CONCAT(col) 返回由屬於一組的列值鏈接組合而成的結果    
    
3、字符串函數

    CHAR_LENGTH(str)
        返回值爲字符串str 的長度,長度的單位爲字符。一個多字節字符算做一個單字符。
    CONCAT(str1,str2,...)
        字符串拼接
        若有任何一個參數爲NULL ,則返回值爲 NULL。
    CONCAT_WS(separator,str1,str2,...)
        字符串拼接(自定義鏈接符)
        CONCAT_WS()不會忽略任何空字符串。 (然而會忽略全部的 NULL)。

    FORMAT(X,D)
        將數字X 的格式寫爲'#,###,###.##',以四捨五入的方式保留小數點後 D 位, 並將結果以字符串的形式返回。若  D 爲 0, 則返回結果不帶有小數點,或不含小數部分。
        例如:
            SELECT FORMAT(12332.1,4); 結果爲: '12,332.1000'
    
    INSERT(str,pos,len,newstr)
        在str的指定位置插入字符串
            pos:要替換位置其實位置
            len:替換的長度
            newstr:新字符串
        例如:
            SELECT INSERT('abcd',1,2,'tt'); 結果爲: 'ttcd'
            SELECT INSERT('abcd',1,4,'tt'); 結果爲: 'tt'
        特別的:
            若是pos超過原字符串長度,則返回原字符串
            若是len超過原字符串長度,則由新字符串徹底替換
    
    INSTR(str,substr)
        返回字符串 str 中子字符串的第一個出現位置。

    LEFT(str,len)
        返回字符串str 從開始的len位置的子序列字符。
        例如:
            SELECT INSTR('abc','c'); 結果爲: 3
            SELECT INSTR('abc','d'); 結果爲: 0
            
    LOWER(str)
        變小寫

    UPPER(str)
        變大寫
   
    REVERSE(str)
        返回字符串 str ,順序和字符順序相反。
        例如:
            SELECT REVERSE('1234567') 結果爲:7654321
            
    SUBSTRING(str,pos) , SUBSTRING(str FROM pos) SUBSTRING(str,pos,len) , SUBSTRING(str FROM pos FOR len)
        不帶有len 參數的格式從字符串str返回一個子字符串,起始於位置 pos。帶有len參數的格式從字符串str返回一個長度同len字符相同的子字符串,起始於位置 pos。 使用 FROM的格式爲標準 SQL 語法。也可能對pos使用一個負值。倘若這樣,則子字符串的位置起始於字符串結尾的pos 字符,而不是字符串的開頭位置。在如下格式的函數中能夠對pos 使用一個負值。

        mysql> SELECT SUBSTRING('Quadratically',5); -- 從第5位開始截取
            -> 'ratically'

        mysql> SELECT SUBSTRING('foobarbar' FROM 4); -- 從第4位開始截取
            -> 'barbar'

        mysql> SELECT SUBSTRING('Quadratically',5,6); --從第5位開始截取,截取6個長度
            -> 'ratica'

        mysql> SELECT SUBSTRING('Sakila', -3);    -- 從倒數第3位開始截取
            -> 'ila'

        mysql> SELECT SUBSTRING('Sakila', -5, 3); -- 從倒數第5位開始截取,截取3個長度
            -> 'aki'
            
4、日期和時間函數
    CURDATE()或CURRENT_DATE() 返回當前的日期
    CURTIME()或CURRENT_TIME() 返回當前的時間
    DAYOFWEEK(date)   返回date所表明的一星期中的第幾天(1~7)
    DAYOFMONTH(date)  返回date是一個月的第幾天(1~31)
    DAYOFYEAR(date)   返回date是一年的第幾天(1~366)
    DAYNAME(date)   返回date的星期名,如:SELECT DAYNAME(CURRENT_DATE);
    FROM_UNIXTIME(ts,fmt)  根據指定的fmt格式,格式化UNIX時間戳ts
    HOUR(time)   返回time的小時值(0~23)
    MINUTE(time)   返回time的分鐘值(0~59)
    MONTH(date)   返回date的月份值(1~12)
    MONTHNAME(date)   返回date的月份名,如:SELECT MONTHNAME(CURRENT_DATE);
    NOW()    返回當前的日期和時間
    QUARTER(date)   返回date在一年中的季度(1~4),如SELECT QUARTER(CURRENT_DATE);
    WEEK(date)   返回日期date爲一年中第幾周(0~53)
    YEAR(date)   返回日期date的年份(1000~9999)
    
    重點:
    DATE_FORMAT(date,format) 根據format字符串格式化date值

       mysql> SELECT DATE_FORMAT('2009-10-04 22:23:00', '%W %M %Y');
        -> 'Sunday October 2009'
       mysql> SELECT DATE_FORMAT('2007-10-04 22:23:00', '%H:%i:%s');
        -> '22:23:00'
       mysql> SELECT DATE_FORMAT('1900-10-04 22:23:00',
        ->                 '%D %y %a %d %m %b %j');
        -> '4th 00 Thu 04 10 Oct 277'
       mysql> SELECT DATE_FORMAT('1997-10-04 22:23:00',
        ->                 '%H %k %I %r %T %S %w');
        -> '22 22 10 10:23:00 PM 22:23:00 00 6'
       mysql> SELECT DATE_FORMAT('1999-01-01', '%X %V');
        -> '1998 52'
       mysql> SELECT DATE_FORMAT('2006-06-00', '%d');
        -> '00'
        
5、加密函數
    MD5()    
        計算字符串str的MD5校驗和
        例如:
            SELECT MD5('1234') 結果爲:81dc9bdb52d04dc20036dbd8313ed055
    PASSWORD(str)   
        返回字符串str的加密版本,這個加密過程是不可逆轉的
        例如:
            SELECT PASSWORD('1234') 結果爲:*A4B6157319038724E3560894F7F932C8886EBFCF
        
6、控制流函數            
    CASE WHEN[test1] THEN [result1]...ELSE [default] END
        若是testN是真,則返回resultN,不然返回default
    CASE [test] WHEN[val1] THEN [result]...ELSE [default]END  
        若是test和valN相等,則返回resultN,不然返回default

    IF(test,t,f)   
        若是test是真,返回t;不然返回f

    IFNULL(arg1,arg2) 
        若是arg1不是空,返回arg1,不然返回arg2
        例如:
            SELECT IFNULL('bbb','abc'); 結果爲: bbb
            SELECT IFNULL(null,'abc');  結果爲: abc

    NULLIF(arg1,arg2) 
        若是arg1=arg2返回NULL;不然返回arg1
        例如:
            SELECT NULLIF('bbb','bbb');結果爲: null
            SELECT NULLIF('aaa','bbb');結果爲: aaa
  • 更多內置函數:https://dev.mysql.com/doc/refman/5.7/en/functions.htmlvim

  • 1 自定義函數windows

CREATE FUNCTION fun1(i1 int,i2 int)
 
RETURNS INT //設置返回類型
 
BEGIN
    DECLARE sum int default 0;
    set sum = i1+i2;
    RETURN(sum); //返回結果
end
  • 2 調用自定義函數
#直接調用自定義函數
select fun1(1,5);
 
#在sql語句中使用自定義函數
select fun1(參數1,參數2),name from 表名
  • 3 刪除自定義函數
DROP FUNCTION fun_name;
  • 4 函數與存儲過程的區別:
函數 過程
通常用於計算數據 完成特定的任務
聲明爲FUNCTION 聲明爲PROCEDURE
須要描述類型,且PL/SQL 塊中至少有一個有效的 RETURN 語句 無返回類型,可經過OUT、IN OUT 參數返回多個值
不能獨立運行,必須做爲表達式一部分 可做爲一個獨立的 PL/SQL 語句運行
在 DML和DQL中可調用函數 在DML和DQL中不可調用過程

5 事物

5.1 什麼是事務

  • 一組sql語句批量執行,要麼所有執行成功,要麼所有執行失敗

5.2 爲何出現這種技術

  • 爲何要使用事務這個技術呢? 如今的不少軟件都是多用戶,多程序,多線程的,對同一個表可能同時有不少人在用,爲保持數據的一致性,因此提出了事務的概念。這樣很抽象,舉個例子:
  • A 給B 要劃錢,A 的帳戶-1000元, B 的帳戶就要+1000元,這兩個update 語句必須做爲一個總體來執行,否則A 扣錢了,B 沒有加錢這種狀況很難處理。

5.3 事物的特性 

  • 80年代中國人結婚四大件:手錶、自行車、縫紉機、收音機(三轉一響)。要把事務娶回家一樣須要四大件,因此事務很刻薄(ACID),四大件清單:原子性(Atom)、一致性(Consistent)、隔離性(Isolate)、持久性(Durable)。ACID就是數據庫事務正確執行的四個特性的縮寫。
    • 原子性:要麼不談,要談就要結婚!
      • 對於其數據修改,要麼全都執行,要麼全都不執行。
    • 一致性:戀愛時,什麼方式愛我;結婚後還得什麼方式愛我;
      • 數據庫原來有什麼樣的約束,事務執行以後還須要存在這樣的約束,全部規則都必須應用於事務的修改,以保持全部數據的完整性。
    • 隔離性:鬧完洞房後,是倆人的私事。
      • 一個事務不能知道另一個事務的執行狀況(中間狀態)
    • 持久性:一旦領告終婚證,沒法後悔。
      • 即便出現致命的系統故障也將一直保持。不要告訴我係統說commit成功了,回頭電話告訴我,服務器機房斷電了,個人事務涉及到的數據修改可能沒有進入數據庫。
  • 另外須要注意:
    • 在 MySQL 中只有使用了 Innodb 數據庫引擎的數據庫或表才支持事務。
    • 事務處理能夠用來維護數據庫的完整性,保證成批的 SQL 語句要麼所有執行,要麼所有不執行。
    • 事務用來管理 insert,update,delete 語句

5.4 事務控制語句

  • BEGIN 或 START TRANSACTION;顯式地開啓一個事務;
  • COMMIT;也可使用COMMIT WORK,不過兩者是等價的。COMMIT會提交事務,並使已對數據庫進行的全部修改稱爲永久性的;
  • ROLLBACK;有可使用ROLLBACK WORK,不過兩者是等價的。回滾會結束用戶的事務,並撤銷正在進行的全部未提交的修改;
  • SAVEPOINT : 保存點,能夠把一個事物分割成幾部分.在執行ROLLBACK 時 能夠指定在什麼位置上進行回滾操做.
  • 注意: SET AUTOCOMMIT=0 ;禁止自動提交 和 SET AUTOCOMMIT=1 開啓自動提交.

5.5 例子: 魯班轉帳給后羿

  • 1 建立表
create table account(
    id int(50) not null auto_increment primary key,
    name VARCHAR(50) not null,
    money DOUBLE(10,2) not NULL
);
  • 2 插入數據
insert into account (id,name,money) values(1,'魯班',250),(2,'后羿',5000);
  • 3 執行轉帳
start transaction; -- 開啓事物
 --  執行sql語句操做
 update account set money = money - 500 where id =1;  
 update account set money = money+500 where id = 2;
 
commit;  -- 手動提交事物
rollback; -- 回滾事物
 
--  查看結果
select * from account;
  • 4 保存點使用
START TRANSACTION ;
 
insert into account (name,money) values('李元芳',1000);
 
SAVEPOINT s1; -- 設置保存點
 
insert into account (name,money) values('張桂枝',1500);
 
ROLLBACK to s1; -- 事物回滾到保存點<br>COMMIT; --提交事物

6 數據庫鎖

  • 需求: 有一個帳戶,兩我的在同一時間要對此帳戶操做,A要對帳戶充值100塊,B要從帳戶中取出100塊.操做前都要先看一下帳戶的 餘額而後再操做.
-- 窗口1 用戶進行充值

-- 充值前 先查看餘額
set @m=0;

SELECT money into @m from account where id = 1;

select @m;

-- 看到餘額後 充值100 塊
update account set money = @m + 100 where id = 1;

SELECT * from account;

--------------------------------------------------------------
-- 窗口2 用戶進行取款

-- 取款前 先查看餘額
set @m=0;

SELECT money into @m from account where id = 1;

select @m;

-- 看到餘額後 取款100 塊
update account set money = @m - 100 where id = 1;

SELECT * from account;

6.1 鎖的基本概念

  • 當併發事務同時訪問一個資源時,有可能致使數據不一致,所以須要一種機制來將數據訪問順序化,以保證數據庫數據的一致性。

6.2 鎖的基本類型

  • 多個事務同時讀取一個對象的時候,是不會有衝突的。同時讀和寫,或者同時寫纔會產生衝突。所以爲了提升數據庫的併發性能,一般會定義兩種鎖:共享鎖和排它鎖。
  • 1 共享鎖(Shared Lock,也叫S鎖)
    • 共享鎖(S)表示對數據進行讀操做。所以多個事務能夠同時爲一個對象加共享鎖。(若是試衣間的門還沒被鎖上,顧客都可以同時進去參觀)
  • 2 排他鎖(Exclusive Lock,也叫X鎖)
    • 排他鎖(X)表示對數據進行寫操做。若是一個事務對 對象加了排他鎖,其餘事務就不能再給它加任何鎖了。(某個顧客把試衣間從裏面反鎖了,其餘顧客想要使用這個試衣間,就只有等待鎖從裏面給打開了).

6.3 實際開發中常見的兩種鎖:

  • 1 悲觀鎖 顧名思義
    • 就是很悲觀,每次去拿數據的時候都認爲別人會修改,因此每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會block(阻塞)直到它拿到鎖。傳統的關係型數據庫裏邊就用到了不少這種鎖機制.
  • 注意:要使用悲觀鎖,咱們必須關閉mysql數據庫的自動提交屬性.由於MySQL默認使用autocommit模式,也就是說,當你執行一個更新操做後,MySQL會馬上將結果進行提交。關閉自動提交命令爲:set autocommit=0;
  • 設置完autocommit後,咱們就能夠執行咱們的正常業務了。具體以下:
-- 0.開始事務
start transaction;
 
-- 1.查詢帳戶餘額
set @m = 0; -- 帳戶餘額
select money into @m from account where id = 1 for update;
select @m;
 
-- 2.修改帳戶餘額
update account set money = @m -100 where id = 1;
 
select * FROM account where id = 1;
-- 3. 提交事務
commit;
  • 在另外的查詢頁面執行:
-- 0.開始事務
start transaction;
 
-- 1.查詢帳戶餘額
set @m = 0; -- 帳戶餘額
select money into @m from account where id = 1 for update;
select @m;
 
-- 2.修改帳戶餘額
update account set money = @m +100 where id = 1;
 
select * FROM account where id = 1;
-- 3. 提交事務
commit;
  • 會發現當前查詢會進入到等待狀態,不會顯示出數據,當上面的sql執行完畢提交事物後,當前sql纔會顯示結果.
  • 注意1:在使用悲觀鎖時,若是表中沒有指定主鍵,則會進行鎖表操做.
  • 注意2: 悲觀鎖的確保了數據的安全性,在數據被操做的時候鎖定數據不被訪問,可是這樣會帶來很大的性能問題。所以悲觀鎖在實際開發中使用是相對比較少的。 

  • 2 樂觀鎖, 顧名思義
    • 就是很樂觀,每次去拿數據的時候都認爲別人不會修改,因此不會上鎖,可是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可使用版本號等機制。 
  • 使用樂觀鎖的兩種方式:
    • 1 使用數據版本(Version)記錄機制實現,這是樂觀鎖最經常使用的一種實現 方式。何謂數據版本?即爲數據增長一個版本標識,通常是經過爲數據庫表增長一個數字類型的 「version」 字段來實現。當讀取數據時,將version字段的值一同讀出,數據每更新一次,對此version值加一。當咱們提交更新的時候,判斷數據庫表對應記錄 的當前版本信息與第一次取出來的version值進行比對,若是數據庫表當前版本號與第一次取出來的version值相等,則予以更新,不然認爲是過時數 據。
-- 1.查詢帳戶餘額
set @m = 0; -- 帳戶餘額
select money into @m from account where id = 1 ;
select @m;
-- 2.查詢版本號
set @version = 0; -- 版本號
select version into @version from account where id = 1 ;
select @version;
 
-- 3.修改帳戶餘額
update account set money = @m -100,version=version+1 where id = 1 and version = @version;
 
select * FROM account where id = 1;
- 2 樂觀鎖定的第二種實現方式和第一種差很少,一樣是在須要樂觀鎖控制的table中增長一個字段,名稱無所謂,字段類型使用時間戳 (datatime), 和上面的version相似,也是在更新提交的時候檢查當前數據庫中數據的時間戳和本身更新前取到的時間戳進行對比,若是一致則OK,不然就是版本衝突。
  • 悲觀鎖與樂觀鎖的優缺點:
  • 兩種鎖各有其有點缺點,不能單純的講哪一個更好.
    • 樂觀鎖適用於寫入比較少的狀況下,即衝突真的不多發生的時候,這樣能夠省去了鎖的開銷,加大了系統的整個吞吐量。
    • 但若是常常產生衝突,上層應用會不斷的進行重試操做,這樣反卻是下降了性能,因此這種狀況下用悲觀鎖就比較合適.

7 數據庫備份

  • 咱們試着想想, 在生產環境中什麼最重要?若是咱們服務器的硬件壞了能夠維修或者換新, 軟件問題能夠修復或從新安裝, 可是若是數據沒了呢?這多是最恐怖的事情了吧, 我感受在生產環境中應該沒有什麼比數據跟更爲重要. 那麼咱們該如何保證數據不丟失、或者丟失後能夠快速恢復呢?只要看完這篇, 你們應該就能對MySQL中實現數據備份和恢復能有必定的瞭解。

7.1 爲何須要備份數據?

  • 在生產環境中咱們數據庫可能會遭遇各類各樣的不測從而致使數據丟失, 大概分爲如下幾種.
    • 硬件故障
    • 軟件故障
    • 天然災害
    • 黑客攻擊
    • 誤操做 (佔比最大)
  • 因此, 爲了在數據丟失以後可以恢復數據, 咱們就須要按期的備份數據, 備份數據的策略要根據不一樣的應用場景進行定製, 大體有幾個參考數值, 咱們能夠根據這些數值從而定製符合特定環境中的數據備份策略
    • 可以容忍丟失多少數據
    • 恢復數據須要多長時間
    • 須要恢復哪一些數據

7.2 數據的備份類型

  • 數據的備份類型根據其自身的特性主要分爲如下幾組
    • 徹底備份
    • 部分備份
    • 徹底備份指的是備份整個數據集( 即整個數據庫 )、部分備份指的是備份部分數據集(例如: 只備份一個表)
  • 而部分備份又分爲如下兩種
    • 增量備份
    • 差別備份
    • 增量備份指的是備份自上一次備份以來(增量或徹底)以來變化的數據; 特色: 節約空間、還原麻煩
    • 差別備份指的是備份自上一次徹底備份以來變化的數據 特色: 浪費空間、還原比增量備份簡單
  • 示意圖

7.3 MySQL備份數據的方式

  • 在MySQl中咱們備份數據通常有幾種方式
    • 熱備份
    • 溫備份
    • 冷備份
    • 熱備份指的是當數據庫進行備份時, 數據庫的讀寫操做均不是受影響
    • 溫備份指的是當數據庫進行備份時, 數據庫的讀操做能夠執行, 可是不能執行寫操做
    • 冷備份指的是當數據庫進行備份時, 數據庫不能進行讀寫操做, 即數據庫要下線
  • MySQL中進行不一樣方式的備份還要考慮存儲引擎是否支持
    • MyISAM
      • 熱備 ×
      • 溫備 √
      • 冷備 √
    • InnoDB
      • 熱備 √
      • 溫備 √
      • 冷備 √
  • 咱們在考慮完數據在備份時, 數據庫的運行狀態以後還須要考慮對於MySQL數據庫中數據的備份方式
    • 物理備份通常就是經過tar,cp等命令直接打包複製數據庫的數據文件達到備份的效果
    • 邏輯備份通常就是經過特定工具從數據庫中導出數據並另存備份(邏輯備份會丟失數據精度)

7.4 備份須要考慮的問題

  • 定製備份策略前, 咱們還須要考慮一些問題

7.4.1 咱們要備份什麼?

  • 通常狀況下, 咱們須要備份的數據分爲如下幾種
    • 數據
    • 二進制日誌, InnoDB事務日誌
    • 代碼(存儲過程、存儲函數、觸發器、事件調度器)
    • 服務器配置文件
  • 備份工具
  • 這裏咱們列舉出經常使用的幾種備份工具
    • mysqldump : 邏輯備份工具, 適用於全部的存儲引擎, 支持溫備、徹底備份、部分備份、對於InnoDB存儲引擎支持熱備
    • cp, tar 等歸檔複製工具: 物理備份工具, 適用於全部的存儲引擎, 冷備、徹底備份、部分備份
    • lvm2 snapshot: 幾乎熱備, 藉助文件系統管理工具進行備份
    • mysqlhotcopy: 名存實亡的的一個工具, 幾乎冷備, 僅支持MyISAM存儲引擎
    • xtrabackup: 一款很是強大的InnoDB/XtraDB熱備工具, 支持徹底備份、增量備份, 由percona提供

7.5 設計合適的備份策略

  • 針對不一樣的場景下, 咱們應該制定不一樣的備份策略對數據庫進行備份, 通常狀況下, 備份策略通常爲如下三種
    • 直接cp,tar複製數據庫文件
    • mysqldump+複製BIN LOGS
    • lvm2快照+複製BIN LOGS
    • xtrabackup
  • 以上的幾種解決方案分別針對於不一樣的場景
    • 若是數據量較小, 可使用第一種方式, 直接複製數據庫文件
    • 若是數據量還行, 可使用第二種方式, 先使用mysqldump對數據庫進行徹底備份, 而後按期備份BINARY LOG達到增量備份的效果
    • 若是數據量通常, 而又不過度影響業務運行, 可使用第三種方式, 使用lvm2的快照對數據文件進行備份, 然後按期備份BINARY LOG達到增量備份的效果
    • 若是數據量很大, 而又不過度影響業務運行, 可使用第四種方式, 使用xtrabackup進行徹底備份後, 按期使用xtrabackup進行增量備份或差別備份

7.6 實戰演練

7.6.1 使用cp進行備份

  • 咱們這裏使用的是使用yum安裝的mysql-5.1的版本, 使用的數據集爲從網絡上找到的一個員工數據庫
  • 查看數據庫的信息
mysql> SHOW DATABASES;    #查看當前的數據庫, 咱們的數據庫爲employees
+--------------------+
| Database           |
+--------------------+
| information_schema |
| employees          |
| mysql              |
| test               |
+--------------------+
4 rows in set (0.00 sec)

mysql> USE employees;
Database changed
mysql> SHOW TABLES;         #查看當前庫中的表
+---------------------+
| Tables_in_employees |
+---------------------+
| departments         |
| dept_emp            |
| dept_manager        |
| employees           |
| salaries            |
| titles              |
+---------------------+
6 rows in set (0.00 sec)

mysql> SELECT COUNT(*) FROM employees;   #因爲篇幅緣由, 咱們這裏只看一下employees的行數爲300024
+----------+
| COUNT(*) |
+----------+
|   300024 |
+----------+
1 row in set (0.05 sec)
  • 向數據庫施加讀鎖
mysql> FLUSH TABLES WITH READ LOCK;    #向全部表施加讀鎖
Query OK, 0 rows affected (0.00 sec)
  • 備份數據文件
[root@node1 ~]# mkdir /backup   #建立文件夾存放備份數據庫文件
[root@node1 ~]# cp -a /var/lib/mysql/* /backup     #保留權限的拷貝源數據文件
[root@node1 ~]# ls /backup   #查看目錄下的文件
employees  ibdata1  ib_logfile0  ib_logfile1  mysql  mysql.sock  test
  • 模擬數據丟失並恢復
[root@node1 ~]# rm -rf /var/lib/mysql/*    #刪除數據庫的全部文件
[root@node1 ~]# service mysqld restart   #重啓MySQL, 若是是編譯安裝的應該不能啓動, 若是rpm安裝則會從新初始化數據庫


mysql> SHOW DATABASES;    #由於咱們是rpm安裝的, 鏈接到MySQL進行查看, 發現數據丟失了!
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| test               |
+--------------------+
3 rows in set (0.00 sec)

[root@node1 ~]# rm -rf /var/lib/mysql/*    #這一步能夠不作
[root@node1 ~]# cp -a /backup/* /var/lib/mysql/    #將備份的數據文件拷貝回去
[root@node1 ~]# service mysqld restart  #重啓MySQL


#從新鏈接數據並查看

mysql> SHOW DATABASES;    #數據庫已恢復
+--------------------+
| Database           |
+--------------------+
| information_schema |
| employees          |
| mysql              |
| test               |
+--------------------+
4 rows in set (0.00 sec)

mysql> USE employees;      

mysql> SELECT COUNT(*) FROM employees;    #表的行數沒有變化
+----------+
| COUNT(*) |
+----------+
|   300024 |
+----------+
1 row in set (0.06 sec)


##完成

7.6.2 使用mysqldump+複製BINARY LOG備份

  • 咱們這裏使用的是使用yum安裝的mysql-5.1的版本, 使用的數據集爲從網絡上找到的一個員工數據庫
  • 咱們經過mysqldump進行一次徹底備份, 再修改表中的數據, 而後再經過binary log進行恢復 二進制日誌須要在mysql配置文件中添加 log_bin=on 開啓
  • mysqldump命令介紹
    • mysqldump是一個客戶端的邏輯備份工具, 能夠生成一個重現建立原始數據庫和表的SQL語句, 能夠支持全部的存儲引擎, 對於InnoDB支持熱備
  • 官網介紹:https://dev.mysql.com/doc/refman/5.7/en/mysqldump.html
#基本語法格式

shell> mysqldump [options] db_name [tbl_name ...]    恢復須要手動CRATE DATABASES
shell> mysqldump [options] --databases db_name ...   恢復不須要手動建立數據庫
shell> mysqldump [options] --all-databases           恢復不須要手動建立數據庫


其餘選項:
     -E, --events: 備份事件調度器
     -R, --routines: 備份存儲過程和存儲函數
     --triggers: 備份表的觸發器; --skip-triggers 
     --master-date[=value]  
         1: 記錄爲CHANGE MASTER TO 語句、語句不被註釋
         2: 記錄爲註釋的CHANGE MASTER TO語句
         基於二進制還原只能全庫還原

     --flush-logs: 日誌滾動
         鎖定表完成後執行日誌滾動
  • 查看數據庫的信息
mysql> SHOW DATABASES;    #查看當前的數據庫, 咱們的數據庫爲employees
+--------------------+
| Database           |
+--------------------+
| information_schema |
| employees          |
| mysql              |
| test               |
+--------------------+
4 rows in set (0.00 sec)

mysql> USE employees;
Database changed
mysql> SHOW TABLES;         #查看當前庫中的表
+---------------------+
| Tables_in_employees |
+---------------------+
| departments         |
| dept_emp            |
| dept_manager        |
| employees           |
| salaries            |
| titles              |
+---------------------+
6 rows in set (0.00 sec)

mysql> SELECT COUNT(*) FROM employees;   #因爲篇幅緣由, 咱們這裏只看一下employees的行數爲300024
+----------+
| COUNT(*) |
+----------+
|   300024 |
+----------+
1 row in set (0.05 sec)
  • 使用mysqldump備份數據庫
[root@node1 ~]# mysql -uroot -p -e 'SHOW MASTER STATUS'   #查看當前二進制文件的狀態, 並記錄下position的數字
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000003 |      106 |              |                  |
+------------------+----------+--------------+------------------+

[root@node1 ~]# mysqldump --all-databases --lock-all-tables  > backup.sql   #備份數據庫到backup.sql文件中

mysql> CREATE DATABASE TEST1;   #建立一個數據庫
Query OK, 1 row affected (0.00 sec)

mysql> SHOW MASTER STATUS;   #記下如今的position
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000003 |      191 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

[root@node1 ~]# cp /var/lib/mysql/mysql-bin.000003 /root  #備份二進制文件
[root@node1 ~]# service mysqld stop   #中止MySQL
[root@node1 ~]# rm -rf /var/lib/mysql/*   #刪除全部的數據文件
[root@node1 ~]# service mysqld start    #啓動MySQL, 若是是編譯安裝的應該不能啓動(需從新初始化), 若是rpm安裝則會從新初始化數據庫


mysql> SHOW DATABASES;   #查看數據庫, 數據丟失!
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| test               |
+--------------------+
3 rows in set (0.00 sec)

mysql> SET sql_log_bin=OFF;   #暫時先將二進制日誌關閉  
Query OK, 0 rows affected (0.00 sec)


mysql> source backup.sql  #恢復數據,所需時間根據數據庫時間大小而定

mysql> SET sql_log_bin=ON; 開啓二進制日誌

mysql> SHOW DATABASES;   #數據庫恢復, 可是缺乏TEST1
+--------------------+
| Database           |
+--------------------+
| information_schema |
| employees          |
| mysql              |
| test               |
+--------------------+
4 rows in set (0.00 sec)

[root@node1 ~]# mysqlbinlog --start-position=106 --stop-position=191 mysql-bin.000003 | mysql employees #經過二進制日誌增量恢復數據

mysql> SHOW DATABASES;    #如今TEST1出現了!
+--------------------+
| Database           |
+--------------------+
| information_schema |
| TEST1              |
| employees          |
| mysql              |
| test               |
+--------------------+
5 rows in set (0.00 sec)



#完成

7.6.3 使用lvm2快照備份數據

  • 作實驗以前咱們先回顧一下lvm2-snapshot的知識
  • LVM快照簡單來講就是將所快照源分區一個時間點全部文件的元數據進行保存,若是源文件沒有改變,那麼訪問快照卷的相應文件則直接指向源分區的源文件,若是源文件發生改變,則快照卷中與之對應的文件不會發生改變。快照卷主要用於輔助備份文件。
  • 部署lvm環境
添加硬盤; 這裏咱們直接實現SCSI硬盤的熱插拔, 首先在虛擬機中添加一塊硬盤, 不重啓

[root@node1 ~]# ls /dev/sd*   #只有如下幾塊硬盤, 可是咱們不重啓可讓系統識別新添加的硬盤
/dev/sda  /dev/sda1  /dev/sda2

[root@node1 ~]# echo '- - -' > /sys/class/scsi_host/host0/scan 
[root@node1 ~]# echo '- - -' > /sys/class/scsi_host/host1/scan 
[root@node1 ~]# echo '- - -' > /sys/class/scsi_host/host2/scan 

[root@node1 ~]# ls /dev/sd*    #看!sdb識別出來了
/dev/sda  /dev/sda1  /dev/sda2  /dev/sdb


[root@node1 ~]# fdisk /dev/sdb   #分區
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0xd353d192.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

WARNING: DOS-compatible mode is deprecated. It's strongly recommended to
         switch off the mode (command 'c') and change display units to
         sectors (command 'u').

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-2610, default 1): 
Using default value 1
Last cylinder, +cylinders or +size{K,M,G} (1-2610, default 2610): +15G

Command (m for help): t
Selected partition 1
Hex code (type L to list codes): 8e
Changed system type of partition 1 to 8e (Linux LVM)

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.
You have new mail in /var/spool/mail/root
[root@node1 ~]# partx -a /dev/sdb
BLKPG: Device or resource busy
error adding partition 1

##建立邏輯卷
[root@node1 ~]# pvcreate /dev/sdb1
  Physical volume "/dev/sdb1" successfully created
[root@node1 ~]# vgcreate myvg /dev/sdb1 
  Volume group "myvg" successfully created
[root@node1 ~]# lvcreate -n mydata -L 5G myvg 
  Logical volume "mydata" created.

[root@node1 ~]# mkfs.ext4 /dev/mapper/myvg-mydata   #格式化
[root@node1 ~]# mkdir /lvm_data
[root@node1 ~]# mount /dev/mapper/myvg-mydata /lvm_data  #掛載到/lvm_data


[root@node1 ~]# vim /etc/my.cnf    #修改mysql配置文件的datadir以下

datadir=/lvm_data

[root@node1 ~]# service mysqld restart  #重啓MySQL

####從新導入employees數據庫########略過####
  • 查看數據庫的信息
mysql> SHOW DATABASES;    #查看當前的數據庫, 咱們的數據庫爲employees
+--------------------+
| Database           |
+--------------------+
| information_schema |
| employees          |
| mysql              |
| test               |
+--------------------+
4 rows in set (0.00 sec)

mysql> USE employees;
Database changed
mysql> SHOW TABLES;         #查看當前庫中的表
+---------------------+
| Tables_in_employees |
+---------------------+
| departments         |
| dept_emp            |
| dept_manager        |
| employees           |
| salaries            |
| titles              |
+---------------------+
6 rows in set (0.00 sec)

mysql> SELECT COUNT(*) FROM employees;   #因爲篇幅緣由, 咱們這裏只看一下employees的行數爲300024
+----------+
| COUNT(*) |
+----------+
|   300024 |
+----------+
1 row in set (0.05 sec)
  • 建立快照卷並備份
mysql> FLUSH TABLES WITH READ LOCK;     #鎖定全部表
Query OK, 0 rows affected (0.00 sec)

[root@node1 lvm_data]# lvcreate -L 1G -n mydata-snap -p r -s /dev/mapper/myvg-mydata   #建立快照卷
  Logical volume "mydata-snap" created.

mysql> UNLOCK TABLES;  #解鎖全部表
Query OK, 0 rows affected (0.00 sec)

[root@node1 lvm_data]# mkdir /lvm_snap  #建立文件夾
[root@node1 lvm_data]# mount /dev/myvg/mydata-snap /lvm_snap/  #掛載snap
mount: block device /dev/mapper/myvg-mydata--snap is write-protected, mounting read-only

[root@node1 lvm_data]# cd /lvm_snap/
[root@node1 lvm_snap]# ls
employees  ibdata1  ib_logfile0  ib_logfile1  mysql  mysql-bin.000001  mysql-bin.000002  mysql-bin.000003  mysql-bin.index  test
[root@node1 lvm_snap]# tar cf /tmp/mysqlback.tar *  #打包文件到/tmp/mysqlback.tar

[root@node1 ~]# umount /lvm_snap/  #卸載snap
[root@node1 ~]# lvremove myvg mydata-snap  #刪除snap
  • 恢復數據
[root@node1 lvm_snap]# rm -rf /lvm_data/*
[root@node1 ~]# service mysqld start    #啓動MySQL, 若是是編譯安裝的應該不能啓動(需從新初始化), 若是rpm安裝則會從新初始化數據庫


mysql> SHOW DATABASES;   #查看數據庫, 數據丟失!
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| test               |
+--------------------+
3 rows in set (0.00 sec)

[root@node1 ~]# cd /lvm_data/
[root@node1 lvm_data]# rm -rf * #刪除全部文件
[root@node1 lvm_data]# tar xf /tmp/mysqlback.tar     #解壓備份數據庫到此文件夾 
[root@node1 lvm_data]# ls  #查看當前的文件
employees  ibdata1  ib_logfile0  ib_logfile1  mysql  mysql-bin.000001  mysql-bin.000002  mysql-bin.000003  mysql-bin.index  test

mysql> SHOW DATABASES;  #數據恢復了
+--------------------+
| Database           |
+--------------------+
| information_schema |
| employees          |
| mysql              |
| test               |
+--------------------+
4 rows in set (0.00 sec)


##完成

7.6.4 使用Xtrabackup備份

  • 爲了更好地演示, 咱們此次使用mariadb-5.5的版本, 使用xtrabackup使用InnoDB可以發揮其最大功效, 而且InnoDB的每一張表必須使用單獨的表空間, 咱們須要在配置文件中添加 innodb_file_per_table = ON 來開啓
  • 下載安裝xtrabackup
咱們這裏經過wget percona官方的rpm包進行安裝
[root@node1 ~]# wget https://www.percona.com/downloads/XtraBackup/Percona-XtraBackup-2.3.4/binary/redhat/6/x86_64/percona-xtrabackup-2.3.4-1.el6.x86_64.rpm   
[root@node1 ~]# yum localinstall percona-xtrabackup-2.3.4-1.el6.x86_64.rpm   #須要EPEL源
  • xtrabackup介紹
    • Xtrabackup是由percona提供的mysql數據庫備份工具,據官方介紹,這也是世界上唯一一款開源的可以對innodb和xtradb數據庫進行熱備的工具。特色:
      • 備份過程快速、可靠;
      • 備份過程不會打斷正在執行的事務;
      • 可以基於壓縮等功能節約磁盤空間和流量;
      • 自動實現備份檢驗;
      • 還原速度快;
  • xtrabackup實現徹底備份
    • 咱們這裏使用xtrabackup的前端配置工具innobackupex來實現對數據庫的徹底備份
    • 使用innobackupex備份時, 會調用xtrabackup備份全部的InnoDB表, 複製全部關於表結構定義的相關文件(.frm)、以及MyISAM、MERGE、CSV和ARCHIVE表的相關文件, 同時還會備份觸發器和數據庫配置文件信息相關的文件, 這些文件會被保存至一個以時間命名的目錄.
  • 備份過程
[root@node1 ~]# mkdir /extrabackup  #建立備份目錄
[root@node1 ~]# innobackupex --user=root /extrabackup/ #備份數據
###################提示complete表示成功*********************

[root@node1 ~]# ls /extrabackup/  #看到備份目錄
2016-04-27_07-30-48
  • 通常狀況, 備份完成後, 數據不能用於恢復操做, 由於備份的數據中可能會包含還沒有提交的事務或已經提交但還沒有同步至數據文件中的事務。所以, 此時的數據文件仍不一致, 因此咱們須要」準備」一個徹底備份
[root@node1 ~]# innobackupex --apply-log /extrabackup/2016-04-27_07-30-48/  #指定備份文件的目錄

#通常狀況下下面三行結尾表明成功*****************
InnoDB: Starting shutdown...
InnoDB: Shutdown completed; log sequence number 369661462
160427 07:40:11 completed OK!

[root@node1 ~]# cd /extrabackup/2016-04-27_07-30-48/
[root@node1 2016-04-27_07-30-48]# ls -hl  #查看備份文件
total 31M
-rw-r----- 1 root root  386 Apr 27 07:30 backup-my.cnf
drwx------ 2 root root 4.0K Apr 27 07:30 employees
-rw-r----- 1 root root  18M Apr 27 07:40 ibdata1
-rw-r--r-- 1 root root 5.0M Apr 27 07:40 ib_logfile0
-rw-r--r-- 1 root root 5.0M Apr 27 07:40 ib_logfile1
drwx------ 2 root root 4.0K Apr 27 07:30 mysql
drwx------ 2 root root 4.0K Apr 27 07:30 performance_schema
drwx------ 2 root root 4.0K Apr 27 07:30 test
-rw-r----- 1 root root   27 Apr 27 07:30 xtrabackup_binlog_info
-rw-r--r-- 1 root root   29 Apr 27 07:40 xtrabackup_binlog_pos_innodb
-rw-r----- 1 root root  117 Apr 27 07:40 xtrabackup_checkpoints
-rw-r----- 1 root root  470 Apr 27 07:30 xtrabackup_info
-rw-r----- 1 root root 2.0M Apr 27 07:40 xtrabackup_logfile
  • 恢復數據
[root@node1 ~]# rm -rf /data/*   #刪除數據文件

***不用啓動數據庫也能夠還原*************

[root@node1 ~]# innobackupex --copy-back /extrabackup/2016-04-27_07-30-48/   #恢復數據, 記清使用方法

#########咱們這裏是編譯安裝的mariadb因此須要作一些操做##########
[root@node1 data]# killall mysqld

[root@node1 ~]# chown -R mysql:mysql ./* 
[root@node1 ~]# ll /data/      #數據恢復
total 28704
-rw-rw---- 1 mysql mysql    16384 Apr 27 07:43 aria_log.00000001
-rw-rw---- 1 mysql mysql       52 Apr 27 07:43 aria_log_control
-rw-rw---- 1 mysql mysql 18874368 Apr 27 07:43 ibdata1
-rw-rw---- 1 mysql mysql  5242880 Apr 27 07:43 ib_logfile0
-rw-rw---- 1 mysql mysql  5242880 Apr 27 07:43 ib_logfile1
-rw-rw---- 1 mysql mysql      264 Apr 27 07:43 mysql-bin.000001
-rw-rw---- 1 mysql mysql       19 Apr 27 07:43 mysql-bin.index
-rw-r----- 1 mysql mysql     2166 Apr 27 07:43 node1.anyisalin.com.err


[root@node1 data]# service mysqld restart
MySQL server PID file could not be found!                  [FAILED]
Starting MySQL..                                           [  OK  ]

MariaDB [(none)]> SHOW DATABASES;  #查看數據庫, 已經恢復
+--------------------+
| Database           |
+--------------------+
| information_schema |
| employees          |
| mysql              |
| performance_schema |
| test               |
+--------------------+
5 rows in set (0.00 sec
  • 增量備份
#########建立連兩個數據庫以供測試#####################
MariaDB [(none)]> CREATE DATABASE TEST1;
Query OK, 1 row affected (0.00 sec)

MariaDB [(none)]> CREATE DATABASE TEST2;
Query OK, 1 row affected (0.00 sec)

[root@node1 ~]# innobackupex --incremental /extrabackup/ --incremental-basedir=/extrabackup/2016-04-27_07-30-48/ 

[root@node1 ~]# ls /extrabackup/2016-04-27_07-57-22/ #查看備份文件
total 96
-rw-r----- 1 root root   386 Apr 27 07:57 backup-my.cnf
drwx------ 2 root root  4096 Apr 27 07:57 employees
-rw-r----- 1 root root 49152 Apr 27 07:57 ibdata1.delta
-rw-r----- 1 root root    44 Apr 27 07:57 ibdata1.meta
drwx------ 2 root root  4096 Apr 27 07:57 mysql
drwx------ 2 root root  4096 Apr 27 07:57 performance_schema
drwx------ 2 root root  4096 Apr 27 07:57 test
drwx------ 2 root root  4096 Apr 27 07:57 TEST1
drwx------ 2 root root  4096 Apr 27 07:57 TEST2
-rw-r----- 1 root root    21 Apr 27 07:57 xtrabackup_binlog_info
-rw-r----- 1 root root   123 Apr 27 07:57 xtrabackup_checkpoints
-rw-r----- 1 root root   530 Apr 27 07:57 xtrabackup_info
-rw-r----- 1 root root  2560 Apr 27 07:57 xtrabackup_logfile
  • BASEDIR指的是徹底備份所在的目錄,此命令執行結束後,innobackupex命令會在/extrabackup目錄中建立一個新的以時間命名的目錄以存放全部的增量備份數據。另外,在執行過增量備份以後再一次進行增量備份時,其--incremental-basedir應該指向上一次的增量備份所在的目錄。
  • 須要注意的是,增量備份僅能應用於InnoDB或XtraDB表,對於MyISAM表而言,執行增量備份時其實進行的是徹底備份。
  • 整理增量備份
[root@node1 ~]# innobackupex --apply-log --redo-only /extrabackup/2016-04-27_07-30-48/
[root@node1 ~]# innobackupex --apply-log --redo-only /extrabackup/2016-04-27_07-30-48/ --incremental-dir=/extrabackup/2016-04-27_07-5
7-22/
  • 恢復數據
[root@node1 ~]# rm -rf /data/*   #刪除數據

[root@node1 ~]# innobackupex --copy-back /extrabackup/2016-04-27_07-30-48/     #整理增量備份以後能夠直接經過全量備份還原

[root@node1 ~]# chown -R mysql.mysql /data/
[root@node1 ~]# ls /data/ -l
total 28732
-rw-rw---- 1 mysql mysql     8192 Apr 27 08:05 aria_log.00000001
-rw-rw---- 1 mysql mysql       52 Apr 27 08:05 aria_log_control
drwx------ 2 mysql mysql     4096 Apr 27 08:05 employees
-rw-r----- 1 mysql mysql 18874368 Apr 27 08:05 ibdata1
-rw-r----- 1 mysql mysql  5242880 Apr 27 08:05 ib_logfile0
-rw-r----- 1 mysql mysql  5242880 Apr 27 08:05 ib_logfile1
drwx------ 2 mysql mysql     4096 Apr 27 08:05 mysql
-rw-rw---- 1 mysql mysql      245 Apr 27 08:05 mysql-bin.000001
-rw-rw---- 1 mysql mysql       19 Apr 27 08:05 mysql-bin.index
-rw-r----- 1 mysql mysql     1812 Apr 27 08:05 node1.anyisalin.com.err
-rw-rw---- 1 mysql mysql        5 Apr 27 08:05 node1.anyisalin.com.pid
drwx------ 2 mysql mysql     4096 Apr 27 08:05 performance_schema
drwx------ 2 mysql mysql     4096 Apr 27 08:05 test
drwx------ 2 mysql mysql     4096 Apr 27 08:05 TEST1
drwx------ 2 mysql mysql     4096 Apr 27 08:05 TEST2
-rw-r----- 1 mysql mysql       29 Apr 27 08:05 xtrabackup_binlog_pos_innodb
-rw-r----- 1 mysql mysql      530 Apr 27 08:05 xtrabackup_info

MariaDB [(none)]> SHOW DATABASES;  #數據還原
+--------------------+
| Database           |
+--------------------+
| information_schema |
| TEST1              |
| TEST2              |
| employees          |
| mysql              |
| performance_schema |
| test               |
+--------------------+
7 rows in set (0.00 sec)

#關於xtrabackup還有不少強大的功能沒有敘述、有興趣能夠去看官方文檔

7.7 總結

備份方法 備份速度 恢復速度 便捷性 功能 通常用於
cp 通常、靈活性低 很弱 少許數據備份
mysqldump 通常、可無視存儲引擎的差別 通常 中小型數據量的備份
lvm2快照 通常、支持幾乎熱備、速度快 通常 中小型數據量的備份
xtrabackup 較快 較快 實現innodb熱備、對存儲引擎有要求 強大 較大規模的備份
  • 其實咱們還能夠經過Master-Slave Replication 進行備份

7.8 mysqldump 參數說明

--all-databases  , -A
導出所有數據庫。
mysqldump  -uroot -p --all-databases
--all-tablespaces  , -Y
導出所有表空間。
mysqldump  -uroot -p --all-databases --all-tablespaces
--no-tablespaces  , -y
不導出任何表空間信息。
mysqldump  -uroot -p --all-databases --no-tablespaces
--add-drop-database
每一個數據庫建立以前添加drop數據庫語句。
mysqldump  -uroot -p --all-databases --add-drop-database
--add-drop-table
每一個數據表建立以前添加drop數據表語句。(默認爲打開狀態,使用--skip-add-drop-table取消選項)
mysqldump  -uroot -p --all-databases  (默認添加drop語句)
mysqldump  -uroot -p --all-databases –skip-add-drop-table  (取消drop語句)
--add-locks
在每一個表導出以前增長LOCK TABLES而且以後UNLOCK  TABLE。(默認爲打開狀態,使用--skip-add-locks取消選項)
mysqldump  -uroot -p --all-databases  (默認添加LOCK語句)
mysqldump  -uroot -p --all-databases –skip-add-locks   (取消LOCK語句)
--allow-keywords
容許建立是關鍵詞的列名字。這由表名前綴於每一個列名作到。
mysqldump  -uroot -p --all-databases --allow-keywords
--apply-slave-statements
在'CHANGE MASTER'前添加'STOP SLAVE',而且在導出的最後添加'START SLAVE'。
mysqldump  -uroot -p --all-databases --apply-slave-statements
--character-sets-dir
字符集文件的目錄
mysqldump  -uroot -p --all-databases  --character-sets-dir=/usr/local/mysql/share/mysql/charsets
--comments
附加註釋信息。默認爲打開,能夠用--skip-comments取消
mysqldump  -uroot -p --all-databases  (默認記錄註釋)
mysqldump  -uroot -p --all-databases --skip-comments   (取消註釋)
--compatible
導出的數據將和其它數據庫或舊版本的MySQL 相兼容。值能夠爲ansi、mysql32三、mysql40、postgresql、oracle、mssql、db二、maxdb、no_key_options、no_tables_options、no_field_options等,
要使用幾個值,用逗號將它們隔開。它並不保證能徹底兼容,而是儘可能兼容。
mysqldump  -uroot -p --all-databases --compatible=ansi
--compact
導出更少的輸出信息(用於調試)。去掉註釋和頭尾等結構。可使用選項:--skip-add-drop-table  --skip-add-locks --skip-comments --skip-disable-keys
mysqldump  -uroot -p --all-databases --compact
--complete-insert,  -c
使用完整的insert語句(包含列名稱)。這麼作能提升插入效率,可是可能會受到max_allowed_packet參數的影響而致使插入失敗。
mysqldump  -uroot -p --all-databases --complete-insert
--compress, -C
在客戶端和服務器之間啓用壓縮傳遞全部信息
mysqldump  -uroot -p --all-databases --compress
--create-options,  -a
在CREATE TABLE語句中包括全部MySQL特性選項。(默認爲打開狀態)
mysqldump  -uroot -p --all-databases
--databases,  -B
導出幾個數據庫。參數後面全部名字參量都被看做數據庫名。
mysqldump  -uroot -p --databases test mysql
--debug
輸出debug信息,用於調試。默認值爲:d:t,/tmp/mysqldump.trace
mysqldump  -uroot -p --all-databases --debug
mysqldump  -uroot -p --all-databases --debug=」 d:t,/tmp/debug.trace」
--debug-check
檢查內存和打開文件使用說明並退出。
mysqldump  -uroot -p --all-databases --debug-check
--debug-info
輸出調試信息並退出
mysqldump  -uroot -p --all-databases --debug-info
--default-character-set
設置默認字符集,默認值爲utf8
mysqldump  -uroot -p --all-databases --default-character-set=utf8
--delayed-insert
採用延時插入方式(INSERT DELAYED)導出數據
mysqldump  -uroot -p --all-databases --delayed-insert
--delete-master-logs
master備份後刪除日誌. 這個參數將自動激活--master-data。
mysqldump  -uroot -p --all-databases --delete-master-logs
--disable-keys
對於每一個表,用/*!40000 ALTER TABLE tbl_name DISABLE KEYS */;和/*!40000 ALTER TABLE tbl_name ENABLE KEYS */;語句引用INSERT語句。這樣能夠更快地導入dump出來的文件,由於它是在插入全部行後建立索引的。該選項只適合MyISAM表,默認爲打開狀態。
mysqldump  -uroot -p --all-databases 
--dump-slave
該選項將主的binlog位置和文件名追加到導出數據的文件中(show slave status)。設置爲1時,將會以CHANGE MASTER命令輸出到數據文件;設置爲2時,會在change前加上註釋。該選項將會打開--lock-all-tables,除非--single-transaction被指定。該選項會自動關閉--lock-tables選項。默認值爲0。
mysqldump  -uroot -p --all-databases --dump-slave=1
mysqldump  -uroot -p --all-databases --dump-slave=2
--master-data
該選項將當前服務器的binlog的位置和文件名追加到輸出文件中(show master status)。若是爲1,將會輸出CHANGE MASTER 命令;若是爲2,輸出的CHANGE  MASTER命令前添加註釋信息。該選項將打開--lock-all-tables 選項,除非--single-transaction也被指定(在這種狀況下,全局讀鎖在開始導出時得到很短的時間;其餘內容參考下面的--single-transaction選項)。該選項自動關閉--lock-tables選項。
mysqldump  -uroot -p --host=localhost --all-databases --master-data=1;
mysqldump  -uroot -p --host=localhost --all-databases --master-data=2;
--events, -E
導出事件。
mysqldump  -uroot -p --all-databases --events
--extended-insert,  -e
使用具備多個VALUES列的INSERT語法。這樣使導出文件更小,並加速導入時的速度。默認爲打開狀態,使用--skip-extended-insert取消選項。
mysqldump  -uroot -p --all-databases
mysqldump  -uroot -p --all-databases--skip-extended-insert   (取消選項)
--fields-terminated-by
導出文件中忽略給定字段。與--tab選項一塊兒使用,不能用於--databases和--all-databases選項
mysqldump  -uroot -p test test --tab=」/home/mysql」 --fields-terminated-by=」#」
--fields-enclosed-by
輸出文件中的各個字段用給定字符包裹。與--tab選項一塊兒使用,不能用於--databases和--all-databases選項
mysqldump  -uroot -p test test --tab=」/home/mysql」 --fields-enclosed-by=」#」
--fields-optionally-enclosed-by
輸出文件中的各個字段用給定字符選擇性包裹。與--tab選項一塊兒使用,不能用於--databases和--all-databases選項
mysqldump  -uroot -p test test --tab=」/home/mysql」  --fields-enclosed-by=」#」 --fields-optionally-enclosed-by  =」#」
--fields-escaped-by
輸出文件中的各個字段忽略給定字符。與--tab選項一塊兒使用,不能用於--databases和--all-databases選項
mysqldump  -uroot -p mysql user --tab=」/home/mysql」 --fields-escaped-by=」#」
--flush-logs
開始導出以前刷新日誌。
請注意:假如一次導出多個數據庫(使用選項--databases或者--all-databases),將會逐個數據庫刷新日誌。除使用--lock-all-tables或者--master-data外。在這種狀況下,日誌將會被刷新一次,相應的因此表同時被鎖定。所以,若是打算同時導出和刷新日誌應該使用--lock-all-tables 或者--master-data 和--flush-logs。
mysqldump  -uroot -p --all-databases --flush-logs
--flush-privileges
在導出mysql數據庫以後,發出一條FLUSH  PRIVILEGES 語句。爲了正確恢復,該選項應該用於導出mysql數據庫和依賴mysql數據庫數據的任什麼時候候。
mysqldump  -uroot -p --all-databases --flush-privileges
--force
在導出過程當中忽略出現的SQL錯誤。
mysqldump  -uroot -p --all-databases --force
--help
顯示幫助信息並退出。
mysqldump  --help
--hex-blob
使用十六進制格式導出二進制字符串字段。若是有二進制數據就必須使用該選項。影響到的字段類型有BINARY、VARBINARY、BLOB。
mysqldump  -uroot -p --all-databases --hex-blob
--host, -h
須要導出的主機信息
mysqldump  -uroot -p --host=localhost --all-databases
--ignore-table
不導出指定表。指定忽略多個表時,須要重複屢次,每次一個表。每一個表必須同時指定數據庫和表名。例如:--ignore-table=database.table1 --ignore-table=database.table2 ……
mysqldump  -uroot -p --host=localhost --all-databases --ignore-table=mysql.user
--include-master-host-port
在--dump-slave產生的'CHANGE  MASTER TO..'語句中增長'MASTER_HOST=<host>,MASTER_PORT=<port>'  
mysqldump  -uroot -p --host=localhost --all-databases --include-master-host-port
--insert-ignore
在插入行時使用INSERT IGNORE語句.
mysqldump  -uroot -p --host=localhost --all-databases --insert-ignore
--lines-terminated-by
輸出文件的每行用給定字符串劃分。與--tab選項一塊兒使用,不能用於--databases和--all-databases選項。
mysqldump  -uroot -p --host=localhost test test --tab=」/tmp/mysql」  --lines-terminated-by=」##」
--lock-all-tables,  -x
提交請求鎖定全部數據庫中的全部表,以保證數據的一致性。這是一個全局讀鎖,而且自動關閉--single-transaction 和--lock-tables 選項。
mysqldump  -uroot -p --host=localhost --all-databases --lock-all-tables
--lock-tables,  -l
開始導出前,鎖定全部表。用READ  LOCAL鎖定表以容許MyISAM表並行插入。對於支持事務的表例如InnoDB和BDB,--single-transaction是一個更好的選擇,由於它根本不須要鎖定表。
請注意當導出多個數據庫時,--lock-tables分別爲每一個數據庫鎖定表。所以,該選項不能保證導出文件中的表在數據庫之間的邏輯一致性。不一樣數據庫表的導出狀態能夠徹底不一樣。
mysqldump  -uroot -p --host=localhost --all-databases --lock-tables
--log-error
附加警告和錯誤信息到給定文件
mysqldump  -uroot -p --host=localhost --all-databases  --log-error=/tmp/mysqldump_error_log.err
--max_allowed_packet
服務器發送和接受的最大包長度。
mysqldump  -uroot -p --host=localhost --all-databases --max_allowed_packet=10240
--net_buffer_length
TCP/IP和socket鏈接的緩存大小。
mysqldump  -uroot -p --host=localhost --all-databases --net_buffer_length=1024
--no-autocommit
使用autocommit/commit 語句包裹表。
mysqldump  -uroot -p --host=localhost --all-databases --no-autocommit
--no-create-db,  -n
只導出數據,而不添加CREATE DATABASE 語句。
mysqldump  -uroot -p --host=localhost --all-databases --no-create-db
--no-create-info,  -t
只導出數據,而不添加CREATE TABLE 語句。
mysqldump  -uroot -p --host=localhost --all-databases --no-create-info
--no-data, -d
不導出任何數據,只導出數據庫表結構。
mysqldump  -uroot -p --host=localhost --all-databases --no-data
--no-set-names,  -N
等同於--skip-set-charset
mysqldump  -uroot -p --host=localhost --all-databases --no-set-names
--opt
等同於--add-drop-table,  --add-locks, --create-options, --quick, --extended-insert, --lock-tables,  --set-charset, --disable-keys 該選項默認開啓,  能夠用--skip-opt禁用.
mysqldump  -uroot -p --host=localhost --all-databases --opt
--order-by-primary
若是存在主鍵,或者第一個惟一鍵,對每一個表的記錄進行排序。在導出MyISAM表到InnoDB表時有效,但會使得導出工做花費很長時間。 
mysqldump  -uroot -p --host=localhost --all-databases --order-by-primary
--password, -p
鏈接數據庫密碼
--pipe(windows系統可用)
使用命名管道鏈接mysql
mysqldump  -uroot -p --host=localhost --all-databases --pipe
--port, -P
鏈接數據庫端口號
--protocol
使用的鏈接協議,包括:tcp, socket, pipe, memory.
mysqldump  -uroot -p --host=localhost --all-databases --protocol=tcp
--quick, -q
不緩衝查詢,直接導出到標準輸出。默認爲打開狀態,使用--skip-quick取消該選項。
mysqldump  -uroot -p --host=localhost --all-databases 
mysqldump  -uroot -p --host=localhost --all-databases --skip-quick
--quote-names,-Q
使用(`)引發表和列名。默認爲打開狀態,使用--skip-quote-names取消該選項。
mysqldump  -uroot -p --host=localhost --all-databases
mysqldump  -uroot -p --host=localhost --all-databases --skip-quote-names
--replace
使用REPLACE INTO 取代INSERT INTO.
mysqldump  -uroot -p --host=localhost --all-databases --replace
--result-file,  -r
直接輸出到指定文件中。該選項應該用在使用回車換行對(\\r\\n)換行的系統上(例如:DOS,Windows)。該選項確保只有一行被使用。
mysqldump  -uroot -p --host=localhost --all-databases --result-file=/tmp/mysqldump_result_file.txt
--routines, -R
導出存儲過程以及自定義函數。
mysqldump  -uroot -p --host=localhost --all-databases --routines
--set-charset
添加'SET NAMES  default_character_set'到輸出文件。默認爲打開狀態,使用--skip-set-charset關閉選項。
mysqldump  -uroot -p --host=localhost --all-databases 
mysqldump  -uroot -p --host=localhost --all-databases --skip-set-charset
--single-transaction
該選項在導出數據以前提交一個BEGIN SQL語句,BEGIN 不會阻塞任何應用程序且能保證導出時數據庫的一致性狀態。它只適用於多版本存儲引擎,僅InnoDB。本選項和--lock-tables 選項是互斥的,由於LOCK  TABLES 會使任何掛起的事務隱含提交。要想導出大表的話,應結合使用--quick 選項。
mysqldump  -uroot -p --host=localhost --all-databases --single-transaction
--dump-date
將導出時間添加到輸出文件中。默認爲打開狀態,使用--skip-dump-date關閉選項。
mysqldump  -uroot -p --host=localhost --all-databases
mysqldump  -uroot -p --host=localhost --all-databases --skip-dump-date
--skip-opt
禁用–opt選項.
mysqldump  -uroot -p --host=localhost --all-databases --skip-opt
--socket,-S
指定鏈接mysql的socket文件位置,默認路徑/tmp/mysql.sock
mysqldump  -uroot -p --host=localhost --all-databases --socket=/tmp/mysqld.sock
--tab,-T
爲每一個表在給定路徑建立tab分割的文本文件。注意:僅僅用於mysqldump和mysqld服務器運行在相同機器上。注意使用--tab不能指定--databases參數
mysqldump  -uroot -p --host=localhost test test --tab="/home/mysql"
--tables
覆蓋--databases (-B)參數,指定須要導出的表名,在後面的版本會使用table取代tables。
mysqldump  -uroot -p --host=localhost --databases test --tables test
--triggers
導出觸發器。該選項默認啓用,用--skip-triggers禁用它。
mysqldump  -uroot -p --host=localhost --all-databases --triggers
--tz-utc
在導出頂部設置時區TIME_ZONE='+00:00' ,以保證在不一樣時區導出的TIMESTAMP 數據或者數據被移動其餘時區時的正確性。
mysqldump  -uroot -p --host=localhost --all-databases --tz-utc
--user, -u
指定鏈接的用戶名。
--verbose, --v
輸出多種平臺信息。
--version, -V
輸出mysqldump版本信息並退出
--where, -w
只轉儲給定的WHERE條件選擇的記錄。請注意若是條件包含命令解釋符專用空格或字符,必定要將條件引用起來。
mysqldump  -uroot -p --host=localhost --all-databases --where=」 user=’root’」
--xml, -X
導出XML格式.
mysqldump  -uroot -p --host=localhost --all-databases --xml
--plugin_dir
客戶端插件的目錄,用於兼容不一樣的插件版本。
mysqldump  -uroot -p --host=localhost --all-databases --plugin_dir=」/usr/local/lib/plugin」
--default_auth
客戶端插件默認使用權限。
mysqldump  -uroot -p --host=localhost --all-databases --default-auth=」/usr/local/lib/plugin/<PLUGIN>」
  • unknown option '--no-beep'
解決辦法是:

1. 刪除my.ini [client]下的 no-beep 參數;
2. 在 mysqldump 後加--no-defaults參數,即:mysqldump --no-defualts -h主機IP -u用戶名 -p密碼 數據庫 > xxx.sql 。
  • 轉自:http://www.cnblogs.com/wangfengming/articles/7883974.html
  • 轉自:http://www.178linux.com/15423
相關文章
相關標籤/搜索