mysql.drvicer Busy buffer error,一个比较Ugly的bug,但是一般情况下不会触发 #993

Open
opened 2018-05-31 09:28:16 +00:00 by zhujingfa · 0 comments
zhujingfa commented 2018-05-31 09:28:16 +00:00 (Migrated from github.com)

本人在修改,准备在xorm增加一层Conn,单个session固定底层db Conn,但是在修改跑测试用例出现了标题上的bug,test case是xorm/tag_extends_test.go:59 TestExtends,只有用到Extend属性才会碰到.

问题代码, 问题在Find方法上,一个简单联合查询出现了两条语句,第二条执行时第一条还没resetSesion,以前之所以没出现问题是因为golang database/sql底层的连接混乱管理机制,具体参见这个Issue https://github.com/go-xorm/xorm/issues/944

[xorm] [info]  2018/05/31 15:35:34.113775 [SQL] SELECT * FROM `userinfo` LEFT JOIN `userdetail` ON `userinfo`.`detail_id` = `userdetail`.`id`
[xorm] [info]  2018/05/31 15:35:34.114092 [SQL] SELECT `id`, `intro`, `profile` FROM `userdetail` WHERE `id`=? LIMIT 1 []interface {}{1}

	fmt.Println("----join--infos2")
	var infos2 = make([]UserAndDetail, 0)
	err = testEngine.Table(&Userinfo{}).
		Join("LEFT", qt(ud), qt(ui)+"."+qt("detail_id")+" = "+qt(ud)+"."+qt(uiid)).
		NoCascade().
		Find(&infos2)
	if err != nil {
		t.Error(err)
		panic(err)
	}
	fmt.Println(infos2)

xorm代码

问题代码在这里,session.slice2Bean(),这里的2次获取导致了conn的buf不干净,因为单个stmt未重置, rows也读取完。备注中也说的很清楚,作者是明白这个缺陷的,但是在事务中是会报错的。
当前一个连接还在查询,直接继续,因为原来的连接buff都没读取完,肯定有问题。
//暂时切换到外部链接去,但是事务中还是有问题的,确实应该直接从父记录中直接获取的
//has, err := session.engine.ID(pk).NoCascade().get(structInter.Interface())
if !isPKZero(pk) {
    // !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
    // however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
    // property to be fetched lazily
    structInter := reflect.New(fieldValue.Type())
    has, err := session.ID(pk).NoCascade().get(structInter.Interface())
    if err != nil {
        return nil, err
    }
    if has {
        fieldValue.Set(structInter.Elem())
    } else {
        return nil, errors.New("cascade obj is not exist")
    }
}

补充下底层driver报错特征 github.com/go-sql-driver/mysql:

挂在:github.com/zhujingfa/sql.(*Conn).closemuRUnlockCondReleaseConn,等待c.closemu.Lock()

sync.runtime_Semacquire(0xc4204c5930)
        /usr/local/Cellar/go/1.10/libexec/src/runtime/sema.go:56 +0x39
sync.(*RWMutex).Lock(0xc4204c5928)
        /usr/local/Cellar/go/1.10/libexec/src/sync/rwmutex.go:98 +0x6e
github.com/zhujingfa/sql.(*Conn).close(0xc4204c5920, 0x4768e00, 0xc420099290, 0x0, 0x0)
        /project/godev/src/github.com/zhujingfa/sql/sql.go:1769 +0x57
github.com/zhujingfa/xorm.TestExtends(0xc42042e4b0)
        /project/godev/src/github.com/zhujingfa/xorm/tag_extends_test.go:251 +0x2d17
                
引起原因是buffer不为空,[mysql] 2018/05/31 15:35:34 packets.go:455: busy buffer
Get方法正常,Find方法不正常。

当然,我基本不用这个特性,今天碰到了,特地反馈下。

本人在修改,准备在xorm增加一层Conn,单个session固定底层db Conn,但是在修改跑测试用例出现了标题上的bug,test case是xorm/tag_extends_test.go:59 TestExtends,只有用到Extend属性才会碰到. 问题代码, 问题在Find方法上,一个简单联合查询出现了两条语句,第二条执行时第一条还没resetSesion,以前之所以没出现问题是因为golang database/sql底层的连接混乱管理机制,具体参见这个Issue https://github.com/go-xorm/xorm/issues/944 ``` [xorm] [info] 2018/05/31 15:35:34.113775 [SQL] SELECT * FROM `userinfo` LEFT JOIN `userdetail` ON `userinfo`.`detail_id` = `userdetail`.`id` [xorm] [info] 2018/05/31 15:35:34.114092 [SQL] SELECT `id`, `intro`, `profile` FROM `userdetail` WHERE `id`=? LIMIT 1 []interface {}{1} fmt.Println("----join--infos2") var infos2 = make([]UserAndDetail, 0) err = testEngine.Table(&Userinfo{}). Join("LEFT", qt(ud), qt(ui)+"."+qt("detail_id")+" = "+qt(ud)+"."+qt(uiid)). NoCascade(). Find(&infos2) if err != nil { t.Error(err) panic(err) } fmt.Println(infos2) ``` xorm代码 ``` 问题代码在这里,session.slice2Bean(),这里的2次获取导致了conn的buf不干净,因为单个stmt未重置, rows也读取完。备注中也说的很清楚,作者是明白这个缺陷的,但是在事务中是会报错的。 当前一个连接还在查询,直接继续,因为原来的连接buff都没读取完,肯定有问题。 //暂时切换到外部链接去,但是事务中还是有问题的,确实应该直接从父记录中直接获取的 //has, err := session.engine.ID(pk).NoCascade().get(structInter.Interface()) if !isPKZero(pk) { // !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch // however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne // property to be fetched lazily structInter := reflect.New(fieldValue.Type()) has, err := session.ID(pk).NoCascade().get(structInter.Interface()) if err != nil { return nil, err } if has { fieldValue.Set(structInter.Elem()) } else { return nil, errors.New("cascade obj is not exist") } } ``` 补充下底层driver报错特征 github.com/go-sql-driver/mysql: ``` 挂在:github.com/zhujingfa/sql.(*Conn).closemuRUnlockCondReleaseConn,等待c.closemu.Lock() sync.runtime_Semacquire(0xc4204c5930) /usr/local/Cellar/go/1.10/libexec/src/runtime/sema.go:56 +0x39 sync.(*RWMutex).Lock(0xc4204c5928) /usr/local/Cellar/go/1.10/libexec/src/sync/rwmutex.go:98 +0x6e github.com/zhujingfa/sql.(*Conn).close(0xc4204c5920, 0x4768e00, 0xc420099290, 0x0, 0x0) /project/godev/src/github.com/zhujingfa/sql/sql.go:1769 +0x57 github.com/zhujingfa/xorm.TestExtends(0xc42042e4b0) /project/godev/src/github.com/zhujingfa/xorm/tag_extends_test.go:251 +0x2d17 引起原因是buffer不为空,[mysql] 2018/05/31 15:35:34 packets.go:455: busy buffer Get方法正常,Find方法不正常。 ``` 当然,我基本不用这个特性,今天碰到了,特地反馈下。
Sign in to join this conversation.
No Milestone
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: xorm/xorm#993
No description provided.