[golang]MySQL中如何为单个事务设置隔离级别

相比起简单的锁表,事务提供了更好的并发性能,但同时也带来更大的复杂性,如隔离级别,mvcc,死锁等。网上关于事务隔离级别的介绍遍地都是,就不再赘述了。

MySQL提供了3个等级的隔离级别配置,下面分别列出配置方法:

  1. 全局
    直接改配置文件
    set global transaction isolation level repeatable read;
  2. 当前session
    set tx_isolation = 'repeatable-read';
    set session transaction isolation level repeatable read;
  3. 下一个事务
    set transaction isolation level repeatable read;

但是在Go的MySQL驱动是自带连接池的,这使得这3个等级都无法直接使用,毕竟谁知道下一条sql会跑在哪个连接上呢?那么有什么解决方案呢?

  1. Go1.8以后的版本,sql库新增了API BeginTx,直接调用即可
tx0, err := db.BeginTx(context.Background(), &sql.TxOptions{
	Isolation: sql.LevelReadUncommitted,
})
复制代码
  1. 如果是1.8以前的版本,可以利用事务在一个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()
复制代码
  1. 或者也可以使用不同的配置创建两个db对象,每个对象有自己独立的连接池
db0, err := sql.Open("mysql", "root@/test")
db1, err := sql.Open("mysql", "root@/test?tx_isolation='read-uncommitted'")
复制代码

最后提供一段测试代码,可以很清楚的看到read-uncommitted带来的脏读问题。

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()
}
复制代码

参考

  • https://github.com/go-sql-driver/mysql/issues/472
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值