-
Notifications
You must be signed in to change notification settings - Fork 0
/
mysql.go
160 lines (129 loc) · 3.19 KB
/
mysql.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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package mysql
import (
"context"
"database/sql"
"time"
"github.com/altstory/go-log"
)
// MySQL 代表一个数据库的链接。
type MySQL struct {
ctx context.Context
master *sql.DB
slave *sql.DB
useMaster bool
}
// New 通过默认工厂创建一个 MySQL 实例。
func New(ctx context.Context) *MySQL {
factory := *defaultFactory
if factory == nil {
log.Errorf(ctx, "go-mysql: default factory is not initialized (forgot to set MySQL config?)")
return nil
}
return factory.New(ctx)
}
func newMySQL(ctx context.Context, master, slave *sql.DB) *MySQL {
return &MySQL{
ctx: ctx,
master: master,
slave: slave,
}
}
// BeginTx 开始一个事务。
func (mysql *MySQL) BeginTx(opts *sql.TxOptions) (tx *Tx, err error) {
if err = mysql.ctx.Err(); err != nil {
return
}
sqltx, err := mysql.db(true).BeginTx(mysql.ctx, opts)
if err != nil {
return
}
tx = &Tx{
ctx: mysql.ctx,
tx: sqltx,
}
return
}
// Exec 执行一条修改语句并返回结果。
func (mysql *MySQL) Exec(query string, args ...interface{}) (result Result, err error) {
if err = mysql.ctx.Err(); err != nil {
return
}
start := time.Now()
res, err := mysql.db(true).ExecContext(mysql.ctx, query, args...)
statsForWrite(mysql.ctx, query, start)
if err != nil {
return
}
affected, _ := res.RowsAffected()
if affected > 0 {
statsForAffectedRows(mysql.ctx, affected)
}
result = res.(Result)
return
}
// Ping 测试连接是否可用。
func (mysql *MySQL) Ping() (err error) {
if err = mysql.ctx.Err(); err != nil {
return
}
return mysql.db(false).PingContext(mysql.ctx)
}
// Prepare 准备一个 Stmt,方便绑定参数。
func (mysql *MySQL) Prepare(query string) (stmt *Stmt, err error) {
if err = mysql.ctx.Err(); err != nil {
return
}
stmt = &Stmt{
db: mysql,
query: query,
}
return
}
// Query 查询一个带参数的查询,返回所有的结果。
func (mysql *MySQL) Query(query string, args ...interface{}) (rows *Rows, err error) {
if err = mysql.ctx.Err(); err != nil {
return
}
start := time.Now()
sqlrows, err := mysql.db(false).QueryContext(mysql.ctx, query, args...)
statsForRead(mysql.ctx, query, start)
if err != nil {
return
}
rows = &Rows{
ctx: mysql.ctx,
rows: sqlrows,
}
return
}
// QueryRow 查询一个带参数的查询,返回第一条结果。
// 如果查询出现错误,QueryRow 依然会保证返回一个合法的 row,但是调用 row.Scan() 会报错。
func (mysql *MySQL) QueryRow(query string, args ...interface{}) (row *Row, err error) {
if err = mysql.ctx.Err(); err != nil {
return
}
start := time.Now()
sqlrow := mysql.db(false).QueryRowContext(mysql.ctx, query, args...)
statsForRead(mysql.ctx, query, start)
row = &Row{
ctx: mysql.ctx,
row: sqlrow,
}
return
}
// Stats 返回数据库当前状态。
func (mysql *MySQL) Stats() sql.DBStats {
return mysql.db(false).Stats()
}
// UseMaster 返回一个 MySQL 实例,调用这个实例的所有方法都会调用主库。
func (mysql *MySQL) UseMaster() *MySQL {
cp := *mysql
cp.useMaster = true
return &cp
}
func (mysql *MySQL) db(forceMaster bool) *sql.DB {
if mysql.useMaster || forceMaster {
return mysql.master
}
return mysql.slave
}