|
本篇文章我們來了解一下 MySQL 中的高級(jí)內(nèi)容。 事務(wù)控制和鎖定語句我們知道,MyISAM 和 MEMORY 存儲(chǔ)引擎支持 頁級(jí)鎖:銷和加鎖時(shí)間界于表鎖和行鎖之間;會(huì)出現(xiàn)死鎖;鎖定粒度界于表鎖和行鎖之間,并發(fā)度一般 表級(jí)鎖:表級(jí)鎖是對(duì)整張表進(jìn)行加鎖,MyISAM 和 MEMORY 主要支持表級(jí)鎖,表級(jí)鎖加鎖快,不會(huì)出現(xiàn)死鎖,鎖的粒度比較粗,并發(fā)度最低 行級(jí)鎖:行級(jí)鎖可以說是 MySQL 中粒度最細(xì)的一種鎖了,InnoDB 支持行級(jí)鎖,行級(jí)鎖容易發(fā)生死鎖,并發(fā)度比較好,同時(shí)鎖的開銷也比較大。 MySQL 默認(rèn)情況下支持表級(jí)鎖定和行級(jí)鎖定。但是在某些情況下需要手動(dòng)控制事務(wù)以確保整個(gè)事務(wù)的完整性,下面我們就來探討一下事務(wù)控制。但是在探討事務(wù)控制之前我們先來認(rèn)識(shí)一下兩個(gè)鎖定語句 鎖定語句MySQL 的鎖定語句主要有兩個(gè) lock table cxuan005 read;我們鎖定了 cxuan005 的 read 鎖,然后這時(shí)我們?cè)龠M(jìn)行一次查詢,看看是否能夠執(zhí)行這條語句 可以看到,在進(jìn)行 read 鎖定了,我們?nèi)耘f能夠執(zhí)行查詢語句。 現(xiàn)在我們另外起一個(gè)窗口,相當(dāng)于另起了一個(gè)線程來進(jìn)行查詢操作。 select * from cxuan005;這是第二個(gè)窗口執(zhí)行查詢的結(jié)果,可以看到,在一個(gè)線程執(zhí)行 read 鎖定后,其他線程仍然可以進(jìn)行表的查詢操作。 那么第二個(gè)線程能否執(zhí)行更新操作呢?我們來看一下 發(fā)生了什么?怎么沒有提示結(jié)果呢?其實(shí)這個(gè)情況下表示 cxuan005 已經(jīng)被加上了 read 鎖,由于當(dāng)前線程不是持有鎖的線程,所以當(dāng)前線程無法執(zhí)行更新。 解鎖語句現(xiàn)在我們把窗口切換成持有 read 鎖的線程,來進(jìn)行 read 鎖的解鎖 unlock tables;在解鎖完成前,進(jìn)行更新的線程會(huì)一直等待,直到解鎖完成后,才會(huì)進(jìn)行更新。我們可以看一下更新線程的結(jié)果。 可以看到,線程已經(jīng)更新完畢,我們看一下更新的結(jié)果 如上圖所示,id = 111 的值已經(jīng)被更新成了 cxuan。 事務(wù)控制
在 MySQL 事務(wù)中,主要涉及的語法包含 SET AUTOCOMMIT、START TRANSACTION、COMMIT 和 ROLLBACK 等。 自動(dòng)提交在 MySQL 中,事務(wù)默認(rèn)是 show variables like 'autocommit';在自動(dòng)提交的模式下,每個(gè) SQL 語句都會(huì)當(dāng)作一個(gè)事務(wù)執(zhí)行提交操作,例如我們上面使用的更新語句
其實(shí),MySQL 是可以關(guān)閉自動(dòng)提交的,你可以執(zhí)行 set autocommit = 0;
然后我們?cè)倏匆幌伦詣?dòng)提交是否關(guān)閉了,再次執(zhí)行一下 show variables like 'autocommit' 語句
可以看到,自動(dòng)提交已經(jīng)關(guān)閉了,再次執(zhí)行 會(huì)再次開啟自動(dòng)提交。
手動(dòng)提交如果需要手動(dòng) commit 和 rollback 的話,就需要明確的事務(wù)控制語句了。 典型的 MySQL 事務(wù)操作如下 start transaction;上面代碼中的 start transaction 就是事務(wù)的開始語句,編寫 SQL 后會(huì)調(diào)用 commit 提交事務(wù),然后將事務(wù)統(tǒng)一執(zhí)行,如果 SQL 語句出現(xiàn)錯(cuò)誤會(huì)自動(dòng)調(diào)用 Rollback 進(jìn)行回滾。 下面我們就通過示例來演示一下 MySQL 的事務(wù),同樣的,我們需要啟動(dòng)兩個(gè)窗口來演示,為了便于區(qū)分,我們使用 mysql01 和 mysql02 來命名。
我們用
然后執(zhí)行 select * from cxuan005;查詢一下 cxuan005 中的數(shù)據(jù)
嗯。。。很多長(zhǎng)度太長(zhǎng)了,現(xiàn)在我們把所有的 info 數(shù)據(jù)都更新為 cxuan 。
更新完畢后,我們先不提交事務(wù),分別在 mysql01 和 mysql02 中進(jìn)行查詢,發(fā)現(xiàn)只有 mysql01 窗口中的查詢已經(jīng)生效,而 mysql02 中還是更新前的數(shù)據(jù)
現(xiàn)在我們?cè)?mysql01 中 commit 當(dāng)前事務(wù),然后在 mysql02 中查詢,發(fā)現(xiàn)數(shù)據(jù)已經(jīng)被修改了。 除了 commit 之外,MySQL 中還有 start transaction; # 開啟一個(gè)新的事務(wù)上面是一個(gè)事務(wù)操作,在 commit and chain 鍵入后,我們可以再次執(zhí)行 SQL 語句 然后再次查詢 select * from cxuan005;
執(zhí)行后,可以發(fā)現(xiàn),我們僅僅使用了一個(gè) start transaction 命令就執(zhí)行了兩次事務(wù)操作。 如果在手動(dòng)提交的事務(wù)中,你發(fā)現(xiàn)有一條 SQL 語句寫的不正確或者有其他原因需要回滾,那么此時(shí)你就會(huì)用到
在同一個(gè)事務(wù)操作中,最好使用相同存儲(chǔ)引擎的表,如果使用不同存儲(chǔ)引擎的表后,rollback 語句會(huì)對(duì)非事務(wù)類型的表進(jìn)行特別處理,因此 commit 、rollback 只能對(duì)事務(wù)類型的表進(jìn)行提交和回滾。 我們提交的事務(wù)一般都會(huì)被記錄到二進(jìn)制的日志中,但是如果一個(gè)事務(wù)中包含非事務(wù)類型的表,那么回滾操作也會(huì)被記錄到二進(jìn)制日志中,以確保非事務(wù)類型的表可以被復(fù)制到從數(shù)據(jù)庫(kù)中。 這里解釋一下什么是事務(wù)表和非事務(wù)表 事務(wù)表和非事務(wù)表事務(wù)表故名思義就是支持事務(wù)的表,支不支持事務(wù)和 MySQL 的存儲(chǔ)類型有關(guān),一般情況下, 非事務(wù)表相應(yīng)的就是不支持事務(wù)的表,在 MySQL 中,存儲(chǔ)引擎 對(duì)于回滾的話,還要講一點(diǎn)就是 我們通過一個(gè)示例來進(jìn)行模擬不同的 SAVEPOINT 首先先啟動(dòng)一個(gè)事務(wù) ,向 cxuan005 中插入一條數(shù)據(jù),然后進(jìn)行查詢,那么是可以查詢到這條記錄的 start transaction;查詢之后的記錄如下
然后我們定義一個(gè) SAVEPOINT,如下所示 然后繼續(xù)插入一條記錄 insert into cxuan005(id,info) values(777,'cxuan777');此時(shí)就可以查詢到兩條新增記錄了,id 是 666 和 777 的記錄。
那么我們可以回滾到剛剛定義的 SAVEPOINT rollback to savepoint test;再次查詢 cxuan005 這個(gè)表,可以看到,只有 id=666 的這條記錄插入進(jìn)來了,說明 id=777 這條記錄已經(jīng)被回滾了。
此時(shí)我們看到的都是 mysql01 中事務(wù)還沒有提交前的狀態(tài),所以這時(shí)候 mysql02 中執(zhí)行查詢操作是看不到 666 這條記錄的。 然后我們?cè)?mysql01 中執(zhí)行 commit 操作,那么此時(shí)在 mysql02 中就可以查詢到這條記錄了。 SQL 安全問題SQL 安全問題應(yīng)該是我們程序員比較忽視的一個(gè)地方了。日常開發(fā)中,我們一般只會(huì)關(guān)心 SQL 能不能解決我們的業(yè)務(wù)問題,能不能把數(shù)據(jù)查出來,而對(duì)于 SQL 問題,我們一般都認(rèn)為這是 DBA 的活,其實(shí)我們 CRUD 程序員也應(yīng)該了解一下 SQL 的安全問題。 SQL 注入簡(jiǎn)介SQL 注入就是利用某些數(shù)據(jù)庫(kù)的外部接口將用戶數(shù)據(jù)插入到實(shí)際的 SQL 中,從而達(dá)到入侵 SQL 注入攻擊有很大的危害,攻擊者可以利用它讀取、修改或者刪除數(shù)據(jù)庫(kù)內(nèi)的數(shù)據(jù),獲取數(shù)據(jù)庫(kù)中的用戶名和密碼,甚至獲得數(shù)據(jù)庫(kù)管理員的權(quán)限。并且 SQL 注入一般比較難以防范。 SQL ModeMySQL 可以運(yùn)行在不同的 SQL Mode 模式下,不同的 SQL Mode 定義了不同的 SQL 語法,數(shù)據(jù)校驗(yàn)規(guī)則,這樣就能夠在不同的環(huán)境中使用 MySQL ,下面我們就來介紹一下 SQL Mode。 SQL Mode 解決問題SQL Mode 可以解決下面這幾種問題
下面我們就通過示例來演示一下 SQL Mode 用法 我們可以通過 來查看默認(rèn)的 SQL Mode,如下是我的數(shù)據(jù)庫(kù)所支持的 SQL Mode
涉及到很多 SQL Mode,下面是這些 SQL Mode 的解釋
同樣舉個(gè)例子,我們現(xiàn)在查詢一下 cxuan005 的 id 和 info 字段。 select id,info from cxuan005;這樣是可以運(yùn)行的
然后我們使用 GROUP BY 字句進(jìn)行分組,這里只對(duì) info 進(jìn)行分組,我們看一下會(huì)出現(xiàn)什么情況
我們可以從錯(cuò)誤原因中看到,這條 SQL 語句是不符合 ONLY_FULL_GROUP_BY 的這條 SQL Mode 的。因?yàn)槲覀冎粚?duì) info 進(jìn)行分組了,沒有對(duì) id 進(jìn)行分組,我們把 SQL 語句改成如下形式 select id,info from cxuan005 group by id,info;
這樣 SQL 就能正確執(zhí)行了。 當(dāng)然,我們也可以刪除 sql_mode = ONLY_FULL_GROUP_BY 的這條 Mode,可以使用 來進(jìn)行刪除,刪除后我們使用分組語句就可以放飛自我了。 select id,info from cxuan005 group by info;
但是這種做法只是暫時(shí)的修改,我們可以修改配置文件 my.ini 中的 sql_mode= STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
這個(gè)模式需要注意下,如果啟用的話,需要 然后我們換表了,使用 cxuan003 這張表,表結(jié)構(gòu)如下
我們主要測(cè)試日期的使用,在 cxuan003 中插入一條日期為 insert into cxuan003 values(111,'study','0000-00-00');發(fā)現(xiàn)能夠執(zhí)行成功,但是把年月日各自變?yōu)?0 之后再進(jìn)行插入,則會(huì)插入失敗。
insert into cxuan003 values(111,'study','2021-01-00');
這些組合有很多,我這里就不再細(xì)致演示了,讀者可以自行測(cè)試。 如果要插入
SQL Mode 三種作用域SQL Mode 按作用區(qū)域和時(shí)間可分為 3。個(gè)級(jí)別,分別是會(huì)話級(jí)別,全局級(jí)別,配置(永久生效)級(jí)別。 我們上面使用的 SQL Mode 都是 全局域就是當(dāng)前會(huì)話關(guān)閉不失效,但是在 MySQL 重啟后失效。它的設(shè)置方式是 set global sql_mode='xx_mode';配置域就是在 配置域在保存退出后,重啟服務(wù)器,即可永久生效。 SQL 正則表達(dá)式正則表達(dá)式相信大家應(yīng)該都用過,不過你在 MySQL 中用過正則表達(dá)式嗎?下面我們就來聊一聊 SQL 中的正則表達(dá)式。
下面來演示一下正則表達(dá)式的用法
常見 SQL 技巧RAND() 函數(shù)大多數(shù)數(shù)據(jù)庫(kù)都會(huì)提供產(chǎn)生隨機(jī)數(shù)的函數(shù),通過這些函數(shù)可以產(chǎn)生隨機(jī)數(shù),也可以使用從數(shù)據(jù)庫(kù)表中抽取隨機(jī)產(chǎn)生的記錄,這對(duì)統(tǒng)計(jì)分析來說很有用。 在 MySQL 中,通常使用 我們新建一張表用于數(shù)據(jù)檢索。 然后插入一些數(shù)據(jù),插入完成后的數(shù)據(jù)如下。
然后我們可以使用 RAND() 函數(shù)進(jìn)行隨機(jī)檢索數(shù)據(jù)行 select * from clerk_info order by rand();檢索完成后的數(shù)據(jù)如下
多次查詢后發(fā)現(xiàn)每次檢索的數(shù)據(jù)順序都是隨機(jī)的。 這個(gè)函數(shù)多用于隨機(jī)抽樣,比如選取一定數(shù)量的樣本在進(jìn)行隨機(jī)排序,需要用到 GROUP BY + WITH ROLLUP我們經(jīng)常使用 GROUP BY 語句,但是你用過 我們?nèi)耘f對(duì) clerk_info 表進(jìn)行操作,我們對(duì) name 和 salary 進(jìn)行分組統(tǒng)計(jì)工資總數(shù)。
可以看到上面的表按照 name 進(jìn)行分組,然后再對(duì) money 進(jìn)行統(tǒng)計(jì)。 也就是說 GROUP BY 語句執(zhí)行完成后可以滿足用戶想要的任何一個(gè)分組以及分組組合的聚合信息值。
數(shù)據(jù)庫(kù)名、表名大小寫問題在 MySQL 中,數(shù)據(jù)庫(kù)中的每個(gè)表至少對(duì)應(yīng)數(shù)據(jù)庫(kù)目錄中的一個(gè)文件,當(dāng)然這取決于存儲(chǔ)引擎的實(shí)現(xiàn)了。不同的操作系統(tǒng)對(duì)大小寫的敏感性決定了數(shù)據(jù)庫(kù)和表名的大小寫的敏感性。在 UNIX 操作系統(tǒng)中是對(duì)大小寫敏感的,因此數(shù)據(jù)庫(kù)名和表名也是具有敏感性的,而到了 Windows 則不存在敏感性問題,因?yàn)?Windows 操作系統(tǒng)本身對(duì)大小寫不敏感。列、索引、觸發(fā)器在任何平臺(tái)上都對(duì)大小寫不敏感。 在 MySQL 中,數(shù)據(jù)庫(kù)名和表名是由
如果只在一個(gè)平臺(tái)上使用 MySQL 的話,通常不需要修改 外鍵問題這里需要注意一個(gè)問題, MySQL 常用函數(shù)下面我們來了解一下 MySQL 函數(shù),MySQL 函數(shù)也是我們?nèi)粘i_發(fā)過程中經(jīng)常使用的,選用合適的函數(shù)能夠提高我們的開發(fā)效率,下面我們就來一起認(rèn)識(shí)一下這些函數(shù) 字符串函數(shù)字符串函數(shù)是最常用的一種函數(shù)了,MySQL 也是支持很多種字符串函數(shù),下面是 MySQL 支持的字符串函數(shù)表
下面通過具體的示例演示一下每個(gè)函數(shù)的用法
上面把
數(shù)值函數(shù)MySQL 支持?jǐn)?shù)值函數(shù),這些函數(shù)能夠處理很多數(shù)值運(yùn)算。下面我們一起來學(xué)習(xí)一下 MySQL 中的數(shù)值函數(shù),下面是所有的數(shù)值函數(shù)
下面我們還是以實(shí)踐為主來聊一聊這些用法
日期和時(shí)間函數(shù)日期和時(shí)間函數(shù)也是 MySQL 中非常重要的一部分,下面我們就來一起認(rèn)識(shí)一下這些函數(shù)
下面結(jié)合示例來講解一下每個(gè)函數(shù)的使用
具體的日期格式可以參考這篇文章 https://blog.csdn.net/weixin_38703170/article/details/82177837 我們演示一下將當(dāng)前日期顯示為年月日的這種形式,使用的日期格式是 %M %D %Y。
interval 表示間隔類型的關(guān)鍵字,expr 是表達(dá)式,這個(gè)表達(dá)式對(duì)應(yīng)后面的類型,type 是間隔類型,MySQL 提供了 13 種時(shí)間間隔類型
DATE_DIFF(date1, date2) 用來計(jì)算兩個(gè)日期之間相差的天數(shù)
查看離 2021 - 01 - 01 還有多少天 流程函數(shù)流程函數(shù)也是很常用的一類函數(shù),用戶可以使用這類函數(shù)在 SQL 中實(shí)現(xiàn)條件選擇。這樣做能夠提高查詢效率。下表列出了這些流程函數(shù)
其他函數(shù) 除了我們介紹過的字符串函數(shù)、日期和時(shí)間函數(shù)、流程函數(shù),還有一些函數(shù)并不屬于上面三類函數(shù),它們是
下面來看一下具體的使用
總結(jié)這篇文章我?guī)闶职咽謹(jǐn)]了一波 MySQL 的高級(jí)內(nèi)容,其實(shí)說高級(jí)也不一定真的高級(jí)或者說難,其實(shí)就是區(qū)分不同梯度的東西。 |
|
|