1. 程式人生 > 實用技巧 >【STM32F429】第13章 ThreadX GUIX視窗任意位置繪製2D圖形

【STM32F429】第13章 ThreadX GUIX視窗任意位置繪製2D圖形

資料庫中事務的重要性,就不多說了!本篇博文主要針對MySQL資料庫介紹事務的重要性!

一、事務概述

事務是程式中一系列嚴密的操作,所有操作執行必須成功完成,否則每個操作所有的更改將會被撤銷,這也是事務的原子性(要麼成功,要麼失敗)。

MySQL的事務是在儲存引擎曾實現的。MySQL的事務有ACID:

  • A:原子性(atomicity):一個事務必須被視為一個不可分割的單元;
  • C:一致性(consistency):資料庫是從一種狀態切換到另一種狀態;
  • I:隔離性(isolation):事務在提交之前,對於其他事務不可見;
  • D:永續性(durablity):一旦事務提交,所修改的將永久儲存到資料庫;

二、事務的基本語法

2.1 示例

mysql> create table bank (
    -> name varchar(25),
    -> money float );
#建立表
mysql> insert into bank values('lu','1000'),('qi','5000');
#插入資料
mysql> select * from bank;
+------+-------+
| name | money |
+------+-------+
| lu   |  1000 |
| qi   |  5000 |
+------+-------+
#檢視資料
mysql> begin;
#begin開啟事務,start transaction也可開啟事務
mysql> update bank set money=money - 1000 where name='qi';
mysql> update bank set money=money+1000 where name ='lu';
#更新資料
mysql> select * from bank;
+------+-------+
| name | money |
+------+-------+
| lu   |  2000 |
| qi   |  4000 |
+------+-------+
#檢視資料
mysql> rollback;
#回滾事務
mysql> select * from bank;
+------+-------+
| name | money |
+------+-------+
| lu   |  1000 |
| qi   |  5000 |
+------+-------+
#再次查詢資料,發現已經便會了原來的值
mysql> commit;
#提交事務
mysql> select * from bank;
+------+-------+
| name | money |
+------+-------+
| lu   |  1000 |
| qi   |  5000 |
+------+-------+
#查詢資料

一個事務涉及到的命令:

  • 事務的開始:start transaction或begin;
  • 事務提交:commit;
  • 事務回滾:rollback;

2.2 檢視提交模式並更改

mysql> show variables like 'AUTOCOMMIT';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
#ON表示自動提交
mysql> set AUTOCOMMIT=0;
#關閉自動提交,0是關閉,1是開啟
mysql> show variables like 'AUTOCOMMIT';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | OFF   |
+---------------+-------+
#OFF表示已經關閉自動提交

2.3 事務的四種隔離級別

事務在提交之前對其他事務不可見。

  • read unaommitted(未提交讀)
  • read committed(已提交讀)
  • Repeatable read(可重複讀)
  • seaializable(可序列化)

2.4 未提交讀

事務中修改沒有提交對其他事務也是可見的,俗稱髒讀。

mysql> create table student (
    -> id int not null auto_increment,
    -> name varchar(32) not null default '',
    -> primary key(id)
    -> )engine=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
#建立測試表

接下來需要自行開啟兩個MySQL會話終端,A和B,兩個終端都需執行以下命令:

mysql> set session tx_isolation='read-uncommitted';
#設定為未提交讀

客戶端A

mysql> begin;
mysql> select * from student;
mysql> insert into student(name) values('zhangsan');
#注意,此時事務未提交

客戶端B

mysql> select * from student;
+----+----------+
| id | name     |
+----+----------+
|  2 | zhangsan |
+----+----------+
#查詢表,即可看到客戶A沒有提交的事務

總結:以上可以看出未提交讀隔離級別非常危險,對於一個沒有提交事務所做修改對另一個事務是可見狀態,出現了髒讀!非特殊情況不建議使用此級別。

2.5 已提交讀

多數資料庫系統預設為此級別(MySQL不是)。已提交讀級別為一個事務只能已提交事務所做的修改,也就是解決了未提交讀的問題。

需執行完成以下命令,再進行測試!

mysql> set session tx_isolation='read-committed';
#設定為已提交讀

客戶端A

mysql> begin;
mysql> select * from student;
+----+----------+
| id | name     |
+----+----------+
|  2 | zhangsan |
+----+----------+
mysql> insert into student(name) values('lisi');
mysql> select * from student;
+----+----------+
| id | name     |
+----+----------+
|  2 | zhangsan |
|  4 | lisi     |
+----+----------+

客戶端B

mysql> select * from student;
+----+----------+
| id | name     |
+----+----------+
|  2 | zhangsan |
+----+----------+
#並沒有檢視到客戶端A剛剛插入的資料

客戶端A

mysql> commit;

客戶端B

mysql> select * from student;
+----+----------+
| id | name     |
+----+----------+
|  2 | zhangsan |
|  4 | lisi     |
+----+----------+
#客戶端A提交完成後便可檢視到已經更新的資料

總結:從上面可以看出,提交讀沒有了未提交讀的問題,但是我們可以看到客戶端A的一個事務中客戶端B執行了兩次同樣的SELECT語句,得到不同的結果,因此已提交讀又被稱為不可重複讀。同樣的篩選條件可能得到不同的結果。

2.6 可重複讀

可重複讀解決了不可重複讀的問題,資料庫級別沒有解決幻讀的問題。

以下是客戶端A和客戶端B同時操作(都設定為可重複讀,然後兩邊都開啟一個事務):

mysql>  set session tx_isolation='repeatable-read';
mysql>  begin;

客戶端A

mysql> select * from student;
+----+----------+
| id | name     |
+----+----------+
|  2 | zhangsan |
|  4 | lisi     |
+----+----------+
mysql> update student set name='wangwu' where id=5;
mysql> commit;
mysql> select * from student;
+----+----------+
| id | name     |
+----+----------+
|  2 | zhangsan |
|  4 | wangwu   |
+----+----------+

客戶端B

mysql> select * from student;
+----+----------+
| id | name     |
+----+----------+
|  2 | zhangsan |
|  4 | lisi     |
+----+----------+
mysql> commit;
mysql> select * from student;
+----+----------+
| id | name     |
+----+----------+
|  2 | zhangsan |
|  4 | wangwu   |
+----+----------+
即可看到客戶端A更新的資料

總結:上面可以看出,可重複讀兩次讀取的內容不一樣。資料庫的幻讀問題並沒有得到解決。幻讀只讀鎖定裡面的資料,不能讀鎖定外的資料,解決幻讀出了mvcc機制Mvcc機制。

2.7 可序列化

是最高隔離級別,強制事務序列執行,執行串行了也就解決問題了,這個只有在對資料一致性要求非常嚴格並且沒有併發的情況下使用。

在客戶端A及客戶端B進行以下操作(設定為可序列讀):

mysql> set session tx_isolation='serializable';

客戶端A

mysql> begin;
mysql> select * from student where id < 5;
+----+----------+
| id | name     |
+----+----------+
|  2 | zhangsan |
|  4 | wangwu   |
+----+----------+

客戶端B

mysql> insert into student(name) values('maliu');
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
#此時進行插入操作時,會一直卡在這裡,然後出現下面的報錯資訊,除非客戶端Acommit提交事務

總結:我們發現INSERT 語句被阻塞執行,原因是A執行了查詢表student同時滿足id<10,已被鎖定。如果查詢表student同時滿足id<5,則新增語句可以正常執行。

以上幾種的隔離界別對比如下:

隔離級別 髒讀 不可重複 幻讀 加鎖讀
未提交讀
提交讀
可重複讀
序列讀