1
1
# dbresolver
2
+
2
3
Golang Database Resolver and Wrapper for any multiple database connections topology, eg. master-slave replication database, cross-region application.
3
4
4
5
[ ![ Go] ( https://github.com/bxcodec/dbresolver/actions/workflows/go.yml/badge.svg?branch=main )] ( https://github.com/bxcodec/dbresolver/actions/workflows/go.yml )
5
6
[ ![ Go.Dev] ( https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white )] ( https://pkg.go.dev/github.com/bxcodec/dbresolver?tab=doc )
6
7
7
8
## Idea and Inspiration
8
9
9
- This DBResolver library will split your connections to correct defined DBs. Eg, all read query will routed to ReadOnly replica db, and all write operation(Insert, Update, Delete) will routed to Primary/Master DB.
10
+ This DBResolver library will split your connections to correct defined DBs. Eg, all read query will routed to ReadOnly replica db, and all write operation(Insert, Update, Delete) will routed to Primary/Master DB.
10
11
11
12
Read more for the explanation on this [ blog post] ( https://betterprogramming.pub/create-a-cross-region-rdbms-connection-library-with-dbresolver-5072bed6a7b8 )
12
13
13
14
### Usecase 1: Separated RW and RO Database connection
15
+
14
16
<details open >
15
17
16
18
<summary >Click to Expand</summary >
17
19
18
20
- You have your application deployed
19
21
- Your application is heavy on read operations
20
22
- Your DBs replicated to multiple replicas for faster queries
21
- - You separate the connections for optimized query
22
- - ![ image] ( https://user-images.githubusercontent.com/11002383/180010864-c9e2a0b6-520d-48d6-bf0d-490eb070e75d.png )
23
+ - You separate the connections for optimized query
24
+ - ![ image] ( https://user-images.githubusercontent.com/11002383/180010864-c9e2a0b6-520d-48d6-bf0d-490eb070e75d.png )
23
25
24
26
</details >
25
27
26
28
### Usecases 2: Cross Region Database
29
+
27
30
<details open >
28
31
29
32
<summary >Click to Expand</summary >
@@ -37,19 +40,20 @@ Read more for the explanation on this [blog post](https://betterprogramming.pub/
37
40
## Support
38
41
39
42
You can file an [ Issue] ( https://github.com/bxcodec/dbresolver/issues/new ) .
40
- See documentation in [ Go.Dev] ( https://pkg.go.dev/github.com/bxcodec/dbresolver?tab=doc )
43
+ See documentation in [ Go.Dev] ( https://pkg.go.dev/github.com/bxcodec/dbresolver/v2 ?tab=doc )
41
44
42
45
## Getting Started
43
46
44
47
#### Download
45
48
46
49
``` shell
47
- go get -u github.com/bxcodec/dbresolver
50
+ go get -u github.com/bxcodec/dbresolver/v2
48
51
```
49
52
50
53
# Example
51
54
52
- ### With Multi * sql.DB
55
+ ### With Multi \* sql.DB
56
+
53
57
<details open >
54
58
55
59
<summary >Click to Expand</summary >
@@ -61,12 +65,13 @@ import (
61
65
" context"
62
66
" database/sql"
63
67
" fmt"
68
+ " log"
64
69
65
- " github.com/bxcodec/dbresolver"
70
+ " github.com/bxcodec/dbresolver/v2 "
66
71
_ " github.com/lib/pq"
67
72
)
68
73
69
- func main () {
74
+ func ExampleWrapDBs () {
70
75
var (
71
76
host1 = " localhost"
72
77
port1 = 5432
@@ -85,36 +90,41 @@ func main() {
85
90
// open database for primary
86
91
dbPrimary , err := sql.Open (" postgres" , rwPrimary)
87
92
if err != nil {
88
- panic (err )
93
+ log. Print ( " go error when connecting to the DB " )
89
94
}
90
- // configure the DBs for other setup eg, tracing, etc
95
+ // configure the DBs for other setup eg, tracing, etc
91
96
// eg, tracing.Postgres(dbPrimary)
92
97
93
98
// open database for replica
94
99
dbReadOnlyReplica , err := sql.Open (" postgres" , readOnlyReplica)
95
100
if err != nil {
96
- panic (err )
101
+ log. Print ( " go error when connecting to the DB " )
97
102
}
98
- // configure the DBs for other setup eg, tracing, etc
103
+ // configure the DBs for other setup eg, tracing, etc
99
104
// eg, tracing.Postgres(dbReadOnlyReplica)
100
105
101
- connectionDB := dbresolver.WrapDBs (dbPrimary, dbReadOnlyReplica)
106
+ connectionDB := dbresolver.NewResolver (
107
+ dbresolver.WithPrimaryDBs (dbPrimary),
108
+ dbresolver.WithReplicaDBs (dbReadOnlyReplica),
109
+ dbresolver.WithLoadBalancer (dbresolver.RoundRobinLB ))
102
110
103
- // now you can use the connection for all DB operation
111
+ // now you can use the connection for all DB operation
104
112
_, err = connectionDB.ExecContext (context.Background (), " DELETE FROM book WHERE id=$1" ) // will use primaryDB
105
113
if err != nil {
106
- panic ( err)
114
+ log. Print ( " go error when executing the query to the DB " , err)
107
115
}
108
116
_ = connectionDB.QueryRowContext (context.Background (), " SELECT * FROM book WHERE id=$1" ) // will use replicaReadOnlyDB
109
117
118
+ // Output:
119
+ //
110
120
}
111
121
112
122
```
113
123
114
124
</details >
115
125
116
-
117
126
### With Multi Connection String
127
+
118
128
<details open >
119
129
120
130
<summary >Click to Expand</summary >
@@ -125,12 +135,13 @@ package main
125
135
import (
126
136
" context"
127
137
" fmt"
138
+ " log"
128
139
129
- " github.com/bxcodec/dbresolver"
140
+ " github.com/bxcodec/dbresolver/v2 "
130
141
_ " github.com/lib/pq"
131
142
)
132
143
133
- func main () {
144
+ func ExampleOpen () {
134
145
var (
135
146
host1 = " localhost"
136
147
port1 = 5432
@@ -147,17 +158,76 @@ func main() {
147
158
readOnlyReplica := fmt.Sprintf (" host=%s port=%d user=%s password=%s dbname=%s sslmode=disable" , host2, port2, user2, password2, dbname)
148
159
connectionDB , err := dbresolver.Open (" postgres" , fmt.Sprintf (" %s ;%s " , rwPrimary, readOnlyReplica))
149
160
if err != nil {
150
- panic ( err)
161
+ log. Print ( " go error when connecting to the DB " , err)
151
162
}
152
163
153
- // now you can use the connection for all DB operation
164
+ // now you can use the connection for all DB operation
154
165
_, err = connectionDB.ExecContext (context.Background (), " DELETE FROM book WHERE id=$1" ) // will use primaryDB
155
166
if err != nil {
156
- panic ( err)
167
+ log. Print ( " go error when connecting to the DB " , err)
157
168
}
158
169
_ = connectionDB.QueryRowContext (context.Background (), " SELECT * FROM book WHERE id=$1" ) // will use replicaReadOnlyDB
159
170
171
+ // Output:
172
+ //
173
+ }
160
174
175
+ ```
176
+
177
+ </details >
178
+
179
+ ### With Multi Master (Primary) Connection String
180
+
181
+ <details open >
182
+
183
+ <summary >Click to Expand</summary >
184
+
185
+ ``` go
186
+ package main
187
+
188
+ import (
189
+ " context"
190
+ " fmt"
191
+ " log"
192
+
193
+ " github.com/bxcodec/dbresolver/v2"
194
+ _ " github.com/lib/pq"
195
+ )
196
+
197
+ func ExampleOpenMultiPrimary () {
198
+ var (
199
+ host1 = " localhost"
200
+ port1 = 5432
201
+ user1 = " postgresrw"
202
+ password1 = " <password>"
203
+ host2 = " localhost"
204
+ port2 = 5433
205
+ user2 = " postgresro"
206
+ password2 = " <password>"
207
+ dbname = " <dbname>"
208
+ )
209
+ // connection string
210
+ rwPrimary1 := fmt.Sprintf (" host=%s port=%d user=%s password=%s dbname=%s sslmode=disable" , host1, port1, user1, password1, dbname)
211
+ rwPrimary2 := fmt.Sprintf (" host=%s port=%d user=%s password=%s dbname=%s sslmode=disable" , host2, port2, user2, password2, dbname)
212
+ readOnlyReplica1 := fmt.Sprintf (" host=%s port=%d user=%s password=%s dbname=%s sslmode=disable" , host1, port1, user1, password1, dbname)
213
+ readOnlyReplica2 := fmt.Sprintf (" host=%s port=%d user=%s password=%s dbname=%s sslmode=disable" , host2, port2, user2, password2, dbname)
214
+
215
+ rwPrimary := fmt.Sprintf (" %s ;%s " , rwPrimary1, rwPrimary2)
216
+ readOnlyReplica := fmt.Sprintf (" %s ;%s " , readOnlyReplica1, readOnlyReplica2)
217
+ connectionDB , err := dbresolver.Open (" postgres" , fmt.Sprintf (" %s ;%s " , rwPrimary, readOnlyReplica))
218
+ if err != nil {
219
+ log.Print (" go error when connecting to the DB" , err)
220
+ }
221
+
222
+ // now you can use the connection for all DB operation
223
+ _, err = connectionDB.ExecContext (context.Background (), " DELETE FROM book WHERE id=$1" ) // will use primaryDB
224
+ if err != nil {
225
+ log.Print (" go error when connecting to the DB" , err)
226
+ }
227
+ _ = connectionDB.QueryRowContext (context.Background (), " SELECT * FROM book WHERE id=$1" ) // will use replicaReadOnlyDB
228
+
229
+ // Output:
230
+ //
161
231
}
162
232
163
233
```
@@ -166,7 +236,7 @@ func main() {
166
236
167
237
## Important Notes
168
238
169
- - Primary Database will be used when you call these functions
239
+ - Primary Database will be used when you call these functions
170
240
- ` Exec `
171
241
- ` ExecContext `
172
242
- ` Begin ` (transaction will use primary)
@@ -178,6 +248,7 @@ func main() {
178
248
- ` QueryRowContext `
179
249
180
250
## Contribution
251
+
181
252
---
182
253
183
254
To contrib to this project, you can open a PR or an issue.
0 commit comments