目錄php
事務指的是一組操做,要麼執行成功,要麼都執行失敗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時,會將數據表分爲.frm 和 idb兩個文件進行存儲。
InnoDB採用MVCC(多版本併發控制)來支持高併發,InnoDB實現了四個隔離級別,默認級別是REPETABLE READ,並經過間隙鎖策略防止幻讀的出現。它的鎖粒度是行鎖。【經過MVCC實現,MVCC在稍後會進行介紹】
InnoDB是典型的事務型存儲引擎,而且經過一些機制和工具,支持真正的熱備份。
InnoDB表是基於聚簇索引創建的,聚簇索引對主鍵的查詢有很高的性能,不過他的二級索引(非主鍵索引)必須包含主鍵列,索引其餘的索引會很大。
MyISAM採用的是索引與數據分離的形式,將數據保存在三個文件中.frm.MYD,.MYIs。
MyISAM不支持行鎖,因此讀取時對錶加上共享鎖,在寫入是對錶加上排他鎖。因爲是對整張表加鎖,相比InnoDB,在併發寫入時效率很低。
MyISAM不支持事務。
MyISAM是基於非聚簇索引進行存儲的。
MyISAM提供了大量的特性,包括全文索引,壓縮,空間函數,延遲更新索引鍵等。
進行壓縮後的表是不能進行修改的,可是壓縮表能夠極大減小磁盤佔用空間,所以也能夠減小磁盤IO,從而提供查詢性能。
全文索引,是一種基於分詞建立的索引,能夠支持複雜的查詢。
延遲更新索引鍵,不會將更新的索引數據當即寫入到磁盤,而是會寫到內存中的緩衝區中,只有在清除緩衝區時候纔會將對應的索引寫入磁盤,這種方式大大提高了寫入性能。
兩種存儲引擎各有各的有點,MyISAM專一性能,InnoDB專一事務。
如何在兩種存儲引擎中進行選擇?
① 是否有事務操做?有,InnoDB。
②是否存儲併發修改?有,InnoDB。
③是否追求快速查詢,且數據修改較少?是,MyISAM。
④是否使用全文索引?若是不引用第三方框架,能夠選擇MyISAM,可是能夠選用第三方框架和InnDB效率會更高。
咱們在建立表的時候能夠指定存儲引擎,若是沒有指定,默認在mysql5.5版本以上建立的表默認是InnoDB引擎
兩個引擎的區別:
查看當前默認存儲引擎:
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
常見存儲引擎以及使用場景:
視圖是一種虛擬存在的表,通俗的說 視圖就是執行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
全數據還原
備份腳本
#!/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值,但不會過濾掉空值