Skip to content

Commit f25e26f

Browse files
authored
Merge pull request #6 from BrandonRoehl/single-transaction
Single transaction
2 parents cd198d0 + 5c7d255 commit f25e26f

File tree

7 files changed

+113
-89
lines changed

7 files changed

+113
-89
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
language: go
22

33
go:
4-
- 1.11.x
4+
- 1.13.x
55
- master
66

77
script:

dump.go

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package mysqldump
22

33
import (
44
"bytes"
5+
"context"
56
"database/sql"
67
"errors"
78
"fmt"
@@ -14,9 +15,11 @@ import (
1415
/*
1516
Data struct to configure dump behavior
1617
17-
Out: Stream to wite to
18-
Connection: Database connection to dump
19-
IgnoreTables: Mark sensitive tables to ignore
18+
Out: Stream to wite to
19+
Connection: Database connection to dump
20+
IgnoreTables: Mark sensitive tables to ignore
21+
MaxAllowedPacket: Sets the largest packet size to use in backups
22+
LockTables: Lock all tables for the duration of the dump
2023
*/
2124
type Data struct {
2225
Out io.Writer
@@ -25,6 +28,7 @@ type Data struct {
2528
MaxAllowedPacket int
2629
LockTables bool
2730

31+
tx *sql.Tx
2832
headerTmpl *template.Template
2933
tableTmpl *template.Template
3034
footerTmpl *template.Template
@@ -123,11 +127,19 @@ func (data *Data) Dump() error {
123127
data.MaxAllowedPacket = defaultMaxAllowedPacket
124128
}
125129

126-
if err := meta.updateServerVersion(data.Connection); err != nil {
130+
if err := data.getTemplates(); err != nil {
127131
return err
128132
}
129133

130-
if err := data.getTemplates(); err != nil {
134+
// Start the read only transaction and defer the rollback until the end
135+
// This way the database will have the exact state it did at the begining of
136+
// the backup and nothing can be accidentally committed
137+
if err := data.begin(); err != nil {
138+
return err
139+
}
140+
defer data.rollback()
141+
142+
if err := meta.updateServerVersion(data); err != nil {
131143
return err
132144
}
133145

@@ -173,6 +185,21 @@ func (data *Data) Dump() error {
173185

174186
// MARK: - Private methods
175187

188+
// begin starts a read only transaction that will be whatever the database was
189+
// when it was called
190+
func (data *Data) begin() (err error) {
191+
data.tx, err = data.Connection.BeginTx(context.Background(), &sql.TxOptions{
192+
Isolation: sql.LevelRepeatableRead,
193+
ReadOnly: true,
194+
})
195+
return
196+
}
197+
198+
// rollback cancels the transaction
199+
func (data *Data) rollback() error {
200+
return data.tx.Rollback()
201+
}
202+
176203
// MARK: writter methods
177204

178205
func (data *Data) dumpTable(name string) error {
@@ -214,7 +241,7 @@ func (data *Data) getTemplates() (err error) {
214241
func (data *Data) getTables() ([]string, error) {
215242
tables := make([]string, 0)
216243

217-
rows, err := data.Connection.Query("SHOW TABLES")
244+
rows, err := data.tx.Query("SHOW TABLES")
218245
if err != nil {
219246
return tables, err
220247
}
@@ -241,10 +268,10 @@ func (data *Data) isIgnoredTable(name string) bool {
241268
return false
242269
}
243270

244-
func (data *metaData) updateServerVersion(db *sql.DB) (err error) {
271+
func (meta *metaData) updateServerVersion(data *Data) (err error) {
245272
var serverVersion sql.NullString
246-
err = db.QueryRow("SELECT version()").Scan(&serverVersion)
247-
data.ServerVersion = serverVersion.String
273+
err = data.tx.QueryRow("SELECT version()").Scan(&serverVersion)
274+
meta.ServerVersion = serverVersion.String
248275
return
249276
}
250277

@@ -263,7 +290,7 @@ func (table *table) NameEsc() string {
263290

264291
func (table *table) CreateSQL() (string, error) {
265292
var tableReturn, tableSQL sql.NullString
266-
if err := table.data.Connection.QueryRow("SHOW CREATE TABLE "+table.NameEsc()).Scan(&tableReturn, &tableSQL); err != nil {
293+
if err := table.data.tx.QueryRow("SHOW CREATE TABLE "+table.NameEsc()).Scan(&tableReturn, &tableSQL); err != nil {
267294
return "", err
268295
}
269296

@@ -274,13 +301,12 @@ func (table *table) CreateSQL() (string, error) {
274301
return tableSQL.String, nil
275302
}
276303

277-
// defer rows.Close()
278304
func (table *table) Init() (err error) {
279305
if len(table.types) != 0 {
280306
return errors.New("can't init twice")
281307
}
282308

283-
table.rows, err = table.data.Connection.Query("SELECT * FROM " + table.NameEsc())
309+
table.rows, err = table.data.tx.Query("SELECT * FROM " + table.NameEsc())
284310
if err != nil {
285311
return err
286312
}
@@ -299,6 +325,7 @@ func (table *table) Init() (err error) {
299325
}
300326

301327
table.types = make([]reflect.Type, len(tt))
328+
table.values = make([]interface{}, len(tt))
302329
for i, tp := range tt {
303330
st := tp.ScanType()
304331
if tp.DatabaseTypeName() == "BLOB" {
@@ -312,9 +339,6 @@ func (table *table) Init() (err error) {
312339
} else {
313340
table.types[i] = reflect.TypeOf(sql.NullString{})
314341
}
315-
}
316-
table.values = make([]interface{}, len(tt))
317-
for i := range table.values {
318342
table.values[i] = reflect.New(table.types[i]).Interface()
319343
}
320344
return nil

0 commit comments

Comments
 (0)