相比起簡(jiǎn)單的鎖表,事務(wù)提供了更好的并發(fā)性能琼梆,但同時(shí)也帶來(lái)更大的復(fù)雜性性誉,如隔離級(jí)別,mvcc茎杂,死鎖等错览。網(wǎng)上關(guān)于事務(wù)隔離級(jí)別的介紹遍地都是,就不再贅述了煌往。
MySQL提供了3個(gè)等級(jí)的隔離級(jí)別配置倾哺,下面分別列出配置方法:
- 全局
直接改配置文件
set global transaction isolation level repeatable read;
- 當(dāng)前session
set tx_isolation = 'repeatable-read';
set session transaction isolation level repeatable read;
- 下一個(gè)事務(wù)
set transaction isolation level repeatable read;
但是在Go的MySQL驅(qū)動(dòng)是自帶連接池的,這使得這3個(gè)等級(jí)都無(wú)法直接使用刽脖,畢竟誰(shuí)知道下一條sql會(huì)跑在哪個(gè)連接上呢羞海?那么有什么解決方案呢?
- Go1.8以后的版本曲管,sql庫(kù)新增了API BeginTx却邓,直接調(diào)用即可
tx0, err := db.BeginTx(context.Background(), &sql.TxOptions{
Isolation: sql.LevelReadUncommitted,
})
- 如果是1.8以前的版本,可以利用事務(wù)在一個(gè)session上處理的特性hack一下
tx1, err := db.Begin()
_, err = tx1.Exec("ROLLBACK")
_, err = tx1.Exec("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED")
_, err = tx1.Exec("BEGIN")
rows, err := tx1.Query("SELECT COUNT(*) FROM USER")
rows.Close()
tx1.Commit()
- 或者也可以使用不同的配置創(chuàng)建兩個(gè)db對(duì)象院水,每個(gè)對(duì)象有自己獨(dú)立的連接池
db0, err := sql.Open("mysql", "root@/test")
db1, err := sql.Open("mysql", "root@/test?tx_isolation='read-uncommitted'")
最后提供一段測(cè)試代碼腊徙,可以很清楚的看到read-uncommitted帶來(lái)的臟讀問(wèn)題简十。
func main() {
db, err := sql.Open("mysql", "root@/test")
if err != nil {
panic(err)
}
db1, err := sql.Open("mysql", "root@/test?tx_isolation='read-uncommitted'")
if err != nil {
panic(err)
}
tx0, err := db.Begin()
if err != nil {
panic(err)
}
_, err = tx0.Exec("insert into user value (null,?)", "cc")
if err != nil {
panic(err)
}
rows, err := db1.Query("select count(*) from user")
if err != nil {
panic(err)
}
for rows.Next() {
s := 0
err = rows.Scan(&s)
if err != nil {
panic(err)
}
fmt.Println(s)
}
tx0.Rollback()
}