package main import ( "fmt" "math/rand" "time" "github.com/DATA-DOG/go-txdb" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/postgres" // Use PostgreSQL in gorm ) func main() { dial := fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=%s&statement_timeout=2000", "gorm", "gorm", "localhost", "15432", "test1", "disable") { conn, err := gorm.Open("postgres", dial) if err != nil { panic(err) } conn.AutoMigrate(&User{}) if err := conn.Close(); err != nil { panic(err) } } { name := RandStringRunes(100) conn1, err := gorm.Open("postgres", dial) if err != nil { panic(err) } conn2, err := gorm.Open("postgres", dial) if err != nil { panic(err) } err = testExec(conn1, conn2, name) fmt.Println(err) if err := conn1.Close(); err != nil { panic(err) } if err := conn2.Close(); err != nil { panic(err) } } fmt.Println("conn3, conn4") { name := RandStringRunes(100) conn3, err := gorm.Open("postgres", dial) if err != nil { panic(err) } conn4, err := gorm.Open("postgres", dial) if err != nil { panic(err) } conn3 = conn3.Begin() conn4 = conn4.Begin() err = testExec(conn3, conn4, name) // conn3 wait lock so we got timeout error fmt.Println(err) if err := conn3.Rollback().Error; err != nil { panic(err) } if err := conn4.Rollback().Error; err != nil { panic(err) } if err := conn3.Close(); err != nil { panic(err) } if err := conn4.Close(); err != nil { panic(err) } } fmt.Println("txdb") { dbname := "postgreql_txdb" txdb.Register(dbname, "postgres", dial) dialect, ok := gorm.GetDialect("postgres") if !ok { panic(fmt.Errorf("dialect not exist")) } gorm.RegisterDialect(dbname, dialect) name := RandStringRunes(100) conn5, err := gorm.Open(dbname, "conn1") if err != nil { panic(err) } conn6, err := gorm.Open(dbname, "conn2") if err != nil { panic(err) } err = testExec(conn5, conn6, name) fmt.Println(err) // timeout if err := conn5.Close(); err != nil { panic(err) } if err := conn6.Close(); err != nil { panic(err) } } fmt.Println("end") } func testExec(conn1 *gorm.DB, conn2 *gorm.DB, name string) error { err := conn1.Save(&User{Name: name}).Error if err != nil { panic(err) // should be always succeed } err = conn2.Save(&User{Name: name}).Error if err != nil { fmt.Println("save failed") return err } return nil } // https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-go func init() { rand.Seed(time.Now().UnixNano()) } var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") func RandStringRunes(n int) string { b := make([]rune, n) for i := range b { b[i] = letterRunes[rand.Intn(len(letterRunes))] } return string(b) } type User struct { gorm.Model Name string `json:"name" gorm:"unique;not null"` }