Skip to content

Commit 83fbe37

Browse files
committed
feat(database): Add performance related configuration settings
1 parent 7b808c2 commit 83fbe37

File tree

6 files changed

+125
-64
lines changed

6 files changed

+125
-64
lines changed

README.md

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -638,15 +638,22 @@ root of the project.
638638

639639
Each of these connection details can be overriden by an `ENV` variable.
640640

641-
| Setting | Description | YAML variable | Environment variable (ENV) | Default |
642-
| -------- | -------------------------------- | ------------- | -------------------------- | ----------- |
643-
| Host | The database host | `host` | `APP_DATABASE_HOST` | `localhost` |
644-
| Port | The database port | `port` | `APP_DATABASE_PORT` | `3306` |
645-
| Database | The database name | `database` | `APP_DATABASE_DATABASE` | |
646-
| Username | App user name | `username` | `APP_DATABASE_USERNAME` | |
647-
| Password | App user password | `password` | `APP_DATABASE_PASSWORD` | |
648-
| Pool | Connection pool size | `pool` | `APP_DATABASE_POOL` | `5` |
649-
| Timeout | Connection timeout (in seconds) | `timeout` | `APP_DATABASE_TIMEOUT` | `1s` |
641+
| Setting | Description | YAML variable | Environment variable (ENV) | Default |
642+
|-------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------|-------------------------------------------------|-------------|
643+
| Host | The database host | `host` | `APP_DATABASE_HOST` | `localhost` |
644+
| Port | The database port | `port` | `APP_DATABASE_PORT` | `3306` |
645+
| Database | The database name | `database` | `APP_DATABASE_DATABASE` | |
646+
| Username | App user name | `username` | `APP_DATABASE_USERNAME` | |
647+
| Password | App user password | `password` | `APP_DATABASE_PASSWORD` | |
648+
| Pool | Connection pool size | `pool` | `APP_DATABASE_POOL` | `5` |
649+
| Timeout | Connection timeout (in seconds) | `timeout` | `APP_DATABASE_TIMEOUT` | `1s` |
650+
| MaxOpenConnections | Sets the maximum number of open connections to the database. | `max_open_connections` | `APP_DATABASE_MAX_OPEN_CONNECTIONS` | `0` |
651+
| ConnectionMaxIdleTime | Sets the maximum amount of time a connection may be idle. | `connection_max_idle_time` | `APP_DATABASE_CONNECTION_MAX_IDLE_TIME` | `0` |
652+
| ConnectionMaxLifetime | Sets the maximum amount of time a connection may be reused | `connection_max_lifetime` | `APP_DATABASE_CONNECTION_MAX_LIFETIME` | `0s` |
653+
| DisableDefaultGormTransaction | Disables default GORM transaction wrapper for write operations | `disable_default_gorm_transaction` | `APP_DATABASE_DISABLE_DEFAULT_GORM_TRANSACTION` | `false` |
654+
| CachePreparedStatements | Enabled creating a prepared statement when executing any SQL and caches them to speed up future calls | `cache_prepared_statements` | `APP_DATABASE_CACHE_PREPARED_STATEMENTS` | `false` |
655+
| MysqlInterpolateParams | If set to `true`, placeholders (?) in calls to db.Query() and db.Exec() are interpolated into a single query string with given parameters. | `mysql_interpolate_params` | `APP_DATABASE_MYSQL_INTERPOLATE_PARAMS` | `false` |
656+
650657

651658
An example `database.yml`:
652659

pkg/database/config.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ type Config struct {
2323
MaxOpenConnections int `mapstructure:"max_open_connections"`
2424
ConnectionMaxIdleTime time.Duration `mapstructure:"connection_max_idle_time"`
2525
ConnectionMaxLifetime time.Duration `mapstructure:"connection_max_lifetime"`
26+
27+
// Performance settings
28+
DisableDefaultGormTransaction bool `mapstructure:"disable_default_gorm_transaction"`
29+
CachePreparedStatements bool `mapstructure:"cache_prepared_statements"`
30+
MysqlInterpolateParams bool `mapstructure:"mysql_interpolate_params"`
2631
}
2732

2833
// NewConfig returns a new Config instance.

pkg/database/config_test.go

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,32 +16,38 @@ func TestNewConfig(t *testing.T) {
1616
})
1717

1818
testCases := []struct {
19-
name string
20-
wantError bool
21-
host string
22-
port int
23-
username string
24-
password string
25-
database string
26-
timeout string
27-
pool int
28-
maxOpenConnections int
29-
connectionMaxIdleTime time.Duration
30-
connectionMaxLifetime time.Duration
19+
name string
20+
wantError bool
21+
host string
22+
port int
23+
username string
24+
password string
25+
database string
26+
timeout string
27+
pool int
28+
maxOpenConnections int
29+
connectionMaxIdleTime time.Duration
30+
connectionMaxLifetime time.Duration
31+
disableDefaultGormTransaction bool
32+
cachePreparedStatements bool
33+
mysqlInterpolateParams bool
3134
}{
3235
{
33-
name: "NewWithoutConfigFileFails",
34-
wantError: true,
35-
host: "",
36-
port: 0,
37-
username: "",
38-
password: "",
39-
database: "",
40-
timeout: "",
41-
pool: 0,
42-
maxOpenConnections: 0,
43-
connectionMaxIdleTime: 0,
44-
connectionMaxLifetime: 0,
36+
name: "NewWithoutConfigFileFails",
37+
wantError: true,
38+
host: "",
39+
port: 0,
40+
username: "",
41+
password: "",
42+
database: "",
43+
timeout: "",
44+
pool: 0,
45+
maxOpenConnections: 0,
46+
connectionMaxIdleTime: 0,
47+
connectionMaxLifetime: 0,
48+
disableDefaultGormTransaction: false,
49+
cachePreparedStatements: false,
50+
mysqlInterpolateParams: false,
4551
},
4652
}
4753

@@ -62,6 +68,9 @@ func TestNewConfig(t *testing.T) {
6268
assert.Equal(t, c.MaxOpenConnections, tc.maxOpenConnections)
6369
assert.Equal(t, c.ConnectionMaxIdleTime, tc.connectionMaxIdleTime)
6470
assert.Equal(t, c.ConnectionMaxLifetime, tc.connectionMaxLifetime)
71+
assert.Equal(t, c.DisableDefaultGormTransaction, tc.disableDefaultGormTransaction)
72+
assert.Equal(t, c.CachePreparedStatements, tc.cachePreparedStatements)
73+
assert.Equal(t, c.MysqlInterpolateParams, tc.mysqlInterpolateParams)
6574
})
6675
}
6776
}

pkg/database/connection_details.go

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,31 @@ import (
77

88
// ConnectionDetails represents database connection details.
99
type ConnectionDetails struct {
10-
Dialect string
11-
Username string
12-
Password string
13-
Host string
14-
Port int
15-
Database string
16-
Encoding string
17-
Timeout string
18-
Pool int
10+
Dialect string
11+
Username string
12+
Password string
13+
Host string
14+
Port int
15+
Database string
16+
Encoding string
17+
Timeout string
18+
Pool int
19+
MysqlInterpolateParams bool
1920
}
2021

2122
// NewConnectionDetails creates a new ConnectionDetails struct from a DB configuration.
2223
func NewConnectionDetails(config *Config) ConnectionDetails {
2324
return ConnectionDetails{
24-
Dialect: "mysql",
25-
Username: config.Username,
26-
Password: config.Password,
27-
Host: config.Host,
28-
Port: config.Port,
29-
Database: config.Database,
30-
Encoding: "utf8mb4_unicode_ci",
31-
Timeout: config.Timeout,
32-
Pool: config.Pool,
25+
Dialect: "mysql",
26+
Username: config.Username,
27+
Password: config.Password,
28+
Host: config.Host,
29+
Port: config.Port,
30+
Database: config.Database,
31+
Encoding: "utf8mb4_unicode_ci",
32+
Timeout: config.Timeout,
33+
Pool: config.Pool,
34+
MysqlInterpolateParams: config.MysqlInterpolateParams,
3335
}
3436
}
3537

@@ -69,6 +71,9 @@ func (cd ConnectionDetails) opts() string {
6971
"loc": "Local",
7072
"timeout": cd.Timeout,
7173
}
74+
if cd.MysqlInterpolateParams {
75+
options["interpolateParams"] = "true"
76+
}
7277

7378
var opts []string
7479

pkg/database/connection_details_test.go

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,16 @@ func TestString(t *testing.T) {
3434
{
3535
name: "WithAllAttributesPresent",
3636
config: &Config{
37-
Host: "192.168.1.1",
38-
Port: 8080,
39-
Username: "john",
40-
Password: "doe",
41-
Database: "microlith",
42-
Timeout: "10s",
37+
Host: "192.168.1.1",
38+
Port: 8080,
39+
Username: "john",
40+
Password: "doe",
41+
Database: "microlith",
42+
Timeout: "10s",
43+
MysqlInterpolateParams: true,
4344
},
4445
connectionString: "john:doe@tcp(192.168.1.1:8080)/microlith",
45-
optionsString: "timeout=10s",
46+
optionsString: "timeout=10s&interpolateParams=true",
4647
},
4748
{
4849
name: "WithOneAttributeBlank",
@@ -118,12 +119,13 @@ func TestStringWithoutDB(t *testing.T) {
118119

119120
func TestOpts(t *testing.T) {
120121
cases := []struct {
121-
name string
122-
details ConnectionDetails
123-
timeout string
124-
charset string
125-
parseTime string
126-
loc string
122+
name string
123+
details ConnectionDetails
124+
timeout string
125+
charset string
126+
parseTime string
127+
loc string
128+
interpolateParams bool
127129
}{
128130
{
129131
name: "WithPresentTimeout",
@@ -145,6 +147,24 @@ func TestOpts(t *testing.T) {
145147
parseTime: "parseTime=True",
146148
loc: "loc=Local",
147149
},
150+
{
151+
name: "WithMysqlInterpolateParams",
152+
timeout: "timeout=1s",
153+
charset: "charset=utf8",
154+
parseTime: "parseTime=True",
155+
loc: "loc=Local",
156+
details: ConnectionDetails{
157+
MysqlInterpolateParams: true,
158+
},
159+
interpolateParams: true,
160+
},
161+
{
162+
name: "WithNoMysqlInterpolateParams",
163+
timeout: "timeout=1s",
164+
charset: "charset=utf8",
165+
parseTime: "parseTime=True",
166+
loc: "loc=Local",
167+
},
148168
}
149169

150170
for _, c := range cases {
@@ -155,6 +175,12 @@ func TestOpts(t *testing.T) {
155175
assert.Contains(t, got, c.charset)
156176
assert.Contains(t, got, c.parseTime)
157177
assert.Contains(t, got, c.loc)
178+
179+
if c.interpolateParams {
180+
assert.Contains(t, got, "interpolateParams=true")
181+
} else {
182+
assert.NotContains(t, got, "interpolateParams=true")
183+
}
158184
})
159185
}
160186
}

pkg/database/gorm.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ func NewConnection(config *Config, environment, appName string) (*gorm.DB, error
4141
databasePoolSettings(sqlDB, config)
4242

4343
dialector := mysql.New(mysql.Config{Conn: sqlDB})
44+
45+
gormConfig := &gorm.Config{}
46+
if config.DisableDefaultGormTransaction {
47+
gormConfig.SkipDefaultTransaction = true
48+
}
49+
if config.CachePreparedStatements {
50+
gormConfig.PrepareStmt = true
51+
}
52+
4453
db, err := gormtrace.Open(dialector, nil, gormtrace.WithServiceName(serviceName))
4554
if err != nil {
4655
return nil, err

0 commit comments

Comments
 (0)