@@ -4,8 +4,20 @@ import (
4
4
"database/sql"
5
5
"errors"
6
6
"fmt"
7
+ "sync/atomic"
7
8
)
8
9
10
+ var txCounter atomic.Uint64
11
+
12
+ // NextTransactionNo returns the next globally unique number
13
+ // for a new transaction in a threadsafe way.
14
+ //
15
+ // Use Connection.TransactionNo() to get the number
16
+ // from a transaction connection.
17
+ func NextTransactionNo () uint64 {
18
+ return txCounter .Add (1 )
19
+ }
20
+
9
21
// Transaction executes txFunc within a database transaction that is passed in to txFunc as tx Connection.
10
22
// Transaction returns all errors from txFunc or transaction commit errors happening after txFunc.
11
23
// If parentConn is already a transaction, then it is passed through to txFunc unchanged as tx Connection
@@ -31,9 +43,10 @@ func Transaction(parentConn Connection, opts *sql.TxOptions, txFunc func(tx Conn
31
43
// Errors and panics from txFunc will rollback the transaction.
32
44
// Recovered panics are re-paniced and rollback errors after a panic are logged with ErrLogger.
33
45
func IsolatedTransaction (parentConn Connection , opts * sql.TxOptions , txFunc func (tx Connection ) error ) (err error ) {
34
- tx , e := parentConn .Begin (opts )
46
+ txNo := NextTransactionNo ()
47
+ tx , e := parentConn .Begin (opts , txNo )
35
48
if e != nil {
36
- return fmt .Errorf ("Transaction Begin error: %w" , e )
49
+ return fmt .Errorf ("Transaction %d Begin error: %w" , txNo , e )
37
50
}
38
51
39
52
defer func () {
@@ -42,7 +55,7 @@ func IsolatedTransaction(parentConn Connection, opts *sql.TxOptions, txFunc func
42
55
e := tx .Rollback ()
43
56
if e != nil && ! errors .Is (e , sql .ErrTxDone ) {
44
57
// Double error situation, log e so it doesn't get lost
45
- ErrLogger .Printf ("Transaction error (%s) from rollback after panic: %+v" , e , r )
58
+ ErrLogger .Printf ("Transaction %d error (%s) from rollback after panic: %+v" , txNo , e , r )
46
59
}
47
60
panic (r ) // re-throw panic after Rollback
48
61
}
@@ -52,15 +65,15 @@ func IsolatedTransaction(parentConn Connection, opts *sql.TxOptions, txFunc func
52
65
e := tx .Rollback ()
53
66
if e != nil && ! errors .Is (e , sql .ErrTxDone ) {
54
67
// Double error situation, wrap err with e so it doesn't get lost
55
- err = fmt .Errorf ("Transaction error (%s) from rollback after error: %w" , e , err )
68
+ err = fmt .Errorf ("Transaction %d error (%s) from rollback after error: %w" , txNo , e , err )
56
69
}
57
70
return
58
71
}
59
72
60
73
e := tx .Commit ()
61
74
if e != nil {
62
75
// Set Commit error as function return value
63
- err = fmt .Errorf ("Transaction Commit error: %w" , e )
76
+ err = fmt .Errorf ("Transaction %d Commit error: %w" , txNo , e )
64
77
}
65
78
}()
66
79
0 commit comments