Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

事务隔离性有点不对 #121

Closed
fwhezfwhez opened this issue May 7, 2020 · 7 comments
Closed

事务隔离性有点不对 #121

fwhezfwhez opened this issue May 7, 2020 · 7 comments

Comments

@fwhezfwhez
Copy link

fwhezfwhez commented May 7, 2020

先贴一下代码,其中,

  • wrong()方法是使用gorose的事务来进行操作的.
  • right()使用的底层提供事务,并且分别预设事务级别isolation=0,1,2三种不同事务级别进行同样的操作。
  • 整个操作的流程是:在同一个事务里,分别插入和查询插入的数据,在未提交时,wrong()里的count未能响应到insert的变化,而right()是可以的。
package main

import (
	"context"
	"database/sql"
	"fmt"

	_ "github.com/go-sql-driver/mysql"
	"github.com/gohouse/gorose/v2"
)

var err error
var engin *gorose.Engin

/*
    CREATE DATABASE test;
    CREATE TABLE t_user(
		id INT NOT NULL,
		name VARCHAR(20) NOT NULL
	)ENGINE=InnoDB DEFAULT CHARSET=utf8;
*/

func init() {
	engin, err = gorose.Open(&gorose.Config{Driver: "mysql", Dsn: "ft:123@tcp(localhost:3306)/test?charset=utf8&parseTime=true&allowNativePasswords=true"})
	if err != nil {
		panic(err)
	}
}
func DB() gorose.IOrm {
	return engin.NewOrm()
}
func main() {
	wrong()
}

func right() {
	var id = 6
	var name = "gorose"
	db := DB()
	tx, e := db.GetISession().GetIEngin().GetExecuteDB().BeginTx(context.Background(), &sql.TxOptions{
		ReadOnly: false,

		// 分别测试0,1,2,三种隔离级别,其他隔离级别该驱动不支持
		Isolation: 0,
	})
	if e != nil {
		panic(e)
	}

	_, err := tx.Exec("insert into t_user(id, name) values(?, ?)", id, name)
	if err != nil {
		tx.Rollback()
		panic(err)
	}

	res, err := tx.Query("select count(*) from t_user where id=?", id)
	if err != nil {
		tx.Rollback()
		panic(err)
	}
	var count int

	for res.Next() {
		if e := res.Scan(&count); e != nil {
			panic(e)
		}
	}
        // 不管isoloation为0还是1还是2,count都可以显示为1
	fmt.Println(count)

	if e := tx.Commit(); e != nil {
		panic(e)
	}
}

func wrong() {
	var id = 6
	var name = "gorose"

	db := DB()

	db.Begin()

	if _, e := db.Execute("insert into t_user(id, name) values(?, ?)", id, name); e != nil {
		db.Rollback()
		panic(e)
		return
	}

	rs, e := db.Query("select count(*) from t_user where id=?", id)
	if e != nil {
		db.Rollback()
		panic(e)
		return
	}

	// 期望输出count为1,实际输出为0
	// [map[count(*):0]]
	fmt.Println(rs)

	db.Commit()
}

贴一下结果:

right() isolation=0:

1

right() isolation=1:

1

right() isolation=2:

1

wrong():

[map[count(*):0]]
  • right()方法,分别对isolation=1,2,0进行操作,所得到的的count都是健康的1,也就是同事务里,count可以响应到插入,哪怕是未commit。

  • wrong()方法,count无法响应到insert的方法。

基于以上结论,猜测:

  • gorose的事务脏了,期望同事务下的select countinsert可能各自进了不同的事务里,导致了事务隔离造成的count异常。

  • go1.12.7

  • gorose/v2

  • win10 x64

  • mysql, docker image<36fcb346aa55> Ver 8.0.18 for Linux on x86_64

@tobycroft
Copy link

这个问题是我先发现的,过来打个卡,群主出来挨打!

@tobycroft
Copy link

事务执行中,插入数据后,无法读取相同事务中已经插入的数据

@tobycroft
Copy link

@fizzday

@tobycroft
Copy link

希望在底层调用db的时候就锁定该db的session,因为目前的情况就是除非用session+原生语句的形式才能规避,这样着实就变得很不方便了,尤其是金融类型的项目,很多地方要用到事务,缺少了这个,几乎每个地方都要写语句了,所以……比较严重吧

@fizzday
Copy link
Member

fizzday commented Jun 2, 2020

已解决, 暂时没油打 tag, 使用 master版本即可

@fwhezfwhez
Copy link
Author

有劳了

@tobycroft
Copy link

感谢群主,我翘起来了,请尽情享用吧!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants