Mysql基礎_SQL語言
1. DQL語言的學習
① 基礎查詢
/* 語法: select 查詢列表 from 表名; 特點: ① 通過select查詢完的結果 ,是一個虛擬的表格,不是真實存在 ② 要查詢的東西 可以是常量值、可以是表示式、可以是欄位、可以是函式 ③ 可以沒有from語句 ④ 先執行from語句,再執行select查詢 */ #✳查詢單個欄位 select 欄位名 from 表名; #✳查詢多個欄位 select 欄位1,欄位2,...,欄位n from 表名; #✳查詢所有欄位(查詢整個表資料) select * from 表名; #雖然這種方式比較簡單,但是為了提高可讀性,建議不使用*,而是列出所有欄位。 #✳查詢時給欄位起別名(as) select 欄位1 【as】 別名1,欄位2 【as】 別名2... from 表; #其中as可以省略,直接用空格 #✳查詢結果去重(distinct) select distinct 欄位 from 表;
② 條件查詢
/* 條件查詢:根據條件過濾原始表的資料,查詢到想要的資料 語法: select 查詢列表 from 表名 where 篩選條件; 特點:先執行from語句,在執行where語句,最後執行select語句 分類: 一、✔條件表示式 > < >= <= = != <> <=>安全等於 between 值1 and 值2 篩選所需要的值在值1和值2之間,等同於 >=值1 and <=值2 is null /is not null 用於判斷null值(也只能判斷null值) in / not in in是指包含,後面接(值1,值2...),相當於多個or,但效率更高 注意:安全等於<=>可以判斷null值,而=不能判斷null值 示例:篩選學生表中:姓名為張三的所有資訊。 select * from students where name='張三'; 二、✔邏輯表示式 and(&&):兩個條件如果同時成立,結果為true,否則為false or(||):兩個條件只要有一個成立,結果為true,否則為false not(!):如果條件成立,則not後為false,否則為true 示例:篩選學生表中:分數在60和70之間的學生全部資訊。 select * from students where score>=60 and scord<=70; 三、✔模糊查詢 like: 通常搭配萬用字元使用 萬用字元:%任意多個字元,_任意單個字元(%不能表示null) 示例:篩選學生表中:姓名第二個字為偉的學生全部資訊 select * from students where name like '_偉%'; */
③ 排序查詢
/* 排序查詢:對查詢的結果按某一欄位進行排序。 語法: select 查詢列表 from 表 【where 篩選條件】 order by 排序的欄位|表示式|函式|別名 【asc|desc】; 特點: ① 可以沒有where篩選語句 ② asc值升序,desc指降序,如果不寫預設為升序 ③ 排序列表支援單個欄位、多個欄位、函式、表示式、別名 ④ order by的位置一般放在查詢語句的最後(除limit語句之外) ⑤ 先執行from語句,再執行where語句,然後執行select,最後執行order by排序 */ #示例:查詢學生表中:所有姓張的學生全部資訊,並按照考試成績進行降序排列 select * from students where name like '張%' order by score desc;
④ 常見函式
1) 單行函式
-
concat: 將多個欄位/字元進行拼接。
#語法:concat(欄位/字元1,欄位/字元2,...,欄位/字元n) #示例:查詢學生表中:所有學生的姓名和成績,並顯示為一列,格式示範:張三(98分) select concat(name,'(',score,'分)') as 姓名(分數) from students;
-
ifnull:判斷某欄位或表示式是否為null,如果為null 返回指定的值,否則返回原本的值
#語法:ifnull(欄位/表示式,指定值) #示例:查詢學生表中:所有學生的姓名和成績,並將原來成績為null(沒參加考試)的同學成績改為0分 select name,ifnull(score,0) from students;
-
isnull:判斷某欄位或表示式是否為null,如果是,則返回1,否則返回0
#語法:ifnull(欄位/表示式) #示例:查詢學生表中:所有學生的姓名以及是否缺考,如果缺考記為1,否則記為0 select name,ifnull(score) from students;
-
substr:擷取子串
#語法:substr(欄位/字元,初始索引,擷取字元長度) #注意:字串索引從1開始,而不是從0開始,如果擷取字元長度省略,則擷取到最後。 #示例:擷取一個字串的前三個字母 select substr('zhang',1,3); #查詢結果為zha
-
length :獲取位元組個數
#語法:length(欄位/字元) #注意:獲取的是位元組個數,而不是字元個數,在utf8編碼中,1個漢字為3個位元組,1個字母為1個位元組。 #示例: select length('123張'); #查詢結果為6
-
instr:返回子串第一次出現的索引
#語法:instr(欄位/字元,子串) #注意:如果字串不在原字元中,則返回0 #示例: select instr('123六六456','六六'); #查詢結果為4 select instr('123六六456','六六六'); #查詢結果為0
-
round:四捨五入
#語法:round(數字,保留小數位數) #注意:保留小數位數可以不寫,那麼預設四捨五入為整數。 #示例: select round(4.76,1); #查詢結果為4.8
-
truncate:截斷
#語法:truncate(數字,保留小數位數) #注意:保留小數位數可以不寫,那麼預設截斷為整數。截斷不是四捨五入,而是均舍掉,4.1、4.9截斷均為4。 #示例: select truncate(4.76,1); #查詢結果為4.7
-
rand:0-1之間隨機數
#語法:rande() #示例: select rand(); #返回一個範圍在0-1之間的隨機值
-
floor:向下取整
#語法:floor(數字) #注意:返回一個不大於括號中值的最大整數。 #示例: select floor(4.7); #查詢結果為4
-
ceil:向上取整
#語法:floor(數字) #注意:返回一個不小於括號中值的最大整數。 #示例: select ceil(4.7); #查詢結果為5
-
mod:取餘
#語法:mod(數1,數2); #注意:返回結果為數1除以數2所得的餘數。 #示例: SELECT MOD(10,3); #查詢結果為1
-
now:當前系統日期+時間
#語法:now(); #示例: SELECT now(); #查詢結果為:2020-07-08 16:43:35
-
curdate:當前系統日期
#語法:curdate(); #示例: SELECT curdate(); #查詢結果為:2020-07-08
-
curtime:當前系統時間
#語法:curtime(); #示例: SELECT curtime(); #查詢結果為:16:45:28
-
str_to_date:將字元轉換成日期
#語法:str_to_date(字元,日期格式); #注意:%Y是年,%m是月,%d是日,%H是小時,%i是分,%s是秒 #示例: select str_to_date('2020-7-8','%Y-%m-%d'); #查詢結果為:2020-07-08
-
date_format:將日期轉換成字元
#語法:date_format(日期,日期格式); #注意:%Y是年,%m是月,%d是日,%H是小時,%i是分,%s是秒 #示例: select date_format('2020-7-8','今天是%Y年%m月%d日')); #查詢結果為:今天是2020年07月08日
-
其他日期函式
select date(now()); #返回日期,結果為:2020-07-08 select year(now()); #返回年,結果為:2020 select month(now()); #返回月 select day(now()); #返回日 select minute(now()); #返回分鐘 select second(now()); #返回秒 select datediff('2020-08-08','2020-07-08'):#返回兩個日期相差的天數,結果為:31
2)分組函式/聚集函式
聚集函式:作用於一組函式,最後返回一個值
分類:
- sum() 求和
- min() 最小值
- max() 最大值
- avg() 平均值
- count() 計數
#示例:查詢學生表中,學生成績的總和、最小值、最大值、平均成績以及學生總人數
select sum(score),min(score),max(score),avg(score),count(*)
from students;
特點:
- 以上五個分組函式都忽略null值,除了count(*);
- sum和avg一般用於處理數值型,max、min、count可以處理任何資料型別;
- 都可以搭配distinct使用,用於統計去重後的結果。
⑤ 分組查詢
/* 分組查詢:將查詢結果按照1個或多個欄位進行分組,欄位值相同的為一組。
語法:
select 查詢的欄位,分組函式
from 表
【where 分組前的篩選條件】
group by 分組的欄位
【having 分組後的篩選條件】
【order by 排序】
特點:
① where語句、having語句和order by語句可以沒有;
② 可以按單個欄位分組,也可以按多個欄位分組,欄位之間用逗號隔開;
③ 和分組函式一同查詢的欄位最好是分組後的欄位;
④ 分組篩選
where 在分組前對原始表進行篩選,位於group by的前面
havng 在分組後對分組後的結果集進行篩選,位於group by的後面
⑤ having後可以支援別名;
⑥ 先執行from,再執行where,然後執行group by,having,接著執行select,最後執行order by。
*/
#示例:查詢學生表中,每個班級的平均分數,並根據此進行降序排列
select avg(score) as 平均分數,grade as 班級名
from students
group by grade
order by avg(score);
⑥ 連線查詢
連線查詢:所要查詢的內容在多個表中,對多個表進行連線後查詢
笛卡爾乘積:如果連線條件省略或無效則會出現。檢索出的行數目等於第一個表中的行數乘以第二個表的行數。
解決辦法:新增上連線條件
SQL92語法(瞭解):支援內連線(等值連線、非等值連線、自連線)
-
等值連線
/* 語法: select 查詢列表 from 表1 別名,表2 別名 where 表1.key=表2.key 【and 篩選條件】 【group by 分組欄位】 【having 分組後的篩選】 【order by 排序欄位】 特點: ① 一般為表起別名; ② 多表的順序可以調換;; ③ n表連線至少需要n-1個連線條件; ④ 等值連線的結果是多表的交集部分。 */
-
非等值連線
/* 語法: select 查詢列表 from 表1 別名,表2 別名 where 非等值的連線條件 【and 篩選條件】 【group by 分組欄位】 【having 分組後的篩選】 【order by 排序欄位】 */
-
自連線
/* 語法: select 查詢列表 from 表 別名1,表 別名2 where 等值的連線條件 【and 篩選條件】 【group by 分組欄位】 【having 分組後的篩選】 【order by 排序欄位】 */
SQL99語法✳(重點):支援內連線(等值連線、非等值連線、內連線)、外連線(左外、右外、全外)和交叉連線。
-
內連線
/* 語法: select 欄位,... from 表1 【inner】 join 表2 on 連線條件 【inner】 join 表3 on 連線條件 ... 【where 篩選條件】 【group by 分組欄位】 【having 分組後的篩選條件】 【order by 排序的欄位或表示式】 特點: ① 一般為表起別名; ② 多表的順序可以調換; ③ n表連線至少需要n-1個連線條件; ④ 內連線的結果是多表的交集部分✦✦; ⑤ inner關鍵字可以省略; ⑥ 先執行from,再執行join on,接著where,之後group by having,然後select,最後order by。 */
-
外連線
/* 語法: select 欄位,... from 表1 left/right/full 【outer】 join 表2 on 連線條件 left/right/full 【outer】 join 表3 on 連線條件 ... 【where 篩選條件】 【group by 分組欄位】 【having 分組後的篩選條件】 【order by 排序的欄位或表示式】 特點: ① 查詢的結果=主表中所有的行,如果從表和它匹配的將顯示匹配行,如果從表沒有匹配的則顯示null; ② 多表的順序很重要,left join 左邊的是主表,right join 右邊的就是主表,full join 兩邊都是主表; ③ outer關鍵字可以省略。 */
-
交叉連線(不常用,關鍵字為cross join)
⑦ 子查詢
/*
子查詢:一條查詢語句中又嵌套了另一條完整的select語句,其中被巢狀的select語句,稱為子查詢或內查詢
主查詢:在外面的查詢語句,稱為主查詢或外查詢
特點:
① 子查詢都放在小括號內;
② 子查詢可以放在from後面、select後面、where後面、having後面,但一般放在條件的右側;
③ 子查詢優先於主查詢執行,主查詢使用了子查詢的執行結果;
④ 子查詢根據查詢結果的行數不同分為以下兩類:
- 單行子查詢(結果集只有一行)
一般搭配單行操作符使用:> < = <> >= <=
非法使用子查詢的情況:
a、子查詢的結果為一組值
b、子查詢的結果為空
- 多行子查詢(結果集有多行)
一般搭配多行操作符使用:any、all、in、not in
in: 屬於子查詢結果中的任意一個就行
any和all往往可以用其他查詢代替
*/
⑧ 分頁查詢
/*
應用場景:當要查詢的條目數太多,一頁顯示不全
語法:
select 欄位|表示式,...
from 表1
【連線型別 join 表2 on 連線條件】
【where 條件】
【group by 分組欄位】
【having 條件】
【order by 排序的欄位】
limit 【起始的條目索引,】條目數;
特點:
① 起始條目索引從0開始
② 其實條目索引可以省略,如省略預設為0
③ limit子句放在查詢語句的最後;
④ 先執行from,再執行join on,接著where,再接著group by having,之後select,然後order by,最後limit。
*/
#示例:查詢學生表中,分數位於前五的學生全部資訊(假設前五名沒有並列排名)
select *
from students
order by score desc
limit 5;
⑨ 聯合查詢
/*
union:合併、聯合,將多次查詢結果合併成一個結果集
語法:
select 欄位|常量|表示式|函式 【from 表】 【where 條件】 union 【all】
select 欄位|常量|表示式|函式 【from 表】 【where 條件】 union 【all】
select 欄位|常量|表示式|函式 【from 表】 【where 條件】 union 【all】
.....
select 欄位|常量|表示式|函式 【from 表】 【where 條件】
特點:
① 多條查詢語句的查詢的列數必須是一致的;
② 多條查詢語句的查詢的各列型別、順序最好一致,各列資料型別也可以不一致,但必須相容(可以隱含轉換);
③ union代表去重,union all代表不去重。
*/
#示例(多個表):假設一班和二班均有一張成績表,現在要把兩張表的資訊合併。
select name,score
from grade1
union
select name,score
from grade2;
#示例(一個表):查詢學生表中:成績大於90或者姓趙的同學的全部資訊(要求用union不用or)
select *
from students
where score>90
union
select *
from students
where name like('趙%')
2. DML語言的學習
① 插入
/*
在表中插入資料,有兩種方式。
✳方式一(重點):
語法:
insert into 表名(欄位1,...)
values(值1,...);
特點:
① 欄位型別和值型別一致或相容,而且一一對應;
② 欄位的個數和順序不一定與原始表中的欄位個數和順序一致,但必須保證值和欄位一一對應;
③ 欄位可以省略,預設為所有欄位,並且順序和表中的儲存順序一致;
④ 不可以為空的欄位,必須插入值;
⑤ 假如表中有可以為null的欄位,注意可以通過以下兩種方式插入null值:欄位和值都省略/欄位寫上,值使用null。
✳方式二:
語法:
insert into 表名
set 欄位1=值1,欄位2=值2,...,欄位n=值n;
✳二者區別:
1).方式一支援一次插入多行,語法如下:
insert into 表名【(欄位名,..)】
values(值,..),(值,...),...;
2).方式一支援子查詢,語法如下:
insert into 表名
查詢語句;
*/
#示例:在學生表中插入一條學生資訊,學號:8,姓名:李四,班級:2,姓別:男,成績:88,電話:123456789
#方式一
insert into students(id,name,grade,gender,score,phone)
values(8,'李四',2,'男',88,'123456789');
#方式2
insert into students
set id=8,name='李四',grade=2,gender='男',score=88,phone='123456789';
② 修改
/*
語法:
update 表名
set 欄位1=新值1,欄位2=新值2,...
【where 條件】
特點:如果沒有where篩選條件,則會更改表中所有行。
*/
#示例:在學生表中修改李四的成績為90分
update students
set score=90
where name='李四';
③ 刪除
/*
刪除表中資料,有兩種方式。
✳方式一(重點):delete語句✔
語法:
delete from 表名
【where 篩選條件】;
特點:
① 如果沒有where篩選條件,則會刪除表中所有行;
② delect刪除的是表中的一行,而不是整個表,也不是一行中的某一個數據。
✳方式二:truncate table語句
語法:
truncate table 表名
特點:
① truncate table不能刪除某一行,而是刪除表中所有資料;
② truncate table語句刪除效率更高,其實質是刪除原來的表,然後重建了新表,而不是逐行刪除表資料。
✳二者區別:
1).truncate table不能加where條件,而delete可以加where條件
2).truncate table 刪除帶自增長的列的表後,如果再插入資料,資料從1開始,
delete 刪除帶自增長列的表後,如果再插入資料,資料從上一次的斷點處開始。
3).truncate table刪除不能回滾,delete刪除可以回滾
*/
#示例:在學生表中刪除李四的資訊
#只能用方式一,不能用方式二
delete from students
where name='李四';
#示例:刪除學生表中全部資訊
#方式1
delete from students;
#方式2
truncate table students;
*/
3. DDL語言的學習
① 庫和表的管理
庫的管理:
/*
1)、建立庫
create database 【if not exists】庫名;
2)、刪除庫
drop database 【if exists】庫名;
*/
表的管理:
1. 建立表 create table
/*
語法:
create table 【if not exists】 表名(
欄位名 欄位型別 【約束】,
欄位名 欄位型別 【約束】,
。。。
欄位名 欄位型別 【約束】
);
*/
#示例:建立一個學生表,包含學號、姓名、班級、性別、分數和電話號碼
create table students(
id int,
name varchar(10),
grade int,
gender char(1),
score int,
phone varchar(20)
);
2. 修改表 alter table
/*
1).新增列
alter table 表名 add column 列名 型別 【first|after 欄位名】;
2).修改列的型別或約束
alter table 表名 modify column 列名 新型別 【新約束】;
3).修改列名
alter table 表名 change column 舊列名 新列名 型別;
4).刪除列
alter table 表名 drop column 列名;
5).修改表名(重命名錶)
alter table 表名 rename 【to】 新表名;
*/
#示例:在學生表中新增一列用於顯示email(郵箱)
alter table students add column email varchar(20);
#示例:將學生表中的電話號碼型別改為int
alter table students modify column phone int;
#示例:將學生表中的name列名稱改為stu_name
alter table students change column name stu_name varchar(20);
#示例:將學生表中的email列刪除
alter table students drop column email;
#示例:將學生表名改為stu_tables
alter table students rename to stu_tables;
3. 刪除表 drop table
#語法:drop table【if exists】 表名;
4. 複製表
/*
1)、複製表的結構
create table 表名 like 舊錶;
2)、複製表的結構+資料
create table 表名
select 查詢列表
from 舊錶
【where 篩選】;
*/
② 常見型別
/*
✳整型:tineint、smallint、mediumint、int/integer、bigint
特點:
①都可以設定無符號和有符號,預設有符號,通過unsigned設定無符號
②如果超出了範圍,會報out or range異常,插入臨界值
③長度可以不指定,預設會有一個長度,長度代表顯示的最大寬度,如果不夠則左邊用0填充,
但需要搭配zerofill,並且預設變無符號整型
✳小數:
浮點型:double(M,D),float(M,D)
定點型:decimal(M,D)或者簡寫為dec(M,D)
特點:
①M代表整數部位+小數部位的個數,D代表小數部位
②如果超出範圍,則報out or range異常,並且插入臨界值
③M和D都可以省略,但對於定點數,M預設為10,D預設為0
④如果精度要求較高,則優先考慮使用定點數
✳字元型:char、varchar、binary、varbinary、enum、set、text、blob
特點:
①char:固定長度的字元,寫法為char(M),最大長度不能超過M,其中M可以省略,預設為1
②varchar:可變長度的字元,寫法為varchar(M),最大長度不能超過M,其中M不可以省略
✳日期型:year年、date日期、time時間、datetime 日期+時間、timestamp 日期+時間
*/
③ 常見約束
/*含義:一種限制,用於限制表中的資料,為了保證表中的資料的準確和可靠性
✳常見約束:
✔NOT NULL:非空,該欄位的值必填
✔UNIQUE:唯一,該欄位的值不可重複
✔DEFAULT:預設,該欄位的值如果不插入會有預設值
✔CHECK:檢查,mysql不支援
✔PRIMARY KEY:主鍵,該欄位的值不可重複並且非空 unique+not null
✔FOREIGN KEY:外來鍵,該欄位的值引用了另外的表的欄位
主鍵與唯一的區別:
①、一個表至多有一個主鍵,但可以有多個唯一;
②、主鍵不允許為空,唯一可以為空。
✳建立表時新增約束
CREATE TABLE 表名(
欄位名 欄位型別 列級約束,
欄位名 欄位型別,
表級約束
)
如:
create table 表名(
欄位名 欄位型別 not null, #非空
欄位名 欄位型別 primary key, #主鍵
欄位名 欄位型別 unique, #唯一
欄位名 欄位型別 default 值, #預設
constraint 約束名 foreign key(欄位名) references 主表(被引用列)
)
注意:
①表級約束語法:在各個欄位的最下面【constraint 約束名】 約束型別(欄位名)
特殊:【constraint 約束名】 foreign key(欄位名) references 主表(被引用列)
表級約束的constraint 約束名可省略,如可以直接primary key(id)
②列級約束和表級約束的區別
支援型別 是否可以起約束名
列級約束 除了外來鍵 不可以
表級約束 除了非空和預設 可以,但對主鍵無效
③列級約束可以在一個欄位上追加多個,中間用空格隔開,沒有順序要求
✳修改表時新增或刪除約束
1、非空
新增非空
alter table 表名 modify column 欄位名 欄位型別 not null;
刪除非空
alter table 表名 modify column 欄位名 欄位型別 ;
2、預設
新增預設
alter table 表名 modify column 欄位名 欄位型別 default 值;
刪除預設
alter table 表名 modify column 欄位名 欄位型別 ;
3、主鍵
新增主鍵
alter table 表名 add【 constraint 約束名】 primary key(欄位名);
刪除主鍵
alter table 表名 drop primary key;
4、唯一
新增唯一
alter table 表名 add【 constraint 約束名】 unique(欄位名);
刪除唯一
alter table 表名 drop index 索引名;
5、外來鍵
新增外來鍵
alter table 表名 add【 constraint 約束名】 foreign key(欄位名) references 主表(被引用列);
刪除外來鍵
alter table 表名 drop foreign key 約束名;
✳自增長列
特點:
①不用手動插入值,可以自動提供序列值,預設從1開始,步長為1,可以通過下面語句改變步長:
set auto_increment_increment=值;
②一個表至多有一個自增長列
③自增長列只能支援數值型
④自增長列必須為一個key
一、建立表時設定自增長列
create table 表(
欄位名 欄位型別 約束 auto_increment
)
二、修改表時設定自增長列
alter table 表 modify column 欄位名 欄位型別 約束 auto_increment
三、刪除自增長列
alter table 表 modify column 欄位名 欄位型別 約束
*/
4. DCL語言的學習
事務:一條或多條sql語句組成一個執行單位,這一組sql語句要麼都執行,要麼都不執行;
事務的特點:(ACID)
原子性(Atomicity):一個事務是一個不可分割的工作單位,其中的操作要麼都做,要麼都不做;如果事務中一個sql語句執行失敗,那麼已執行的語句也會回滾,資料庫退回到事務前的狀態,就像這個事務從來沒有執行過一樣。
一致性(Consistency):事務執行結束後,資料庫的完整性約束沒有被破壞,事務執行的前後都是合法的資料狀態。
隔離性(Isolation):資料庫允許多個併發事務同時對其資料進行讀寫和修改,一個事務的執行不受另外一個事務的干擾。
永續性(Durability ):事務一旦提交後,對資料的修改就是永久的,即便系統故障也不會丟失
事務的使用步驟:
/*
1.隱式事務:沒有明顯的開啟和結束事務的標誌,本身就是一條事務可以自動提交,比如insert、update、delete
2.顯示事務:具有明顯的開啟和結束事務的標誌.
1)、開啟事務(取消自動提交事務的功能)
set autocommit=0;
start transaction; #可以省略
2)、編寫事務的一組邏輯操作單元(多條sql語句)
支援insert、update、delete語句
【savepoint 回滾點名;】 #設定回滾點,可以沒有
3)、提交事務或回滾事務
commit; #提交
rollback; #回滾
rollback to 回滾點名;
*/
事務的併發問題:
髒讀:事務A訪問資料時,讀取到了事務B修改了但尚未提交的資料。(事務B沒有提交,可能提交成功,但也有可能回滾)
不可重複讀:事務A在訪問資料時,由於事務B對資料進行了修改,使得事務A多次讀取到的資料不一致。(違反了事務的一致性)
幻讀:事務A讀取資料時,事務B進行了插入或刪除,導致第一個事務讀取到了不同數目的資料。
如何避免事務的併發問題?(設定隔離級別)
隔離級別 | 髒讀 | 不可重複讀 | 幻讀 |
---|---|---|---|
read uncommitted(讀未提交) | 可能發生 | 可能發生 | 可能發生 |
read committed(讀已提交) | 不可能發生 | 可能發生 | 可能發生 |
repeatable read(可重複讀) | 不可能發生 | 不可能發生 | 可能發生 |
serializable(序列化) | 不可能發生 | 不可能發生 | 不可能發生 |
設定隔離級別:
set session|global transaction isolation level 隔離級別名;
檢視隔離級別:
select @@tx_isolation; #mysql預設的隔離級別是repeatable read(可重複讀)