go-xorm mysqlロックテスト

6219 ワード

mysqlデータベーススクリプト
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `balance` decimal(10,2) NOT NULL DEFAULT '0.00',
  `version` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `idx_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;

-- ----------------------------
--  Records of `user`
-- ----------------------------
BEGIN;
INSERT INTO `user` VALUES ('1', '12313', '9999.00', '1'), ('2', '12313', '9999.00', '2');
COMMIT;

テスト1
for updateの条件はbalance=8888 balance非索則テーブルレベルロックです
package main

import (
	"fmt"
	"game_server/log"
	_ "github.com/go-sql-driver/mysql"
	"github.com/go-xorm/xorm"
	"time"
)

type (
	User struct {
		Id      int64
		Name    string  `xorm:"varchar(255) notnull 'name'"`
		Balance float32 `xorm:"float notnull 'balance'"`
		//Version int     `xorm:"version"`
	}
)

var (
	mysqlEngine *xorm.Engine
	err         error
)

func main() {
	mysqlEngine, err = xorm.NewEngine("mysql", "root:123456@tcp(localhost:3306)/test?charset=utf8")
	if err != nil {
		log.Fatal("init mysql failed [%+v]", err)
	}
	mysqlEngine.ShowSQL(true)

	go TestTransaction()

	time.Sleep(2 * time.Second)

	user := new(User)
	user.Id = 2
	user.Name = "12313"
	user.Balance = 9999

	go TestUpdate(user)

	time.Sleep(30 * time.Second)
}

func TestTransaction() {

	session := mysqlEngine.NewSession()
	defer session.Close()
	err = session.Begin()
	if err != nil {
		panic(err)
	}

	session.Query("select * from user where balance = 8888 for update")

	//session.Where("balance = ?", 8888).ForUpdate()   //    

	session.Where("id = ?", 1).Update(&User{
		Balance: 88837,
	})

	time.Sleep(20 * time.Second)

	session.Commit()

}

func TestUpdate(user *User) {


	//  context    
	//ctx,cancelFunc  := context.WithTimeout(context.TODO(), 5*time.Second)
	//defer cancelFunc()
	//affected, err := mysqlEngine.Context(ctx).Exec("update user set name = ?, balance = ? where id = ?", user.Name, user.Balance, user.Id)
	//fmt.Printf("######## %#v, %+v
", affected, err) //cancelFunc() // mysqlEngine.Exec("update user set name = ?, balance = ? where id = ?", user.Name, user.Balance, user.Id) fmt.Printf(" COMMIT
") }

実行結果:[xorm][info]2019/09/15 20:33:33.212445[SQL]BEGIN TRANSACTION[xorm][info]2019/09/15 20:33:33.212653[SQL]select*from user where balance=8888 for update[xorm][info]2019/09/15 20:33:33.3.216061[SQL]UPDATE`user`SET`balance`=?WHERE (id = ?) []interface {}{88837, 1} [xorm] [info]  2019/09/15 20:33:35.207591 [SQL] update user set name = ?, balance = ? where id = ? []interface{}{"12313",9999,2}[xorm][info]2019/09/15 20:33:53.222873[SQL]COMMIT実行COMMITがCOMMITの前にロックされていない
 
テスト2
for updateは使用されていませんが、トランザクションの条件はプライマリ・キーIDが1で、TestUpdateVersion関数が更新したのはIDが1で、ロックがあります
func main() {
	user := new(User)
	user.Id = 1
	user.Name = "12313"
	user.Balance = 9999
}

func TestTransaction() {

    ....
	session.Where("id = ?", 1).Update(&User{
		Balance: 88837,
	})
    ...
}

[xorm] [info]  2019/09/15 20:35:09.674575 [SQL] BEGIN TRANSACTION [xorm] [info]  2019/09/15 20:35:09.674927 [SQL] UPDATE `user` SET `balance` = ? WHERE (id = ?) []interface {}{88837, 1} [xorm] [info]  2019/09/15 20:35:11.669606 [SQL] update user set name = ?, balance = ? where id = ? []interface{}{"12313",9999,1}[xorm][info]2019/09/15 20:35:29.679462[SQL]COMMIT実行COMMIT前はロックされていません
テスト3
for updateは使用されず、トランザクション条件IDは1、TestUpdateVersion関数はID 2のデータを更新し、ID 2のデータはロックされていないので、トランザクション条件は文であり、行レベルロックである
func main() {
	user := new(User)
	user.Id = 2
	user.Name = "12313"
	user.Balance = 9999
}

func TestTransaction() {

    ....
	session.Where("id = ?", 1).Update(&User{
		Balance: 88837,
	})
    ...
}

[xorm] [info]  2019/09/15 20:38:23.217078 [SQL] BEGIN TRANSACTION [xorm] [info]  2019/09/15 20:38:23.217437 [SQL] UPDATE `user` SET `balance` = ? WHERE (id = ?) []interface {}{88837, 1} [xorm] [info]  2019/09/15 20:38:25.207137 [SQL] update user set name = ?, balance = ? where id = ? []interface{}{"12313",9999,2}実行COMMITの前にロックされていない[xorm][info]2019/09/15 20:38:43.221392[SQL]COMMIT
テスト4
for update条件はid=2で、トランザクション内のupdate条件id=1で、結果的にロックが発生するので、for update条件がインデックスであればロック行
func main() {
	...
	user := new(User)
	user.Id = 2
	user.Name = "12313"
	user.Balance = 9999
	...
}

func TestTransaction() {

    ...
	session.Query("select * from user where id = 2 for update")
	session.Where("id = ?", 1).Update(&User{
		Balance: 88837,
	})
    ...

}

[xorm] [info]  2019/09/15 20:41:29.932293 [SQL] BEGIN TRANSACTION [xorm] [info]  2019/09/15 20:41:29.932448 [SQL] select * from user where id = 2 for update [xorm] [info]  2019/09/15 20:41:29.933547 [SQL] UPDATE `user` SET `balance` = ? WHERE (id = ?) []interface {}{88837, 1} [xorm] [info]  2019/09/15 20:41:31.925843 [SQL] update user set name = ?, balance = ? where id = ? []interface{}{"12313",9999,1}[xorm][info]2019/09/15 20:41:49.939323[SQL]COMMIT実行COMMIT前はロックされていません
テスト5
トランザクションではbalance=9999.00をid 1として使用します.balanceはインデックスではなく、ロックがあります(表レベルのロック)
func main() {
	...
	user := new(User)
	user.Id = 2
	user.Name = "12313"
	user.Balance = 9999
	...
}

func TestTransaction() {

    ...
	session.Where("balance = ?", 9999.00).Update(&User{
		Balance: 88837,
	})
    ...

}

[xorm] [info]  2019/09/15 20:54:48.451605 [SQL] BEGIN TRANSACTION [xorm] [info]  2019/09/15 20:54:48.451942 [SQL] UPDATE `user` SET `balance` = ? WHERE (balance = ?) []interface {}{88837, 9999} [xorm] [info]  2019/09/15 20:54:50.448837 [SQL] update user set name = ?, balance = ? where id = ? []interface{}{"12313",9999,2}[xorm][info]2019/09/15 20:55:08.457835[SQL]COMMIT実行COMMIT前はロックなし