· 8 years ago · Mar 29, 2018, 12:12 AM
1package main
2
3import (
4 "database/sql"
5 "flag"
6 "fmt"
7 "math/rand"
8 "os"
9 "sync"
10 "time"
11
12 _ "github.com/go-sql-driver/mysql"
13)
14
15var (
16 concurrent = flag.Int("C", 100, "concurrent")
17 number = flag.Int("N", 12000000, "number")
18)
19
20func perror(err error) {
21 if err != nil {
22 fmt.Printf("%s\n", err)
23 os.Exit(1)
24 }
25}
26
27var letters = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
28
29func randString(r *rand.Rand, n int) string {
30 b := make([]byte, n)
31 for i := range b {
32 b[i] = letters[r.Intn(len(letters))]
33 }
34
35 return string(b)
36}
37
38func main() {
39 db, err := sql.Open("mysql", "root@tcp(172.16.10.1:4000)/test")
40 perror(err)
41
42 db.SetMaxIdleConns(*concurrent + 1)
43
44 defer db.Close()
45
46 _, err = db.Exec("drop table if exists account")
47 perror(err)
48
49 _, err = db.Exec(
50 `CREATE TABLE account (
51 accountId int(20) NOT NULL AUTO_INCREMENT,
52 name varchar(255) DEFAULT NULL,
53 balance int(20) NOT NULL,
54 PRIMARY KEY (accountId),
55 KEY INDEX_balance (balance)
56) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;`)
57
58 perror(err)
59
60 var wg sync.WaitGroup
61 wg.Add(*concurrent)
62 for i := 0; i < *concurrent; i++ {
63 r := rand.New(rand.NewSource(time.Now().UnixNano()))
64 step := *number / *concurrent
65 go func(i int) {
66 defer wg.Done()
67 for j := 0; j < step; j++ {
68 n := r.Intn(4) + 6
69 id := i*step + j + 1
70 _, err1 := db.Exec("insert ignore into account (accountId, name, balance) values (?, ?, ?)", id, randString(r, n), 10000)
71 perror(err1)
72 }
73 }(i)
74 }
75 wg.Wait()
76
77 total, err := sumBalance(db)
78 perror(err)
79
80 for i := 0; i < *concurrent; i++ {
81 go func() {
82 r := rand.New(rand.NewSource(time.Now().UnixNano()))
83 for {
84 if err := doTransaction(db, r); err != nil {
85 fmt.Printf("do transaction failed %v\n", err)
86 }
87 }
88 }()
89 }
90
91 for {
92 checkSum(db, total)
93 }
94}
95
96func sumBalance(db *sql.DB) (int64, error) {
97 var total int64
98 err := db.QueryRow("select sum(balance) from account where id < 10000000").Scan(&total)
99 return total, err
100}
101
102func checkSum(db *sql.DB, total int64) {
103 n, err := sumBalance(db)
104 if err != nil {
105 fmt.Printf("get total err %v\n", err)
106 return
107 }
108
109 if n != total {
110 fmt.Printf("check sum failed, want %d, but got %d", total, n)
111 os.Exit(1)
112 }
113}
114
115func doTransaction(db *sql.DB, r *rand.Rand) error {
116 txn, err := db.Begin()
117 if err != nil {
118 return err
119 }
120
121 defer txn.Rollback()
122
123 _, err = txn.Exec("update account set balance = balance + 100 where accountId = ?", r.Intn(10000000-1)+1)
124 if err != nil {
125 return err
126 }
127 _, err = txn.Exec("update account set balance = balance - 100 where accountId = ?", r.Intn(10000000-1)+1)
128 if err != nil {
129 return err
130 }
131
132 return txn.Commit()
133}