死锁1:
问题来由
服务端错误日志:
{Source:/var/lib/jenkins/tools/org.jenkinsci.plugins.golang.GolangInstallation/go/src/git.jiayougougou.com/snail/server/models/user_shop.go:162
Time:2018-08-0215:41:53.742066909 +0800 CST Level:log UseTime: Sql:
Message:Error 1213: Deadlock found when trying to get lock; try restarting
transaction}
代码定位
func (u UserShop) SetUserDefaultShop(userId, shopId int) error {
if err := u.DB().Table(u.TableName()).Where("user_id = ? and shop_id = ?", userId, shopId).Update("is_default", SureYes).Error; err != nil {
return err
}
//设置其他店铺未不默认
if err := u.DB().Table(u.TableName()).Where("user_id = ? and shop_id != ?", userId, shopId).Update("is_default", SureNo).Error; err != nil {
return err
}
if err := u.clear(userId); err != nil {
return err
}
return nil
}
部分表结构
CREATE TABLE user_shop (
user_shop_id int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键自增',
user_id int(11) NOT NULL COMMENT '用户Id',
shop_id int(11) unsigned NOT NULL COMMENT '店铺id',
type tinyint(4) NOT NULL DEFAULT '1' COMMENT '1: 管理员;2:普通员工',
is_default tinyint(1) NOT NULL DEFAULT '1',
home_set varchar(255) NOT NULL DEFAULT '' COMMENT '店铺设置',
PRIMARY KEY (user_shop_id),
UNIQUE KEY user_id (user_id,shop_id) USING BTREE,
KEY shop_id (shop_id) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=12800 DEFAULT CHARSET=utf8mb4 COMMENT='用户与商品的关联表'
问题解决思路
首先通过业务代码怀疑进行update时,又进行了select,但是出现了事务中的资源抢夺导致死锁
怀疑代码的索引未生效导致了锁表,因为sql语句中用了!
事务的本质进行分析
验证1 资源抢夺
通过goroutine进行了并发执行
func TestRR(t *testing.T) {
Init()
ch := make(chan error)
go func() {
for {
err := UserShopDefault.SetUserDefaultShop(4, 2)
if err != nil {
ch
}
fmt.Println(11)
}
}()
go func() {
for {
err := UserShopDefault.SetUserDefaultShop(4, 2)
if err != nil {
ch
}
//fmt.Println(11)
//_, err := UserShopDefault.GetByUserIdAndShopId(4, 2)
//if err != nil {
//ch
//}
fmt.Println(22)
}
}()
fmt.Println(
}
结果并未退出并打印错误,一直保持正常运行。因此排除第一种可能
验证2,索引未生效导致行锁
其实第一个代码已经证明了没有行锁,但是还是不放心进行了explain分析。
explain select *From user_shop where shop_id != 2 and user_id = 4;
expalin update ...
结果也是,索引能够正常生效,就算是!。另外update和delect的explain要mysql5.7版本后才支持。
验证3,事务的隔离性分析
查看mysql的隔离性
select @@tx_isolation
reapeat read
是默认的RR(保障主从备份)
验证4,其他