- Created by 郭强, last modified by 海亮 on May 28, 2024
配置文件
我们推荐使用配置组件来管理数据库配置,并使用g
对象管理模块中的g.DB("数据库分组名称")
方法获取数据库操作对象,数据库对象将会自动读取配置组件中的相应配置项,并自动初始化该数据库操作的单例对象。数据库配置管理功能使用的是配置管理组件实现(配置组件采用接口化设计默认使用文件系统实现),同样支持多种数据格式如:toml/yaml/json/xml/ini/properties
。默认并且推荐的配置文件数据格式为yaml
。
简单配置
从v2.2.0
版本开始,使用link
进行数据库配置时,数据库组件统一了不同数据库类型的配置格式,以简化配置管理。
简化配置通过配置项link
指定,格式如下:
type:username:password@protocol(address)[/dbname][?param1=value1&...¶mN=valueN]
即:
类型:账号:密码@协议(地址)/数据库名称?特性配置
其中:
- 数据库名称 及 特性配置为非必须参数,其他参数为必须参数。
- 协议可选配置为:
tcp/udp/file
,常见配置为tcp
- 特性配置根据不同的数据库类型,由其底层实现的第三方驱动定义,具体需要参考第三方驱动官网。例如,针对
mysql
驱动而言,使用的第三方驱动为:https://github.com/go-sql-driver/mysql 支持的特性配置如multiStatements
和loc
等。
示例:
database: default: link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test" user: link: "sqlite::@file(/var/data/db.sqlite3)"
不同数据类型对应的link
示例如下:
类型 | link示例 | extra参数 |
---|---|---|
mysql | mysql:root:12345678@tcp(127.0.0.1:3306)/test?loc=Local&parseTime=true | mysql |
mariadb | mariadb:root:12345678@tcp(127.0.0.1:3306)/test?loc=Local&parseTime=true | mysql |
tidb | tidb:root:12345678@tcp(127.0.0.1:3306)/test?loc=Local&parseTime=true | mysql |
pgsql | pgsql:root:12345678@tcp(127.0.0.1:5432)/test | pq |
mssql |
| go-mssqldb |
sqlite | sqlite::@file(/var/data/db.sqlite3) (可以使用相对路径,如: | go-sqlite3 |
oracle | oracle:root:12345678@tcp(127.0.0.1:5432)/test | go-oci8 |
clickhouse | clickhouse:root:12345678@tcp(127.0.0.1:9000)/test | |
dm | dm:root:12345678@tcp(127.0.0.1:5236)/test |
更多框架支持的数据库类型请参考:https://github.com/gogf/gf/tree/master/contrib/drivers
完整配置
完整的config.yaml
数据库配置项的数据格式形如下:
database: 分组名称: host: "地址" port: "端口" user: "账号" pass: "密码" name: "数据库名称" type: "数据库类型(如:mariadb/tidb/mysql/pgsql/mssql/sqlite/oracle/clickhouse/dm)" link: "(可选)自定义数据库链接信息,当该字段被设置值时,以上链接字段(Host,Port,User,Pass,Name)将失效,但是type必须有值" extra: "(可选)不同数据库的额外特性配置,由底层数据库driver定义" role: "(可选)数据库主从角色(master/slave),不使用应用层的主从机制请均设置为master" debug: "(可选)开启调试模式" prefix: "(可选)表名前缀" dryRun: "(可选)ORM空跑(只读不写)" charset: "(可选)数据库编码(如: utf8/gbk/gb2312),一般设置为utf8" protocol: "(可选)数据库连接协议,默认为TCP" weight: "(可选)负载均衡权重,用于负载均衡控制,不使用应用层的负载均衡机制请置空" timezone: "(可选)时区配置,例如:Local" namespace: "(可选)用以支持个别数据库服务Catalog&Schema区分的问题,原有的Schema代表数据库名称,而NameSpace代表个别数据库服务的Schema" maxIdle: "(可选)连接池最大闲置的连接数(默认10)" maxOpen: "(可选)连接池最大打开的连接数(默认无限制)" maxLifetime: "(可选)连接对象可重复使用的时间长度(默认30秒)" queryTimeout: "(可选)查询语句超时时长(默认无限制,注意ctx的超时时间设置)" execTimeout: "(可选)写入语句超时时长(默认无限制,注意ctx的超时时间设置)" tranTimeout: "(可选)事务处理超时时长(默认无限制,注意ctx的超时时间设置)" prepareTimeout: "(可选)预准备SQL语句执行超时时长(默认无限制,注意ctx的超时时间设置)" createdAt: "(可选)自动创建时间字段名称" updatedAt: "(可选)自动更新时间字段名称" deletedAt: "(可选)软删除时间字段名称" timeMaintainDisabled: "(可选)是否完全关闭时间更新特性,true时CreatedAt/UpdatedAt/DeletedAt都将失效"
完整的数据库配置项示例(YAML
):
database: default: host: "127.0.0.1" port: "3306" user: "root" pass: "12345678" name: "test" type: "mysql" extra: "parseTime=true" role: "master" debug: "true" dryrun: 0 weight: "100" prefix: "gf_" charset: "utf8" timezone: "Local" maxIdle: "10" maxOpen: "100" maxLifetime: "30s" protocol
使用该配置方式时,为保证数据库安全,默认底层不支持多行SQL
语句执行。为了得到更多配置项控制,请参考推荐的简化配置,同时建议您务必了解清楚简化配置项中每个连接参数的功能作用。
集群模式
gdb
的配置支持集群模式,数据库配置中每一项分组配置均可以是多个节点,支持负载均衡权重策略,例如:
database: default: - link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test" role: "master" - link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test" role: "slave" user: - link: "mysql:root:12345678@tcp(127.0.0.1:3306)/user" role: "master" - link: "mysql:root:12345678@tcp(127.0.0.1:3306)/user" role: "slave" - link: "mysql:root:12345678@tcp(127.0.0.1:3306)/user" role: "slave"
以上数据库配置示例中包含两个数据库分组default
和user
,其中default
分组包含一主一从,user
分组包含一主两从。在代码中可以通过g.DB()
和g.DB("user")
获取对应的数据库连接对象。
日志配置
gdb
支持日志输出,内部使用的是glog.Logger
对象实现日志管理,并且可以通过配置文件对日志对象进行配置。默认情况下gdb
关闭了DEBUG
日志输出,如果需要打开DEBUG
信息需要将数据库的debug
参数设置为true
。以下是为一个配置文件示例:
database: logger: path: "/var/log/gf-app/sql" level: "all" stdout: true default: link: "mysql:root:12345678@tcp(127.0.0.1:3306)/user_center" debug: true
其中database.logger
即为gdb
的日志配置,当该配置不存在时,将会使用日志组件的默认配置,具体请参考 日志组件-配置管理 章节。
需要注意哦:由于ORM
底层都是采用安全的预处理执行方式,提交到底层的SQL
与参数其实是分开的,因此日志中记录的完整SQL
仅作参考方便人工阅读,并不是真正提交到底层的SQL
语句。
原生配置(高阶,可选)
以下为数据库底层管理配置介绍,如果您对数据库的底层配置管理比较感兴趣,可继续阅读后续章节。
数据结构
gdb
数据库管理模块的内部配置管理数据结构如下:
ConfigNode
用于存储一个数据库节点信息;ConfigGroup
用于管理多个数据库节点组成的配置分组(一般一个分组对应一个业务数据库集群);Config
用于管理多个ConfigGroup
配置分组。
配置管理特点:
- 支持多节点数据库集群管理;
- 每个节点可以单独配置连接属性;
- 采用单例模式管理数据库实例化对象;
- 支持对数据库集群分组管理,按照分组名称获取实例化的数据库操作对象;
- 支持多种关系型数据库管理,可通过
ConfigNode.Type
属性进行配置; - 支持
Master-Slave
读写分离,可通过ConfigNode.Role
属性进行配置; - 支持客户端的负载均衡管理,可通过
ConfigNode.Weight
属性进行配置,值越大,优先级越高;
type Config map[string]ConfigGroup // 数据库配置对象 type ConfigGroup []ConfigNode // 数据库分组配置 // 数据库配置项(一个分组配置对应多个配置项) type ConfigNode struct { Host string // 地址 Port string // 端口 User string // 账号 Pass string // 密码 Name string // 数据库名称 Type string // 数据库类型:mysql, sqlite, mssql, pgsql, oracle Link string // (可选)自定义链接信息,当该字段被设置值时,以上链接字段(Host,Port,User,Pass,Name)将失效(该字段是一个扩展功能) Extra string // (可选)不同数据库的额外特性配置,由底层数据库driver定义 Role string // (可选,默认为master)数据库的角色,用于主从操作分离,至少需要有一个master,参数值:master, slave Debug bool // (可选)开启调试模式 Charset string // (可选,默认为 utf8)编码,默认为 utf8 Prefix string // (可选)表名前缀 Weight int // (可选)用于负载均衡的权重计算,当集群中只有一个节点时,权重没有任何意义 MaxIdleConnCount int // (可选)连接池最大闲置的连接数 MaxOpenConnCount int // (可选)连接池最大打开的连接数 MaxConnLifetime time.Duration // (可选,单位秒)连接对象可重复使用的时间长度 }
特别说明,gdb
的配置管理最大的特点是,(同一进程中)所有的数据库集群信息都使用同一个配置管理模块进行统一维护,不同业务的数据库集群配置使用不同的分组名称进行配置和获取。
配置方法
这是原生调用gdb
模块来配置管理数据库。如果开发者想要自行控制数据库配置管理可以参考以下方法。若无需要可忽略该章节。
接口文档: https://pkg.go.dev/github.com/gogf/gf/v2/database/gdb
// 添加一个数据库节点到指定的分组中 func AddConfigNode(group string, node ConfigNode) // 添加一个配置分组到数据库配置管理中(同名覆盖) func AddConfigGroup(group string, nodes ConfigGroup) // 添加一个数据库节点到默认的分组中(默认为default,可修改) func AddDefaultConfigNode(node ConfigNode) // 添加一个配置分组到数据库配置管理中(默认分组为default,可修改) func AddDefaultConfigGroup(nodes ConfigGroup) // 设置默认的分组名称,获取默认数据库对象时将会自动读取该分组配置 func SetDefaultGroup(groupName string) // 设置数据库配置为定义的配置信息,会将原有配置覆盖 func SetConfig(c Config)
默认分组表示,如果获取数据库对象时不指定配置分组名称,那么gdb
默认读取的配置分组。例如:gdb.NewByGroup()
可获取一个默认分组的数据库对象。简单的做法,我们可以通过gdb
包的SetConfig
配置管理方法进行自定义的数据库全局配置,例如:
gdb.SetConfig(gdb.Config { "default" : gdb.ConfigGroup { gdb.ConfigNode { Host : "192.168.1.100", Port : "3306", User : "root", Pass : "123456", Name : "test", Type : "mysql", Role : "master", Weight : 100, }, gdb.ConfigNode { Host : "192.168.1.101", Port : "3306", User : "root", Pass : "123456", Name : "test", Type : "mysql", Role : "slave", Weight : 100, }, }, "user-center" : gdb.ConfigGroup { gdb.ConfigNode { Host : "192.168.1.110", Port : "3306", User : "root", Pass : "123456", Name : "test", Type : "mysql", Role : "master", Weight : 100, }, }, })
随后,我们可以使用gdb.NewByGroup("数据库分组名称")
来获取一个数据库操作对象。该对象用于后续的数据库一系列方法/链式操作。
常见问题
如何实现数据库账号密码在配置文件中加密
在某些场景下,数据库的账号密码无法明文配置到配置文件中,需要进行一定的加密。在连接数据库的时候,再对配置文件中加密的字段进行解密处理。这种需求可以通过自定义Driver
来实现(关于Driver
的详细介绍请参考章节:ORM接口开发)。以mysql
为例,我们可以自己编写一个Driver
,包裹框架社区组件中的mysql driver
,并且覆盖它的Open
方法即可。代码示例:
import ( "database/sql" "github.com/gogf/gf/contrib/drivers/mysql/v2" "github.com/gogf/gf/v2/database/gdb" ) type MyBizDriver struct { mysql.Driver } // Open creates and returns an underlying sql.DB object for mysql. // Note that it converts time.Time argument to local timezone in default. func (d *MyBizDriver) Open(config *gdb.ConfigNode) (db *sql.DB, err error) { config.User = d.decode(config.User) config.Pass = d.decode(config.Pass) return d.Driver.Open(config) } func (d *MyBizDriver) decode(s string) string { // 执行字段解密处理逻辑 // ... return s }
- No labels
40 Comments
朱华 Hunk
在v2下使用sqlite时,使用该文档所述的link格式 (即sqlite::@file(文件名) ),结果一直报error14,打不开数据库。后面采用 sqlite: 文件名,则成功打开数据库。文档这里关于sqlite的使用是否存在问题?
郭强
这个格式是从
v2.2
版本开始支持,请使用最新版本框架。zuns
配置中的updatedAt 自动更新的值是个字符串 “2022-10-14 13:46:09” 有没有指定用时间戳来替代该字符串时间的配置
18lkdev
郭强 这里时间戳自己转?
MagicGirlYoYo
使用pgsql的时候报:Error: missing "=" after "postgres:123456@tcp(localhost:5432)/dev_db" in connection info string"
郭强
仔细看下文档
pgsql:root:12345678@tcp(127.0.0.1:5432)/test
MagicGirlYoYo
我的数据库配置是这样的
郭强
也要同时升级driver:
go get -u github.com/gogf/gf/contrib/drivers/mysql/v2
MagicGirlYoYo
感谢老哥,升级一下就没问题了
chenwei
我也遇到了相同的问题,没看懂你们是怎么解决的。我的做法是把mysql/v2屏蔽了,打开了pgsql/v2
2024-04-22 09:55:24.117 [ERRO] {384e82076177c81786a5b441a6bf7d52} D:/GO/GoFrame/hotgo/server/utility/simple/simple.go:114: SafeGo exec failed:casbin.NewAdapter err .
CREATE TABLE IF NOT EXISTS hg_admin_role_casbin (
id bigint(20) NOT NULL AUTO_INCREMENT,
p_type varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
v0 varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
v1 varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
v2 varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
v3 varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
v4 varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
v5 varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (id) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '管理员_casbin权限表' ROW_FORMAT = Dynamic;
: missing "=" after "postgres:123456@tcp(127.0.0.1:5432)/hotgo" in connection info string"
1. casbin.NewAdapter err .
cbqi
这个有类似gorm的migration功能吗,表还是要自己提前创建好吗,那修改表结构不是很麻烦
一只喜羊羊呀
貌似没有,需要自己导SQL文件
caiwenjun
你最后咋整的放弃这个框架了吗?还是手工维护sql文件
wangshuai
连接clickhouse查询数据,请问这个错误和版本有关系嘛
CLI Built Detail:
Go Version: go1.19.2
GF Version: v2.2.5
Git Commit: none
Build Time: 2022-11-29 16:16:54
clickhouse版本:22.2.2
配置文件:
异常日志:
[clickhouse][conn=1][XXX.XXX.XXX.XXX:9000][send query] compression=%!t(clickhouse.CompressionMethod=2) select * from 表名 where name= 'sss'
[clickhouse][conn=1][XXX.XXX.XXX.XXX:9000][send data] compression=%!t(clickhouse.CompressionMethod=2)
[clickhouse][conn=1][XXX.XXX.XXX.XXX:9000][exception] code: 115, message: Unknown setting charset
2022-11-30 11:17:18.817 [ERRO] {285d7715763e2c1752303151bcfd403a} [ 80 ms] [ck] [default] [rows:0 ] select * from 表名 where name= 'sss'
Error: code: 115, message: Unknown setting charset
咸鱼老罗
sqlite数据库在开发模式下可以使用相对路径,相对路径由项目路径开始
下面配置将会读取文件的路径:项目文件夹/manifest/document/sqlite/focus.db
database:
default:
link: "sqlite::@file(manifest/document/sqlite/focus.db)"
Ocean
有微信交流群吗? 求拉
智刚
这个页面有微信群的信息 框架介绍(最新版本)
Kri6
GoFrame CLI Tool v2.3.1 pgsql 遇到的一些问题(已解决
cannot find database driver for specified database type "pgsql", did you misspell type name "pgsql" or forget importing the database driver? possible reference: https://github.com/gogf/gf/tree/master/contrib/drivers
遇到此问题 不需要下载CLI源码 添加驱动编译!!!
并在 main.go 添加
如果gen dao 生成代码报错 同样执行以上步骤 重新 gen dao
其他数据库同理
gf 默认支持的数据库 https://github.com/gogf/gf/tree/master/contrib/drivers
saner.qu
pgsql有个关于表别名的BUG:
代码:
----------------------------------------
出错信息:
SELECT A.*,B.c_name AS c_org_name FROM "tb_base_dept" AS A LEFT JOIN\"tb_base_org" AS "B" ON (A.c_org_id=B.id) WHERE "A"."deleted_at" IS NULL AND "B"."deleted_at" IS NULL: pq: 对于表\"b\",丢失FROM子句项
--------------------------------------------
原因分析:
在生成的SQL语句中,发现两个表的别名A和B,有些有双引号,有些没有(当然其中也有我的代码中硬编码的也没有加双引号),
如果将所有硬编码部分的A、B都写成"\"A\"" "\"B\""这样也是可以的,但显得非常麻烦,而且容易出错
这个问题应该是仅出现在多表操作时,单表操作没有发现这个问题
Tzu Chieh Li
pgsql 我看是使用 lib/pq , lib/pq 已進入維護模式不再新增功能
有考慮更換為 pgx 嗎?
郭强
可以提pr哈
MagicGirlYoYo
提一个bug,达梦数据库link`dm:root:12345678@tcp(127.0.0.1:5236)/test` 这么写的的话会出现不指定达梦模式的问题,需要这样写才能指定连接模式 `dm:root:12345678@tcp(127.0.0.1:5236)/test?schema=test`
郭强
看起来似乎是配置的问题,如果觉得是BUG欢迎提PR参与共建。
zhonghunxunGM
hi, bro!
I am working on upgrading Dameng content, please pay attention to the merge of this branch
https://github.com/gogf/gf/tree/fix/db_dameng
jiftle
sqlite驱动, gtime.Time类型,数据库字段采用text类型,写入时间为空。
type SysLoginLog struct {
g.Meta `orm:"table:sys_login_log, do:true"`
InfoId interface{} // 访问ID
LoginName interface{} // 登录账号
Ipaddr interface{} // 登录IP地址
LoginLocation interface{} // 登录地点
Browser interface{} // 浏览器类型
Os interface{} // 操作系统
Status interface{} // 登录状态(0成功 1失败)
Msg interface{} // 提示消息
LoginTime *gtime.Time // 登录时间
Module interface{} // 登录模块
}
fc
sqlserver连接时使用sa用户,设置namespace,db.model(table)构建后没有拼接namespace,驱动里面确实没有这个功能,就是找不到对应的表,这个要怎么修改,主要是update那里会查tablefields,如果我传入 schema.table,不知道其他地方是否会有什么影响
pengxue
我的版本 gf -v
GoFrame CLI Tool v2.5.2, https://goframe.org
GoFrame Version: v2.5.3 in current go.mod
CLI Installed At: D:\gopath\bin\gf.exe
Current is a custom installed version, no installation information.
但是 gf gendao 生成的代码不对呢。生成的任何表对应的字段都是不对的呢,entity目录下的。
我回退到2.0.0 版本没有问题了,你们2.5.3这个版本肯定有问题的。
gf -v
GoFrame CLI Tool v2.0.0, https://goframe.org
GoFrame Version: v2.5.3 in current go.mod
CLI Installed At: D:\gopath\bin\gf.exe
CLI Built Detail:
Go Version: go1.17.7
GF Version: v2.0.0
Git Commit: 2022-03-08 21:27:14 aa294ea5df3b86dd8d45dcbf8f3f8b3b5176acf8
Build Time: 2022-03-08 21:55:37
小陈
gdb类覆盖率好低啊, 都是0%
小陈
这里澄清一下, gdb的覆盖率, 是单独提出来放在各个驱动里面的. 如mysql驱动
eric
pg 的 timezone 不能用 `local`, 要用 具体的, 比如:
timezone: "Asia/Shanghai"
苏坚昭
郭强 我的数据库密码包含@,怎么办呢?
lip
不用处理,dsn会解析最后一个@作为间隔符
liuz
SHOW FULL COLUMNS 这个查询是否可以关闭掉,在我执行垮库查询的时候执行这条SHOW FULL COLUMNS会报错。单又不会影响查询结果,会导致一堆错误log
郭强
我看你用的版本
v2.0.6
比较老了,建议升级一下框架版本,后续版本有过改进。fish
hzj
能否在简化下配置,我们实际项目需要链接上百个 mysql,配置文件中每个 mysql 都需要单独配置下 maxIdle、maxOpen 参数,配置文件会很长,如下:
智刚
可以使用配置服务,这样就不需要单独写了配置文件了,集中在配置服务中设置
zdq2601
问大家一下,我的只有这样配置 才能联通"link":"sqlite:./errfile.db" 但是按"link":"sqlite::@file(./errfile.db)" 就不通
cherychen007
V2.6版本使用sqlite 进行数据插入,总是报database is locked (5) (SQLITE_BUSY),能不能帮忙分析下
jarry8359
如果主从都设置成master,数据库主从切换后,只能读数据,不能改数据,只能重新改配置重启服务。