MySQL其餘和備份

事務

事務指的是一組操做,要麼執行成功,要麼都執行失敗html

咱們來看下面一個例子:node

我去銀行給朋友匯款,我卡上有1000元,朋友卡有1000元,我給朋友轉帳100元(無手續費)。若是個人錢剛被扣完,這時候網絡忽然斷了,而朋友帳戶的錢又沒加,怎麼辦?mysql

咱們來模擬一下這個操做:redis

mysql> create table user(
    id int auto_increment primary key,
    name varchar(32) not null default '',
    salary int not null default 0
)charset=utf8;

# 向表中插入數據
mysql> insert into user(name,salary) values ("qinyj",1000);
mysql> insert into user(name,salary) values ("jack",1000);

# 此時咱們打開兩個終端 查看數據
# 一個終端表明qinyj,另外一個表明jack
mysql> select * from user where name="qinyj";

mysql> select * from user where name="jack";

# 當我開始轉帳的時候在個人窗口進行操做
mysql> update user set salary=900 where name="qinyj";
# 這時候模擬網忽然斷了,轉不了帳了
# 咱們再來查看qinyj的帳戶
mysql> select * from user where name="qinyj";
# 咱們再來看jack的帳戶
mysql> select * from user where name="jack";

# 發現qinyj已經轉帳了,帳戶的錢已經少了100,可是jack的帳戶的錢卻沒有增長,那麼這就形成了一個數據上的不安全。

模擬完上面的操做以後呢,咱們來解決這個問題sql

解決這個問題就須要用到mysql的事務:docker

start transaction:使用事務shell

commit/rollback:提交事務/回滾事務數據庫

例子:緩存

mysql> start transaction;   # 使用事務
Query OK, 0 rows affected (0.00 sec)

mysql> update user set salary=900 where name="qinyj";
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update user set salary=1100 where name="jack";
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit;              # 提交事務
Query OK, 0 rows affected (0.01 sec)

# 若是在commit以前 全部轉帳sql已經執行完畢了,這時候忽然斷網了,那麼mysql會默認執行rollback操做,將事務中全部操做回滾到使用事務以前的狀態,保證了數據的安全
mysql> rollback;            # 回滾提交
Query OK, 0 rows affected (0.00 sec)

# 咱們再來看兩個帳戶的金額:
mysql> select * from user where name="qinyj";

mysql> select * from user where name="jack";

pymysql使用事務

import pymysql

conn = pymysql.connect(
    host="192.168.32.130",
    password="123",
    user="root",
    database="test",
    charset="utf8"
)

cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)

try:
    sql = "start transaction"
    cursor.execute(sql)

    sql = "update user set salary=800 where name='qinyj'"
    cursor.execute(sql)

    import time
    print(".......")
    time.sleep(20)

    sql = "update user set salary=1200 where name='jack'"
    cursor.execute(sql)
    sql = "commit"
    cursor.execute(sql)
except Exception as e:

    print("事務處理失敗")
    sql = "rollback"
    cursor.execute(sql)


    cursor.close()
    conn.close()

那麼咱們來總結一下事務的特性特徵:

  • 原子性:原子意思爲最小的粒子,即不能再分的書屋,要麼所有執行,要麼所有取消,就像上面銀行轉帳的例子。
  • 一致性:指事務發生前和發生後數據的總額依然匹配。
  • 隔離性:指得是某個事務的操做對其餘事務不可見,隔離開來的。
  • 持久性:當事務完成後,影響應該保留下來,不能撤銷,只能經過「補償性事務」來取消以前的錯誤。

存儲引擎

存儲引擎負責MySQL中的數據的存儲和提取。

MySQL存儲引擎有不少,不一樣的存儲引擎保存數據和索引的方式是不一樣的。每一種存儲引擎都有它的優點和劣勢

InnoDB存儲引擎

InnoDB是默認的事務型存儲引擎,也是最重要,使用最普遍的存儲引擎。在沒有特殊狀況下,通常優先使用InnoDB存儲引擎。

數據存儲形式

使用InnoDB時,會將數據表分爲.frm 和 idb兩個文件進行存儲。

鎖的粒度

InnoDB採用MVCC(多版本併發控制)來支持高併發,InnoDB實現了四個隔離級別,默認級別是REPETABLE READ,並經過間隙鎖策略防止幻讀的出現。它的鎖粒度是行鎖。【經過MVCC實現,MVCC在稍後會進行介紹】

事務

InnoDB是典型的事務型存儲引擎,而且經過一些機制和工具,支持真正的熱備份。

數據的存儲特色

InnoDB表是基於聚簇索引創建的,聚簇索引對主鍵的查詢有很高的性能,不過他的二級索引(非主鍵索引)必須包含主鍵列,索引其餘的索引會很大。

MyISAM存儲引擎

數據存儲形式

MyISAM採用的是索引與數據分離的形式,將數據保存在三個文件中.frm.MYD,.MYIs。

鎖的粒度

MyISAM不支持行鎖,因此讀取時對錶加上共享鎖,在寫入是對錶加上排他鎖。因爲是對整張表加鎖,相比InnoDB,在併發寫入時效率很低。

事務

MyISAM不支持事務。

數據的存儲特色

MyISAM是基於非聚簇索引進行存儲的。

其餘

MyISAM提供了大量的特性,包括全文索引,壓縮,空間函數,延遲更新索引鍵等。

進行壓縮後的表是不能進行修改的,可是壓縮表能夠極大減小磁盤佔用空間,所以也能夠減小磁盤IO,從而提供查詢性能。

全文索引,是一種基於分詞建立的索引,能夠支持複雜的查詢。

延遲更新索引鍵,不會將更新的索引數據當即寫入到磁盤,而是會寫到內存中的緩衝區中,只有在清除緩衝區時候纔會將對應的索引寫入磁盤,這種方式大大提高了寫入性能。

對比與選擇

兩種存儲引擎各有各的有點,MyISAM專一性能,InnoDB專一事務。

如何在兩種存儲引擎中進行選擇?

① 是否有事務操做?有,InnoDB。

②是否存儲併發修改?有,InnoDB。

③是否追求快速查詢,且數據修改較少?是,MyISAM。

④是否使用全文索引?若是不引用第三方框架,能夠選擇MyISAM,可是能夠選用第三方框架和InnDB效率會更高。

咱們在建立表的時候能夠指定存儲引擎,若是沒有指定,默認在mysql5.5版本以上建立的表默認是InnoDB引擎

兩個引擎的區別:

  • InnoDB:支持事務;支持行鎖
  • MyIsam:不支持事務;支持表鎖

查看當前默認存儲引擎:

show engines;

在建立表的時候指定引擎:

create table test(id int auto_increment primary key)engine=InnoDB;
create table test(id int auto_increment primary key)engine=MyIsam;

在配置文件中指定:

default-storage-engine=INNODB

常見存儲引擎以及使用場景:

  • InnoDB:事務處理應用程序,對於相似擊飛系統或者對數據要求比較高的
  • MyIsam:對事務完整性,併發性要求不高,可使用這個存儲引擎。

視圖

視圖是一種虛擬存在的表,通俗的說 視圖就是執行select語句後返回的結果。

增長視圖:

create view 視圖名 as sql語句

刪除視圖:

drop view 視圖名

例子:

# 若是咱們對下面的sql語句查詢很是頻繁而且這個sql很是長,那麼咱們能夠建立出來一個視圖
mysql> select * from user where name="qinyj";

# 建立視圖
mysql> create view v1 as select * from user where name="qinyj";
Query OK, 0 rows affected (0.00 sec)

# 再查看錶,會看到有一個v1的表
show tables;

# 那麼咱們若是想要去查第一個sql,而且這個sql很是長,又不想從新輸入一遍,那麼咱們能夠查這個視圖,出來效果是同樣的。
mysql> select * from v1;

觸發器

假設如今有這樣一個場景,有兩張表,

訂單表 庫存表

當咱們下一個訂單的時候,訂單表中須要增長一條記錄,同時庫存表中須要減1,這兩個操做是同時發生的,而且前一個操做觸發下一個操做,就可使用觸發器

使用方法:

增長觸發器:

delimiter //
create trigger boy_before_insert_girl before insert on boy for each row
begin
    insert into girl (girl_name) values ("aa");
end //
delimiter ;

例子:

mysql> delimiter //
mysql> create trigger boy_before_insert_girl before insert on boy for each row
    -> begin
    -> insert into girl (girl_name) values ("aa");
    -> end //
Query OK, 0 rows affected (0.00 sec)

mysql> delimiter ;  # 結束符

mysql> show triggers\G;

# 當咱們在向boy表中插入數據的時候,咱們再來查詢girl表的數據會發現會多一條記錄

mysql> insert into boy (boy_name) values ("qinyj");
Query OK, 1 row affected (0.01 sec)
mysql> select * from boy;
mysql> select * from girl;

刪除觸發器:

drop trigger 觸發器名

存儲過程

像一個SQL函數,一組sql語句集,存儲過程就是一段預執行的sql語句,都是一組sql集,存儲過程主動調用的時候纔會執行。

建立存儲過程:

delimiter //
create procedure p1()
begin
    select * from boy where id=2;
end //
delimiter ;

查看存儲過程:

mysql> show procedure status\G;

刪除存儲過程:

mysql> drop procedure p1;

調用存儲過程:

mysql> call p1();

函數

參考:https://www.runoob.com/mysql/mysql-functions.html

備份

物理備份

可使用percona-xtrabackup-2.0.7-552.rhel6.x86_64.rpm對mysql進行備份。

xtrabackup官方網址:https://www.percona.com/downloads/XtraBackup/

基本語法--多實例備份--語法解釋:

  • --user=數據庫用戶

  • --password=數據庫密碼

  • --socket=指定socket

  • --default-file=指定配置文件

  • 最後面是存放位置

    例子:

    innobackupex --user=root --port=3306 --host=127.0.0.1 --defaults-file=/etc/my.cnf --defaults-group=mysqld3306 --stream=tar /usr/local/backup |gzip > 127.0.0.1_3306.tar.gz

全數據還原

  1. /etc/init.d/mysqld stop //停掉mysql
  2. mv /var/lib/mysql /var/lib/mysql_bak //數據目錄備份
  3. mkdir -p /var/lib/mysql //重建數據目錄
  4. --apply-log選項的命令是準備在一個備份上啓動mysql服務
  5. --copy-back 選項的命令從備份目錄拷貝數據,索引,日誌到my.cnf文件裏規定的初始位置
  6. innobackupex --defaults-file=/etc/my.cnf --user=root --apply-log /home/tank/backup/2014-09-18_16-35-12
  7. chown -R mysql.mysql /var/lib/mysql //改變文件所屬
  8. /etc/init.d/mysqld stop //啓動mysql

備份腳本

#!/bin/bash
#       Version V1.1
###############################################
# 保留備份的天數
DAY=3
#等待n秒後再執行備份
wait=60
#是否開啓增量備份默認0爲開啓1爲關閉
open_increase_bak=1
#全備時間點
default_time=4
#設置不進行備份的時間點
exclude_time="0 5"
###############################################

#載入環境變量,不然沒法找到/usr/local/mysql/bin/mysql路徑

source /etc/profile

DBIP="127.0.0.1"

DBUSER="xxx"

DBPWD="root"

DATE=`date +%F_%H-%M`

Hour=`date '+%H'`

PORT=`netstat -tunlp|grep mysql |awk '{print $4}'|awk -F: '{print $2}'`

MYCNF="/etc/my.cnf"

LOG_FILE="/home/msbakscript/logs/xtrabackup.log"

BACKUP_PATH="/usr/local/hero_all_backup"

MYSQL_LOG="/home/msbakscript/logs/mysql.log"

INNOBACKUPEX="/usr/bin/innobackupex"

bak_log="/home/msbakscript/logs/mysqlbak.log"

MYSQL_PATH="/usr/local/mysql/var"

HOST=$(awk -F= '/IPADDR=/ {print $2}' /etc/sysconfig/network-scripts/ifcfg-eth1)

CHECKPOINT=$(awk '/to_lsn/ {print $3}' /usr/local/hero_all_backup/xtrabackup_checkpoints 2>/dev/null)

all_bak=("$HOST"_"$DATE")

increase_bak=("$HOST"_"$DATE""-increase")

 

if [ $# -eq 0 -o $# -eq 1 -o $# -eq 2 ];then

        echo "OK" > /dev/null

else

        echo "sh $0 allbakfile 或者 sh $0 allbakfile incbakfile"

        exit 1

fi

[ ! -d ${BACKUP_PATH} ] && mkdir -p ${BACKUP_PATH}

[ ! -d /home/msbakscript/logs ] && mkdir -p /home/msbakscript/logs

 

if [ -z "`/sbin/pidof -s mysqld`" ];then

        echo "mysqld is not running"

        exit 1

fi

 

if [ `rpm -qa |grep -c xtrabackup-0.9-2.rhel4` -eq 1 ];then

        rpm -e xtrabackup-0.9-2.rhel4

fi

if [ ! -f /usr/bin/innobackupex ];then

        echo "xtrabackup is not installed"

        rpm -i --nodeps http://122.228.194.133:8080/percona-xtrabackup-2.0.7-552.rhel5.x86_64.rpm

elif [ -f /usr/bin/innobackupex ] && [ `ps -ef|grep -v grep |grep -c  /usr/bin/innobackupex` -ge 1 ];then

        echo "xtrabackup process already exist."

        exit 1

fi

 

complete_bak ()

{

        cd ${BACKUP_PATH}

        ${INNOBACKUPEX} --user=${DBUSER} --password=${DBPWD} --port=${PORT} --host=${DBIP} --defaults-file=${MYCNF} --stream=tar ${BACKUP_PATH}/ 2>>${LOG_FILE} |gzip >${BACKUP_PATH}/${all_bak}_${P

ORT}.tar.gz

        if [ $? -eq 0 ] && [ `tail -10 "${LOG_FILE}" | grep -ic "completed OK"` -eq 1 ];then

                tar zxvfi ${BACKUP_PATH}/${all_bak}_${PORT}.tar.gz xtrabackup_checkpoints

                echo "${all_bak}_${PORT}.tar.gz backup successed" >>${bak_log}

                echo -en "ok\n${all_bak}_${PORT}.tar.gz" >${MYSQL_LOG}

                sh /home/msbakscript/redis_backup.sh

                chown nobody.nobody *

        else

                echo "${all_bak}_${PORT}.tar.gz backup failed" >>${bak_log}

                echo -e "failure\n${all_bak}_${PORT}.tar.gz" >${MYSQL_LOG}

                exit 1

        fi

}

complete_bak

increase_bak ()

{

        cd ${BACKUP_PATH}

        if [ ! -f ${BACKUP_PATH}/xtrabackup_checkpoints -o -z ${BACKUP_PATH}/xtrabackup_checkpoints ];then

                echo "xtrabackup_checkpoints does not exist" >>/{LOG_FILE}

                complete_bak

                exit 0

        fi

        ${INNOBACKUPEX} --user=${DBUSER} --password=${DBPWD} --port=${PORT} --host=${DBIP} --defaults-file=${MYCNF} --no-timestamp --incremental --throttle=30 ${BACKUP_PATH}/${increase_bak}_${PORT

} --incremental-lsn=${CHECKPOINT} >>${LOG_FILE} 2>&1

        if [ $? -eq 0 ] && [ `tail -10 "${LOG_FILE}" | grep -ic "completed OK"` -eq 1 ];then

                tar zcfi ${increase_bak}_${PORT}.tar.gz ${increase_bak}/

                rm -rf ${increase_bak}_${PORT}

                echo "${increase_bak}_${PORT}.tar.gz backup successed" >>${bak_log}

                echo -e "ok\n${increase_bak}_${PORT}.tar.gz" >${MYSQL_LOG}

        else

                echo "${increase_bak}_${PORT} backup failed" >>${bak_log}

                echo -e "failure\n${increase_bak}_${PORT}.tar.gz" >${MYSQL_LOG}

                exit 1

        fi
}

increase_bak

del_bakfile ()

{

        for dbfile in `find "${BACKUP_PATH}/" -name "[0-9]*.tar.gz" -type f -mtime +${DAY}`; do

                rm -f ${dbfile}

        done

}

del_bakfile

bakmysql ()

{

        for i in ${exclude_time[@]};do

                [ "${Hour}" -eq "$i" ] && exit 0

        done

        if [  "${Hour}" -eq "${default_time}" ];then

                complete_bak

        elif [  "${Hour}" -ne "${default_time}" -a ${open_increase_bak} -eq 0 ];then

                increase_bak

        else

                exit 0

        fi

}

bakmysql

 

case $# in

        0)

        bakmysql

        del_bakfile

        ;;

        1)

        if [ "$1" = "all" ];then

                complete_bak

                del_bakfile

        elif [  "$1" = "inc" ];then

                increase_bak

                del_bakfile

        else

                echo "sh $0 all or sh $0 inc" && exit 0

        fi

        ;;

esac

邏輯備份

mysqldump工具:邏輯備份工具,適用全部存儲引擎溫備;支持徹底或部分備份;對InnoDB存儲引擎支持熱備;Schema(數據庫的定義)和數據存儲在一塊兒。

mysqldump參考:
https://dev.mysql.com/doc/refman/5.7/en/mysqldump.html
語法: 
 mysqldump [OPTIONS] database [tables] 
 mysqldump [OPTIONS] –B DB1 [DB2 DB3...]
 mysqldump [OPTIONS] –A [OPTIONS]
選項:
    -A:備份全部庫
    -B db_name1,[db_name2,...]:備份指定庫
    -E:備份相關的全部event scheduler
    -R:備份全部存儲過程和存儲函數
    --triggers:備份表相關觸發器,默認啓用,用--skip-triggers,不備份觸發器
    --master-data={1|2}:
         1:所備份的數據以前加一條記錄爲CHANGE MASTER TO語句,非註釋,不指定默認爲1
         2:記錄爲註釋的CHANGE MASTER TO語句,注意:此選項會自動關閉--lock-tables功能,自動打開--lock-all-tables功能(除非開啓--single-transaction)
    -F:備份前滾動日誌,鎖定表完成後,執行flush logs命令,生成新的二進制日誌文件,配合-A時,會致使刷新屢次數據庫,在同一時刻執行轉儲和日誌刷新,
則應同時使用--flush-logs和-x,--master-data或-single-transaction,此時只刷新一次;建議:和-x,--master-data或 --single-transaction一塊兒使用
    --compact 去掉註釋,適合調試,生產不使用
    -d:只備份表結構
    -t:只備份數據,不備份create table
    -n:不備份create database,可被-A或-B覆蓋
    --flush-privileges:備份前刷新受權表,備份mysql庫或相關時須要使用
    -f:忽略SQL錯誤,繼續執行
    --hex-blob:使用十六進制符號轉儲二進制列(例如,「abc」變爲0x616263),受影響的數據類型包括BINARY, VARBINARY,BLOB,BIT
    -q:不緩存查詢,直接輸出,加快備份速度
InnoDB建議備份策略:
    mysqldump –uroot –A –F –E –R  --single-transaction --master-data=1 --flush-privileges  --triggers --hex-blob >$BACKUP/fullbak_$BACKUP_TIME.sql

MyISAM建議備份策略:
    mysqldump –uroot –A –F –E –R –x --master-data=1 --flush-privileges  --triggers --hex-blob >$BACKUP/fullbak_$BACKUP_TIME.sql

補充
一、 null 和 空值有什麼區別?
null 佔用空間、空不佔空間
在查詢的時候:
count會忽略null的行數,但不會忽略空值

二、 約束條件限制了not null能夠插入空值嗎?
能夠插入空值
不能夠插入null

三、 null 和 空哪一個查詢效率更高 使用 is not null的時候能夠過濾掉 null的值,可是空值過濾不掉 使用count會過濾掉null值,但不會過濾掉空值

相關文章
相關標籤/搜索