review的项目代码

db.go:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package main

import (
"fmt"
"github.com/go-xorm/xorm"
_ "github.com/lib/pq"
"log"
"xorm.io/core"
)

type People struct {
Id int `xorm:"not null pk autoincr"`
Age int `xorm:"unique"` // 增加 unique
Name string
}

var engine *xorm.Engine

func init() {
host := "localhost"
port := 5432
user := "postgres"
password := "root"
dbName := "test"
psqlInfo := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", host, port, user, password, dbName)
var err error
engine, err = xorm.NewEngine("postgres", psqlInfo)
if err != nil {
log.Fatal(err)
}
engine.SetTableMapper(core.SameMapper{})
err = engine.Sync2(new(People)) // 在表存在的情况下,结构增加 unique 后,sync2() 时会自动给表建立索引。
if err != nil {
log.Fatal(err)
}
engine.SetMaxIdleConns(100)
engine.SetMaxIdleConns(100)
engine.ShowSQL(false)
}

main.go:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package main

import (
"fmt"
"github.com/go-xorm/xorm"
"github.com/lib/pq"
"log"
"sync"
)

var _pgUniqueViolationErrorCode = "23505"

func main() {
engine.Delete(new(People))
wg := &sync.WaitGroup{}
for i := 0; i <= 100; i++ {
wg.Add(1)
go TestTransaction(i, wg)
}
wg.Wait()
}

func TestTransaction(i int, wg *sync.WaitGroup) {
defer wg.Done()

engine.Transaction(func(session *xorm.Session) (interface{}, error) {
p := &People{}
// 对本条记录增加读写锁,其他协程不可读写,
session = session.ForUpdate()
READ:
exist, err := session.Where("name = ?", "xmge").Get(p)
fmt.Println(i, p)
if err != nil {
log.Fatal(err)
}
if !exist {
//如果本条记录不存在,则没有枷锁,会出现同时创建的情况,因此在这里需要增加唯一索引来控制
p := People{Age: 27, Name: "xmge"}
_, err := session.InsertOne(&p)
if err != nil {
pgErr := err.(*pq.Error)
if string(pgErr.Code) == _pgUniqueViolationErrorCode {
// 使用 goto 一定要谨慎,否则容易造成死循环
// 考虑一下是否可以接受错误的返回,提示服务器异常,让用户再点一下
goto READ
}
log.Fatal(err)
}
fmt.Printf("%d:,name 为 xmge 的记录不存在,进行创建\n", i)
return nil, nil
} else {
fmt.Printf("%d,查询时已存在\n", i)
p.Age++
if p.Age > 50 {
return nil, nil
}
_, err := session.Cols("age").Update(p)
if err != nil {
log.Fatal(err)
}
}
return nil, err
})
}

xorm-联合索引