MySQL的事務和索引
阿新 • • 發佈:2020-07-20
目錄
MySQL的事務-TCL(Transaction)
什麼是事務
一個事務是一個完整的業務邏輯單元,不可再分。 比如:銀行賬戶轉賬,從A賬戶向B賬戶轉賬10000,需要執行兩條update語句: update t_act set balance = balance - 10000 where actno = 'act-001'; update t_act set balance = balance + 10000 where actno = 'act-001'; 以上兩條DML語句必須同時成功,或者同時失敗,不允許出現一條成功,一條失敗。 要想保證以上的兩條DML語句同時成功或者同時失敗,那麼就需要使用資料庫的“事務機制”。
和事務相關的語句只有:DML語句。(insert delete update)
為什麼?因為它們這三個語句都是和資料庫表當中的“資料”相關的。
事務的存在是為了保證資料的完整性,安全性。
假設所有的業務都能使用1條DML語句搞定,還需要事務機制嗎?
不需要事務。
但實際情況不是這樣的。通常一個事務(業務)需要更多DML語句共同聯合完成。
事物的特性
事務包括四大特性:ACID A:原子性:事務是最小的工作單元,不可再分。 C:一致性:事務必須保證多條DML語句同時成功或者同時失敗。 I:隔離性:事務A與事務B之間具有隔離。 D:永續性:永續性說的是最終資料必須持久化到硬碟檔案中,事務才算成功的結束。
事務之間的隔離性
事務隔離性存在隔離級別,理論上隔離級別包括4個: 第一級別:讀未提交(read uncommitted) 對方事務還沒有提交,我們當前事務可以讀取到對方未提交的資料。 對方提交存在髒讀(Dirty Read)現象:表示堵到了髒的資料。 第二級別:讀已提交(read committed) 對方事務提交之後的資料我方可以讀取到。 這種隔離級別解決了髒讀現象。 讀已提交存在的問題是:不可重複讀。 第三級別:可重複讀(repeatable read) 這種隔離級別解決了不可重複讀問題。 這種隔離級別存在的問題是:讀取到的資料是幻想。 第四級別:序列化讀/序列化讀 解決了所有問題 效率低,需要事務排隊。 Oracle資料預設的隔離級別是:讀已提交。 MySQL資料庫預設的隔離級別是:可重複讀。
驗證隔離級別
設定事務的全域性隔離級別:
set global transaction isolation level 隔離級別;
檢視事務的全域性隔離級別:
select @@global.tx_isolation;
現表內資料:
mysql> select * from person;
+----+----------+
| id | name |
+----+----------+
| 1 | ZHANGSAN |
| 2 | LISI |
| 3 | WANGWU |
+----+----------+
3 rows in set (0.00 sec)
讀未提交-read uncommitted
需要先設定隔離級別為read uncommitted(讀未提交)set global transaction isolation level read uncommitted
設定完成後需要exit退出一下再進入執行一下命令
讀已提交-read committed
序列化-serializable
使用者A
mysql> select @@global.tx_isolation; //第一步:檢視到當前隔離級別
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| SERIALIZABLE |
+-----------------------+
1 row in set (0.00 sec)
mysql> use test;
Database changed
mysql> select * from person; //第二步:查詢表內容
+----+----------+
| id | name |
+----+----------+
| 1 | ZHANGSAN |
| 2 | LISI |
| 3 | WANGWU |
+----+----------+
3 rows in set (0.00 sec)
mysql> start transaction; //第三步:關閉自動提交機制
Query OK, 0 rows affected (0.00 sec)
mysql> select * from person; //第六步:當用戶在person表內插入了新的內容,查詢person表全部資訊會發現游標在閃爍,一直等到使用者commit後才會查詢到 +----+----------+ person表的全部內容
| id | name |
+----+----------+
| 1 | ZHANGSAN |
| 2 | LISI |
| 3 | WANGWU |
| 9 | XIAOHUA |
+----+----------+
4 rows in set (10.66 sec)
使用者B
mysql> use test;
Database changed
mysql> start transaction; //第四步:關閉自動提交機制
Query OK, 0 rows affected (0.00 sec)
mysql> insert into person(name) values('XIAOHUA'); //第五步:插入新內容
Query OK, 1 row affected (0.00 sec)
mysql> commit; //第七步:提交
Query OK, 0 rows affected (0.01 sec)
可重複讀-repeatable read
演示事務
- start transaction 關閉自動提交機制 ,
- rollback 回滾機制
- commit 提交機制
mysql事務預設情況下是自動提交的。(什麼是自動提交?只要執行任意一條DML語句則提交一次。)怎麼關閉自動提交? start transaction;
準備表:
drop table if exists t_user;
create table t_user(
id int primary key auto_increment,
username varchar(255)
);
演示:當沒有使用 回滾和提交機制
mysql> insert into t_user(username) values('zhangsan');
Query OK, 1 row affected (0.01 sec)
mysql> select * from t_user;
+----+----------+
| id | username |
+----+----------+
| 1 | zhangsan |
+----+----------+
1 row in set (0.00 sec)
mysql> rollback; //回滾後資料沒有發生改變
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t_user;
+----+----------+
| id | username |
+----+----------+
| 1 | zhangsan |
+----+----------+
1 row in set (0.00 sec)
演示:使用 start transaction; 關閉自動提交機制.
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into t_user(username) values('lisi');
Query OK, 1 row affected (0.00 sec)
mysql> select * from t_user;
+----+----------+
| id | username |
+----+----------+
| 1 | zhangsan |
| 2 | lisi |
+----+----------+
2 rows in set (0.00 sec)
mysql> rollback; //因為關閉了自動提交機制,所以回滾後發現剛才插入的資料刪除了。
Query OK, 0 rows affected (0.01 sec)
mysql> select * from t_user;
+----+----------+
| id | username |
+----+----------+
| 1 | zhangsan |
+----+----------+
1 row in set (0.00 sec)
演示:使用 commit; 提交機制
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into t_user(username) values('jack'),('rose');
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from t_user;
+----+----------+
| id | username |
+----+----------+
| 1 | zhangsan |
| 3 | jack |
| 4 | rose |
+----+----------+
3 rows in set (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.01 sec)
mysql> rollback; //當commit提交過後 就會發現回滾資料沒有發生改變
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t_user;
+----+----------+
| id | username |
+----+----------+
| 1 | zhangsan |
| 3 | jack |
| 4 | rose |
+----+----------+
3 rows in set (0.00 sec)
索引
什麼是索引?有什麼用?
索引就相當於一本書的目錄,通過目錄可以快速的找到對應的資源。
在資料庫方面,查詢一張表的時候有兩種檢索方式:
第一種方式:全表掃描
第二種方式:根據索引檢索(效率很高)
索引為什麼可以提高檢索效率呢?
其實最根本的原理是縮小了掃描的範圍。
索引雖然可以提高檢索效率,但是不能隨意的新增索引,因為索引也是資料庫當中的物件,也需要資料庫不斷的維護。是有維護成本的。比如:表中的資料經常被修改這樣就不適合新增索引,因為資料一旦修改,索引需要重新排列,進行維護。
如何建立和刪除索引?
建立索引物件:
create index 索引名稱 on 表名(欄位名;
刪除索引物件:
drop index 索引名稱 on 表名;
什麼時候給欄位新增索引?
資料量龐大(根據客戶的要求,根據線上的環境)
該欄位很少的DML操作(因為欄位進行修改操作,索引也需要維護)
該欄位經常出現在where子句中(經常根據哪個欄位查詢)
注意:主鍵和具有unique約束的欄位自動回新增索引。
根據主鍵查詢效率較高,儘量根據主鍵檢索。
檢視sql語句的執行計劃
mysql> explain select ename,sal from emp where sal=5000;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | emp | ALL | NULL | NULL | NULL | NULL | 14 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
給薪資sal欄位新增索引:
mysql> create index emp_sal_index on emp(sal);
mysql> explain select ename,sal from emp where sal=5000; // 查詢後會發現檢索方式不是ALL而是ref了 檢索條目rows不是14而是1了
+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+
| 1 | SIMPLE | emp | ref | emp_sal_index | emp_sal_index | 9 | const | 1 | Using where |
+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+
索引的實現原理
索引的底層採用的資料結構是:B + Tree
通過B Tree縮小掃描範圍,底層索引進行了排序、分割槽,索引回攜帶資料在表中的“實體地址”,最終通過索引檢索到資料之後,獲取到關聯的實體地址,通過實體地址定位表中的資料,效率是最高的。
select ename from emp where ename = 'SMITH';
通過索引轉換為:
select ename from emp where 實體地址 = 0x123;
索引的分類
單一索引:給單個欄位新增索引
複合索引:給多個欄位聯合新增1個索引
主鍵索引:主鍵上會自動新增索引
唯一索引:有unique約束的欄位上會自動新增索引
索引什麼時候會失效?
select ename from emp where ename like '%A%';
模糊查詢的時候,第一個萬用字元使用的是%,這個時候索引是失效的。