MYSQL---複習準備

·數據庫的概念
DB:數據庫
DBMS:數據庫管理系統MYSQL,Oracle,DB2,sqlserver
SQL:結構化語句查詢
1.SQL語句的分類:
數據查詢語句(DQL)—slect
數據操縱(DML)—insert,truncate(delete),update
數據定義語言(DDL)–create,drop,alter
事務語句(DCL)–grant,revoke

·MYSQL安裝5.7.26-----結合PDF—文章末尾

  • window下啓動mysql : 管理員身份進入cmd 進入cd D:\soft\mysql-5.7.26-winx64\bin net start/stop mysql
  • 退出exit
  • window 登陸 mysql -uroot -p 123456
  • Linux 登陸 mysql -h 遠程主機號10.66.84.71 -u root -p 123456
  • 注意linux 登陸時候注意主機號!!!!!千萬不要找錯血一樣的教訓

在這裏插入圖片描述

1.入門指令:
2.常見函數

	a.字符函數:--------大小寫控制函數
LOWER('SQL HAha')====>(sql haha)
UPPER('sql  HHHH')=====>(SQL HHHH)
					     --------字符控制函數
CONCAT('hello','world')===>helloworld 
SUBSTR('HelloWorld',1,5)>Hello
LENGTH('HelloWorld')====>10
INSTR('HelloWorld','W')===>6
LPAD(salary,10,'*')=======>****salary 
RPAD(salary,10,'*')=======>salary****
TRIM('H' from 'HelloWorld')=>elloWorld
REPLACE('abcd','b','m')====>amcd
b.數字函數

 - ROUND:四捨五入
 		ROUND(45.926,2)------>45.93
 - TRUNCATE:截斷
 		TRUNC(45.926,2)------->45.92
 - MOD:求餘
 		MOD(1600,300)---------->300
 - now():獲取當前日期
c.條件表達式
IF-THEN-ELSE
case:查詢部門號爲10,20,30的員工信息,若部門號爲10,則打印工資爲其1.1倍數,20號部門,則打印工資爲1.2倍,30號部門則打印工資爲1.3倍
			select last_name,job_id,salary,
						CASE job_id WHEN 10 THEN 1.10*salary
											   WHEN 20 THEN 1.20*salary
											   	WHEN 30 THEN 1.30*salary
						ELSE salary END   "REVISED_SALARY"
										

3.子查詢
概念:出現在其他語句內部的select語句,稱爲子查詢,或者是內部查詢

單行子查詢
 - 1. 誰的工資比Abel高?
 	【SELECT  last_name FROM employees WHERE salary > all(SELECT salary FROM employee WHERE last_name = 'Abel'】
 - 2. 返回job_id與141員工號相同,salary比143號員工多的員工姓名,job_id 和 工資
 	【SELECT name,job_id,salary FROM employee WHERE job_id =141 AND salary >(select salary FROM employee WHERE department_id = 143) 】
 - 3. 返回工資最少員工的last_name,job_id和salary 
	【SELECT last_name,job_id,salary FROM employee WHERE salary = (SELECT MIN(salary) FROM employee 
 - 4. 查詢最低工資大於40號部門最低工資的部門id和他的最低工資】
 	 【SELECT department_id,MIN(salary) FROM employee GROUP BY department_id HAVING MIN(salary) > (SELECT MIN(salary)  FROM employee WHERE department_id = 40】 AND department_id <> 40
多行子查詢
IN/NOT IN------------------------------>列表中的任意一個
ANY | SOME--------------------------->和子查詢返回的某一個值比較
ALL--------------------------------------->和子查詢返回的所有數值比較

4.創建和管理表

  • 創建一個保存員工信息的數據庫
    - create database employees;
    - show databases:查看當前所有的數據庫
    - use employees:"使用"一個數據庫
CREATE TABLE dept(
				#表示自增
				deptno INT(2) AUTO_INCREMENT,
				dname VARCHAR(14),
				loc CARCHAR(13),
				#主鍵
				PRIMARY KEY(deptno);
				)

數據類型:
INT:使用四個字節保存整數數據
CHAR:定長字符數據,若未指定,默認一個字符,最大長度255
VARCHAR:可變字符數據,根據字符串實際長度保存
FLOAT(M,D):M+D<6
DOUBLE(M,D):M+D<15
DATE:日期數據格式
BLOB:二進制的長文本數據
TEXT:長文本數據

  • 使用子查詢創建表
複製現有的表:
		#複製數據
		CREATE TABLE emp1 AS  SELECT *FROM employee
		#複製表的結構
		CREATE TABLE emp1 AS  SELECT *FROM employee WHERE 1=2;
		#多表聯查
		SELECT * FORM A,B,C,D where
		
  • 向已經有的表中添加,修改,刪除,重命名現有表中的列
  • ALTER TABLE語句
追加一個新的列
		ALTER TABLE dept80
		ADD job_id VARCHAR(15);
可以修改列的數據類型,尺寸和默認值
		ALTER TABLE dept80
		MODIFY last_name VARCHAR(30);
	 MODIFY (salary double(9,2) default 1000);
  • 刪除一個列
  • DROP COLUMN
ALTER TABLE dept80
DROP COLUMN job_id;
  • 重新命名一個列
  • CHANGE old_name new_name 數據類型
ALTER TABLE dept80
CHANGE department_name dept_name VARCHAR(15);
  • 刪除一個表(數據和結構都刪除)
DROP TABLE dept80;
  • 清空一個表(結構不刪除)
  • TRUNCATE TABLE dept(不能夠回滾)
  • DELETE語句可以回滾
truncate table dept;
delete from emp2;
select * from emp2;
rollback ;
select * from emp2;
  • 改變表,視圖的名稱
ALTER table dept 
RENAME TO detail_dept;

5.約束和分頁
概念:

  • 爲了保證數據的一致性和完整性,SQL規範以約束的方式對錶數據進行額外 條件限制
  • 約束是表級的強制規定
  • 可以在創建表時規定約束,也可以在創建表以後進行約束,通過ALTER TABLE 語句

約束的種類:

  • NOT NULL非空約束
  • UNIQUE 唯一約束,規定某個字段在整個表中唯一
  • PRIMARY KEY 非空而且唯一
  • FOREIGN KEY 外鍵
  • CHECK 檢查約束----(MYSQL不支持)
  • DEFAULT 默認值
NULL:(ALTER TABLE  MODIFY )
1.非空約束用於確保當前列的值不爲空,非空約束只能夠出現在表對象的列上
2.NULL類型特徵值:
		>所有的類型值都可以是null,包括int,float
		>空字符串“ ”不等於NULL,0也不等於NULL;
UNIQUE:唯一約束允許出現多個空值:NULL
CREATE TABLE user (
		id INT NOT NULL,
		name VARCHAR(25),
		password VARCHAR(25),
		#使用表級約束語句法
		#表示name和password組合不能夠重複
		CONSTRAINT uk_name_ped UNIQUE(name,password)
		);
		-添加唯一的約束
		ALTER TABLE USER
		ADD UNIQUE(name,password);
		ALTER TABLE USER
		ADD CONSTRAINT uk_name_ped UNIQUE(name,password);
		-刪除約束
		ALTER TABLE user
		DROP INDEX uk_name_pwd
		
PRIMARY KEY ==唯一約束+非空約束
#列級模式
CREATE TABLE emp4(
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20)
);
#表級模式
CREATE TABLE emp5(
id INT AUTO_INCREMENT ,
name VARCHAR(20),
pwd VARCHAR(15),
CONSTRAINT emp5_id_pk PRIMARY KEY(id)
);
#組合模式
CREATE TABLE emp5(
id INT AUTO_INCREMENT ,
name VARCHAR(20),
pwd VARCHAR(15),
CONSTRAINT emp7_pk PRIMARY KEY(name,pwd)
);
-增,刪,改
ALTER TABLE sth
ADD/DROP /MODIFY

FOREIGN KEY(創建外鍵約束能夠聯表查詢)
========================================
CREATE TABLE emp4(
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20)
);
=======================================
CREATE TABLE dept(
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20)
);
CONSTRAINT dept_emp5_id_fk FOREIGN KEY(id)
REFERENCE emp4(id)
======================================
-增,刪除
		> ALTER TABLE emp
		   DROP FOREIGN KEY emp_dept_id_fk
		>ALTER  TABLE emp
		  ADD [CONSTRAINT emp_dept_id_fk] FOREIGN KEY(dept_id)  REFERENCE dept (dept_id);
======================================
		  -FOREIGN :指定子表中的列
		  -REFERENCE:標識父表中的列
		  -ON DELETE CASCADE(聯級刪除)當父親刪除時,子也應該刪除
		  -ON DELETE SET NULL:子表中相應的列置空
		  FORENIGN KEY (class_name,classes_number)
		  REFERENCE class(name,number) ON DELETE CASCADE
  • List item

分頁查詢-limit:必須放在整個查詢的最後面

前10條記錄:select * from table limit 0,10
前11條至20條記錄:select * from table limit 10,10
前21條至30條記錄:select *from table limit 20,10;

6.事務

>1. 事務的概念和特性
  • 事務:事務由單獨的單元的一個或者是多個SQL語句組成,在這個單元中,每個MYSQL語句是相互依賴的 而整個單獨單元作爲一個不可分隔的整體,如果單元中某條SQL語句一旦執行失敗或者產生錯誤,真個單元將會回滾。所有受到影響的數據將返回事物開始以前的狀態,如果單元中的所有SQL語句執行成功,則事務被順利進行

    MySQL中存儲引擎 [ 瞭解 ]

  • 概念:在mysql中的數據用各種不同的技術存儲在文件(或內存)中

  • 通過show engines 查看

  • MySQL中常用的引擎有:innodb,myisam,memory等。其中innodb支持事務,mysiam和memory不支持

2.事務的ACID屬性

  • 原子性
    事務是不可分隔的一個工作單位,事務操作中,要麼都發生,要麼都不發生
  • 一致性
    事務必須使數據庫從一個狀態轉換成爲另外一個狀態
  • 隔離性
    事務的隔離性是指事務的執行不能夠被其他事務干擾,也就是說一個事務內部的操作以及使用數據對併發其他事物是隔離的
  • 持久性
    持久性是指事務一旦被提交,他對數據庫中數據的改變就是永久性的,接下來的其他操作和數據庫故障不應該對其有任何影響
    在這裏插入圖片描述

數據庫提供四種事務的隔離級別:

  • -READ UNCOMMITTED:允許事務讀取未被其他事務提交的變更和髒讀,不可重複讀和幻讀都會出現

  • -READ COMMITED :只允許事務讀取已經被其他事務提交的變更,可以避免髒讀,但不可重複讀和幻讀問題仍然存

  • REPEATABLE READ:確保事務可以多次從一個字段中讀取相同的值,在這個事務持續期間,禁止其他事務對這個字段進行更改,避免了髒讀和不可重複度讀取,但是幻讀仍然存

  • SERIALIZABLE(串行化):確保事務可以從一個表中讀取相同的行,在這個事務持續期間,禁止其他事務對該表執行插入,更新和刪除,所有併發問題都解決,但是性能低下

  • Oracle支持兩種:READ COMMITED(讀取已經提交),SERIALIZABLE,默認事務隔離級別:READ COMMITED

  • Mysql支持4種,默認級別爲:REPEATABL EREAD

  • 查看當前隔離級別:SELECT @@tx_isolation

  • 設置當前連接的隔離級別:set transation isolation level read committed

7.數據庫範式

  • 第一範式(1NF):列不可分,eg:【聯繫人】(姓名,性別,電話),一個聯繫人有家庭電話和公司電話,那麼這種表結構設計就沒有達到 1NF

  • 第二範式(2NF):有主鍵,保證完全依賴。eg:訂單明細表【OrderDetail】(OrderID,ProductID,UnitPrice,Discount,Quantity,ProductName),Discount(折扣),Quantity(數量)完全依賴(取決)於主鍵(OderID,ProductID),而 UnitPrice,ProductName 只依賴於 ProductID,不符合2NF;

  • 第三範式 (3NF):無傳遞依賴(非主鍵列 A 依賴於非主鍵列 B,非主鍵列 B 依賴於主鍵的情況),eg:訂單表【Order】(OrderID,OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity)主鍵是(OrderID),CustomerName,CustomerAddr,CustomerCity 直接依賴的是 CustomerID(非主鍵列),而不是直接依賴於主鍵,它是通過傳遞才依賴於主鍵,所以不符合 3NF。

9.存儲過程和函數的區別是什麼

存儲過程是用戶定義的一系列SQL語句的集合,涉及特定的表或者其他對象的任務,用戶可以調用存儲過程。而函數通常是數據庫已經定義的方法,它接收
參數,並且返回某種類型的值,並不涉及特定用戶表

10.遊標的作用,如何知道遊標已經到達最後了呢??

遊標用於定位結果集的行,通常判斷全局變量@@FETCH_STATUS可以判斷其是否到了最後,通常此變量不等於0表示出錯或者到了最後

11.觸發器分爲事前觸發和事後觸發,這兩種觸發有何區別?語句級觸發和行級觸發有何區別?

觸發器是與表相關的數據庫對象,在滿足定義條件時觸發,並執行觸發器中定義的語句集合。觸發器的這種特性可以協助應用在數據庫端確保數據庫的完整性。
  事前觸發運行於事前觸發之前,事後觸發運行於觸發之後,語句級觸發,可以運行在語句執行前或者執行之後,行級觸發在觸發器所影響的每一行觸發一次

12.什麼叫做SQL注入式攻擊,如何防範?

所謂注入式攻擊指的是,攻擊者把SQL命令插入到Web表單的輸入域或者頁面請求的查詢字符串中,欺騙服務器執行惡意的SQL命令,在某些表單中用戶輸入內容直接用來構造(或者影響)動態SQL命令,或者作爲存儲過程的輸入參數,這類表單特別容易受到注入式攻擊
防範SQL注入式攻擊並不是一件特別困難的事情,只要在表單輸入的內容構造SQL命令之前,把所有輸入內容過濾一遍就夠了,過濾輸入內容可以按照多種方法進行。
-用來執行查詢的數據庫賬號限制其權限 -將用戶登陸的名字,密碼等數據進行加密
-檢查輸入用戶的合法性,確定輸入內容只包含合法的數據

13.數據庫索引
索引是對數據庫表中一個或多個列的值進行排序的數據結構,以協助快速查詢、更新數據庫表中數據。索引的實現通常使用B_TREE及其變種。索引加速了數據訪問,因爲存儲引擎不會再去掃描整張表得到需要的數據;相反,它從根節點開始,根節點保存了子節點的指針,存儲引擎會根據指針快速尋找數據。
14.索引有哪些結構
Hash索引和B+ Tree索引(5.7版本後InnoDB默認)

問:爲什麼採用B+ 樹嗎?這和Hash索引比較起來有什麼優缺點嗎?

答:因爲Hash索引底層是哈希表,哈希表是一種以key-value存儲數據的結構,所以多個數據在存儲關係上是完全沒有任何順序關係的,所以,對於區間查詢是無法直接通過索引查詢的,就需要全表掃描。所以,哈希索引只適用於等值查詢的場景。而B+ 樹是一種多路平衡查詢樹,所以他的節點是天然有序的(左子節點小於父節點、父節點小於右子節點),所以對於範圍查詢的時候不需要做全表掃描

1、哈希索引適合等值查詢,但是無法進行範圍查詢
2、哈希索引沒辦法利用索引完成排序
3、哈希索引不支持多列聯合索引的最左匹配規則
4、如果有大量重複鍵值的情況下,哈希索引的效率會很低,因爲存在哈希碰撞問題

15.問:文件和數據庫爲什麼採用B+ 樹,不採用紅黑樹?
 文件與數據庫都是需要較大的存儲,也就是說,它們都不可能全部存儲在內存中,故需要存儲到磁盤上。而所謂索引,則爲了數據的快速定位與查找,那麼索引的結構組織要儘量減少查找過程中磁盤I/O的存取次數,因此B+樹相比B樹更爲合適。數據庫系統巧妙利用了局部性原理與磁盤預讀原理,將一個節點的大小設爲等於一個頁,這樣每個節點只需要一次I/O就可以完全載入,而紅黑樹這種結構,高度明顯要深的多,並且由於邏輯上很近的節點(父子)物理上可能很遠,無法利用局部性。最重要的是,B+樹還有一個最大的好處:方便掃庫。B樹必須用中序遍歷的方法按序掃庫,而B+樹直接從葉子結點挨個掃一遍就完了,B+樹支持range-query非常方便,而B樹不支持,這是數據庫選用B+樹的最主要原因。
 
16.B樹,B+樹,紅黑樹,AVL樹,的特點以及區別
(1). B-Tree(平衡多路查找樹)
 B_TREE是一種平衡多路查找樹,是一種動態查找效率很高的樹形結構。B_TREE中所有結點的孩子結點的最大值稱爲B_TREE的階,B_TREE的階通常用m表示,簡稱爲m叉樹。一般來說,應該是m>=3。一顆m階的B_TREE或是一顆空樹,或者是滿足下列條件的m叉樹:

  • 樹中每個結點最多有m個孩子結點;
  • 若根結點不是葉子節點,則根結點至少有2個孩子結點;
  • 除根結點外,其它結點至少有(m/2的上界)個孩子結點;
    B_TREE的查找類似二叉排序樹的查找,所不同的是B-樹每個結點上是多關鍵碼的有序表,在到達某個結點時,先在有序表中查找,若找到,則查找成功;否則,到按照對應的指針信息指向的子樹中去查找,當到達葉子結點時,則說明樹中沒有對應的關鍵碼。由於B_TREE的高檢索效率,B-樹主要應用在文件系統和數據庫中,對於存儲在硬盤上的大型數據庫文件,可以極大程度減少訪問硬盤次數,大幅度提高數據檢索效率

2)B+Tree : InnoDB存儲引擎的索引實現
  B+Tree是應文件系統所需而產生的一種B_TREE樹的變形樹。一棵m階的B+樹和m階的B_TREE的差異在於以下三點:

  • n 棵子樹的結點中含有n個關鍵碼;
  • 所有的葉子結點中包含了全部關鍵碼的信息,及指向含有這些關鍵碼記錄的指針,且葉子結點本身依關鍵碼的大小自小而大的順序鏈接;
  • 非終端結點可以看成是索引部分,結點中僅含有其子樹根結點中最大(或最小)關鍵碼。
      通常在B+樹上有兩個頭指針,一個指向根節點,另一個指向關鍵字最小的葉子節點。因此可以對B+樹進行兩種查找運算:一種是從最小關鍵字起順序查找,另一種是從根節點開始,進行隨機查找。
      在B+樹上進行隨機查找、插入和刪除的過程基本上與B-樹類似。只是在查找時,若非終端結點上的關鍵碼等於給定值,並不終止,而是繼續向下直到葉子結點。因此,對於B+樹,不管查找成功與否,每次查找都是走了一條從根到葉子結點的路徑

(3). 爲什麼說B±tree比B 樹更適合實際應用中操作系統的文件索引和數據庫索引?

  • B+tree的磁盤讀寫代價更低:B+tree的內部結點並沒有指向關鍵字具體信息的指針(紅色部分),因此其內部結點相對B
    樹更小。如果把所有同一內部結點的關鍵字存放在同一盤塊中,那麼盤塊所能容納的關鍵字數量也越多。一次性讀入內存中的需要查找的關鍵字也就越多,相對來說IO讀寫次數也就降低了;
  • B+tree的查詢效率更加穩定:由於內部結點並不是最終指向文件內容的結點,而只是葉子結點中關鍵字的索引,所以,任何關鍵字的查找必須走一條從根結點到葉子結點的路。所有關鍵字查詢的路徑長度相同,導致每一個數據的查詢效率相當;
  • 數據庫索引採用B+樹而不是B樹的主要原因:B+樹只要遍歷葉子節點就可以實現整棵樹的遍歷,而且在數據庫中基於範圍的查詢是非常頻繁的,而B樹只能中序遍歷所有節點,效率太低。

18.索引的優點

  • 大大加快數據的檢索速度,這也是創建索引的最主要的原因;
  • 加速表和表之間的連接;
  • 在使用分組和排序子句進行數據檢索時,同樣可以顯著減少查詢中分組和排序的時間;
  • 通過創建唯一性索引,可以保證數據庫表中每一行數據的唯一性

19.什麼情況下設置了索但是無法使用

  • 以“%(表示任意0個或多個字符)”開頭的LIKE語句,模糊匹配;
  • OR語句前後沒有同時使用索引;
  • 數據類型出現隱式轉化(如varchar不加單引號的話可能會自動轉換爲int型);
  • 對於多列索引,必須滿足 最左匹配原則 (eg:多列索引col1、col2和col3,則 索引生效的情形包括 col1或col1,col2或col1,col2,col3)。

20.什麼樣的字段適合創建索引?

  • 經常作查詢選擇的字段
  • 經常作表連接的字段
  • 經常出現在order by, group by, distinct 後面的字段

21.索引有哪些索引

  • 主鍵索引(聚集索引)
  • 普通索引
  • 唯一索引
  • 全文索引
    聚集索引和非聚集索引的區別

聚集索引的順序就是數據的物理存儲順序,而非聚集索引的解釋是索引順序與物理存儲數據無關,正因爲如此一個表中最多一個聚集索引
SQLserver中索引是用二叉樹的數據結構描述的,我們可以這樣理解聚集索引,索引的葉節點就是數據節點,而非聚集索引的葉節點仍然是索引節點,只不過有一個指針指向對應的數據

22. 索引的缺點

  • 時間方面:創建索引和維護索引要耗費時間,具體地,當對錶中的數據進行增加、刪除和修改的時候,索引也要動態的維護,這樣就降低了數據的維護速度;
  • 空間方面:索引需要佔物理空間

23.主鍵、自增主鍵、主鍵索引與唯一索引概念區別
主鍵:指字段 唯一、不爲空值 的列;

主鍵索引:指的就是主鍵,主鍵是索引的一種,是唯一索引的特殊類型。創建主鍵的時候,數據庫默認會爲主鍵創建一個唯一索引;

自增主鍵:字段類型爲數字、自增、並且是主鍵;

唯一索引:索引列的值必須唯一,但允許有空值。主鍵是唯一索引,這樣說沒錯;但反過來說,唯一索引也是主鍵就錯誤了,因爲唯一索引允許空值,主鍵不允許有空值,所以不能說唯一索引也是主鍵。

24.主鍵就是聚集索引嗎?主鍵和索引有什麼區別?
  主鍵是一種特殊的唯一性索引,其可以是聚集索引,也可以是非聚集索引。在SQLServer中,主鍵的創建必須依賴於索引,默認創建的是聚集索引,但也可以顯式指定爲非聚集索引。InnoDB作爲MySQL存儲引擎時,默認按照主鍵進行聚集,如果沒有定義主鍵,InnoDB會試着使用唯一的非空索引來代替。如果沒有這種索引,InnoDB就會定義隱藏的主鍵然後在上面進行聚集。所以,對於聚集索引來說,你創建主鍵的時候,自動就創建了主鍵的聚集索引

25.實踐中如何優化數據庫
   實踐中,MySQL的優化主要涉及SQL語句及索引的優化、數據表結構的優化、系統配置的優化和硬件的優化四個方面,如下圖所示:
   在這裏插入圖片描述
  
26.簡單說一說drop、delete與truncate的區別
SQL中的drop、delete、truncate都表示刪除,但是三者有一些差別:

  • Delete用來刪除表的全部或者一部分數據行,執行delete之後,用戶需要提交(commmit)或者回滾(rollback)來執行刪除或者撤銷刪除, delete命令會觸發這個表上所有的delete觸發器;
  • Truncate刪除表中的所有數據,這個操作不能回滾,也不會觸發這個表上的觸發器,TRUNCATE比delete更快,佔用的空間更小;
  • Drop命令從數據庫中刪除表,所有的數據行,索引和權限也會被刪除,所有的DML觸發器也不會被觸發,這個命令也不能回滾。

因此,在不再需要一張表的時候,用drop;在想刪除部分數據行時候,用delete;在保留表而刪除所有數據的時候用truncate。

27、MySQL中的悲觀鎖與樂觀鎖的實現
悲觀鎖與樂觀鎖是兩種常見的資源併發鎖設計思路,也是併發編程中一個非常基礎的概念。

(1). 悲觀鎖
  悲觀鎖的特點是先獲取鎖,再進行業務操作,即“悲觀”的認爲所有的操作均會導致併發安全問題,因此要先確保獲取鎖成功再進行業務操作。通常來講,在數據庫上的悲觀鎖需要數據庫本身提供支持,即通過常用的select … for update操作來實現悲觀鎖。當數據庫執行select … for update時會獲取被select中的數據行的行鎖,因此其他併發執行的select … for update如果試圖選中同一行則會發生排斥(需要等待行鎖被釋放),因此達到鎖的效果。select for update獲取的行鎖會在當前事務結束時自動釋放,因此必須在事務中使用。
  這裏需要特別注意的是,不同的數據庫對select… for update的實現和支持都是有所區別的,例如oracle支持select for update no wait,表示如果拿不到鎖立刻報錯,而不是等待,mysql就沒有no wait這個選項。另外,mysql還有個問題是: select… for update語句執行中所有掃描過的行都會被鎖上,這一點很容易造成問題。因此,如果在mysql中用悲觀鎖務必要確定使用了索引,而不是全表掃描。

(2). 樂觀鎖
  樂觀鎖的特點先進行業務操作,只在最後實際更新數據時進行檢查數據是否被更新過,若未被更新過,則更新成功;否則,失敗重試。樂觀鎖在數據庫上的實現完全是邏輯的,不需要數據庫提供特殊的支持。一般的做法是在需要鎖的數據上增加一個版本號或者時間戳,然後按照如下方式實現:

1. SELECT data AS old_data, version AS old_version FROM …;
2. 根據獲取的數據進行業務操作,得到new_data和new_version
3. UPDATE SET data = new_data, version = new_version WHERE version = old_version
if (updated row > 0) {
    // 樂觀鎖獲取成功,操作完成
} else {
    // 樂觀鎖獲取失敗,回滾並重試
}

樂觀鎖是否在事務中其實都是無所謂的,其底層機制是這樣:在數據庫內部update同一行的時候是不允許併發的,即數據庫每次執行一條update語句時會獲取被update行的寫鎖,直到這一行被成功更新後才釋放。因此在業務操作進行前獲取需要鎖的數據的當前版本號,然後實際更新數據時再次對比版本號確認與之前獲取的相同,並更新版本號,即可確認這其間沒有發生併發的修改。如果更新失敗,即可認爲老版本的數據已經被併發修改掉而不存在了,此時認爲獲取鎖失敗,需要回滾整個業務操作並可根據需要重試整個過程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章