go语言中的数据库操作
qingheluo2021-10-23清河洛427
在go语言中,标准库"database/sql"提供了保证SQL或类SQL数据库的泛用接口,使用前需要注入对应的数据库驱动,go标准库中没有提供任何一个数据库驱动,需要我们通过其他方式安装驱动常用的支持"database/sql"通用接口的数据库驱动包地址: sqlite3:github.com/mattn/go-sqlite3(注册的数据库驱动名称"sqlite3")
mysql:github.com/go-sql-driver/mysql(注册的数据库驱动名称"mysql")
postgresDB:github.com/lib/pq(注册的数据库驱动名称"pos...
在go语言中,标准库"database/sql"提供了保证SQL或类SQL数据库的泛用接口,使用前需要注入对应的数据库驱动,go标准库中没有提供任何一个数据库驱动,需要我们通过其他方式安装驱动
常用的支持"database/sql"通用接口的数据库驱动包地址:
sqlite3:github.com/mattn/go-sqlite3(注册的数据库驱动名称"sqlite3") mysql:github.com/go-sql-driver/mysql(注册的数据库驱动名称"mysql") postgresDB:github.com/lib/pq(注册的数据库驱动名称"postgres") import ( "database/sql" _ "github.com/mattn/go-sqlite3" )
标准库"database/sql"的使用
type Result interface { LastInsertId() (int64, error) // 返回一个数据库生成的回应命令的整数 // 当插入新行时,一般来自一个"自增"列 // 不是所有的数据库都支持该功能,该状态的语法也各有不同。 RowsAffected() (int64, error) // 返回被update、insert或delete命令影响的行数 // 不是所有的数据库都支持该功能。 } Register(name string, driver driver.Driver) 注册并命名一个数据库,可以在Open函数中使用该命名启用该驱动 当我们引入数据库驱动时都会通过init方法注册,无需我们再去注册 type DB struct {} DB是一个数据库(操作)句柄,代表一个具有零到多个底层连接的连接池。 可以安全的被多个go程同时使用,sql包会自动创建和释放连接; 它也会维护一个闲置连接的连接池。 如果数据库具有单连接状态的概念,该状态只有在事务中被观察时才可信。 一旦调用了BD.Begin,返回的Tx会绑定到单个连接。 当调用事务Tx的Commit或Rollback后,该事务使用的连接会归还到DB的闲置连接池中。 连接池的大小可以用SetMaxIdleConns方法控制。 Open(driverName, dataSourceName string) (*DB, error) 打开一个dirverName指定的数据库 dataSourceName指定数据源,指定数据库名和连接信息 该函数可能只是验证其参数,而不创建与数据库的连接 调用返回值的Ping方法检查数据源的名称是否合法 返回的DB可以安全的被多个go程同时使用,并会维护自身的闲置连接池。 sqlite3只需传入数据库文件即可 db,err := sql.Open("sqlite3","/path/db_file.db") mysql: db,err := sql.Open("mysql","username:password@tcp(ip:port)/database?charset=utf8") 常用的可用参数:点击查看 pgsql: db,err := sql.Open("postgres","user=username password=pwd host=localhost ...") 每项设置为key=val的格式,多个设置项之间使用空格隔开 db,err := sql.Open("postgres","postgres://user:password@host:port/dbname?key1=val&key2=val2...") 以类似url的形式传入参数 常用的可用参数:点击查看
Open函数返回的*DB的方法
Driver() driver.Driver:返回数据库下层驱动 Ping() error:检查与数据库的连接是否仍有效,如果需要会创建连接 Close() error:关闭数据库,释放任何打开的资源 SetMaxOpenConns(n int):设置与数据库建立连接的最大数目 如果n <= 0,不会限制最大开启连接数,默认为0 SetMaxIdleConns(n int):设置连接池中的最大闲置连接数 如果n大于最大连接数,则最大闲置连接数会设置为最大连接数 如果n <= 0,不会保留闲置连接 Exec(query string, args ...interface{}) (Result, error) 执行一次命令,args表示query中的占位参数 Query(query string, args ...interface{}) (*Rows, error) 执行一次查询,返回所有结果(Rows),args表示query中的占位参数 QueryRow(query string, args ...interface{}) *Row 执行一次查询,并仅返回一行结果(即Row) 总是返回非nil的值,直到返回值的Scan方法被调用时,才会返回可能的错误 占位符(字符串占位符不能使用单引号包含) ?:后面参数按照问号的顺序依次提供 $n:第一个为$1,第二个为$2,以此类推 Prepare(query string) (*Stmt, error) 创建一个准备好的状态用于之后的查询和命令 stmt,err := db.Prepare("insert into info (name,age) values (?,?)") Begin() (*Tx, error):Begin开始一个事务。隔离水平由数据库驱动决定
type Row struct {}:表示单行查询结果
Scan(dest ...interface{}) error 将该行查询结果各列分别保存进dest参数指定的值中 如果没有匹配查询的行,会返回ErrNoRows
type Rows struct {}:表示多行查询结果集
它的游标默认指向结果集的第零行 Columns() ([]string, error):返回所有列的名称 Scan(dest ...interface{}) error:将当前游标所在行各列结果填充进dest指定的各个值中 Next() bool:将当前游标向下移动一行。如果没有下一行或者出现错误会返回false Close() error:Close关闭Rows,如果Next方法返回假,Rows会自动关闭 Err() error:返回可能的、在迭代时出现的错误 使用示例: req,err := db.Query("select id,name,age from info") for req.Next(){ var id int var name string var age int err = req.Scan(&id,&name,&age) checkErr(err) fmt.Println(id,name,age)
type Stmt struct {}:表示准备好的状态,可以安全的被多个go程同时使用
Exec(args ...interface{}) (Result, error) Query(args ...interface{}) (*Rows, error) QueryRow(args ...interface{}) *Row Close() error:关闭状态 使用示例: stmt,err := db.Prepare("insert into info (name,age) values (?,?)") name为字符串,age为数字,但是创建Stmt时的sql语句value中name不需要添加单引号 req,err := stmt.Exec("三千",30) 按照创建Stmt时的问号顺序依次传入值即可
type Tx struct {}:代表一个进行中的数据库事务
一次事务必须以对Commit或Rollback的调用结束。 调用Commit或Rollback后,所有对事务的操作都会失败并返回错误值ErrTxDone Exec(query string, args ...interface{}) (Result, error) Query(query string, args ...interface{}) (*Rows, error) QueryRow(query string, args ...interface{}) *Row Prepare(query string) (*Stmt, error) 准备一个专用于该事务的状态 返回的该事务专属状态操作在Tx递交会回滚后不能再使用 Stmt(stmt *Stmt) *Stmt 使用已存在的状态生成一个该事务特定的状态 Commit() error:递交事务 Rollback() error:放弃并回滚事务
使用Open()打开mysql数据库时的可用参数
一般情况下我们使用"username:password@tcp(ip:port)/database"格式
我们可以传入一些参数来配置数据库连接的各种选项
通过在上面字符串最后添加问号(?)分割,以key=val的格式,多个配置项之间使用 & 符号连接,就和网址中get方式传参一样
当传入的字符串值中有空格时,需要使用单引号包含
当传入的值中存在单引号(')或斜杠(/)时需要进行转义
单引号转义为%27,斜杠转义为%2F
常用的参数及其意义
charset: string,设置默认字符集 可以使用逗号隔开传入多个值,用于兼容 如charset=utf8mb4,utf8表示优先使用utf8mb4,如果不支持则向后继续取值 checkConnLiveness=true,每次操作之前检测连接的活跃性 在支持的平台上,每次数据库操作之前会检查从连接池中获取的连接的活跃性 如果检测活跃性失败,则标记该连接为坏连接,并重新从连接池中获取新连接 然后检测活跃性,如此循环,知道检测通过后进行下一步操作 设置为false禁用连接的活跃度检查 collation=utf8mb4_general_ci 设置用于连接时客户端-服务器交互的排序规则 如果指定的排序规则在目标服务器上不可用,则连接将失败 clientFoundRows=false:默认update语句返回的是实际更改的行数,设置为true后返回的是匹配的行数 columnsWithAlias=false 默认返回的列明不含表名 为true时,对sql.Rows.Columns()的调用将返回表别名和列名,并以点分隔 interpolateParams=true: 为true时允许使用占位符 ? 来避免SQL注入 loc=UTC: 设置时区 当设置parseTime=true时,默认值为Local,否则默认值为UTC 如:loc=Asia%2FShanghai maxAllowedPacket=64*1024*1024 允许的最大数据包大小(字节),默认值64MiB 设置为 0 时在每次连接时自动从服务器获取max_allowed_packet变量 multiStatements=false :是否允许使用分号分割的select语句,即一次性执行多个查询语句 使用Rows.NextResultSet()获取下一个查询语句的结果 此时, ? 参数只能在第一个语句中生效 parseTime=false: 为true时会自动将DATE和DATETIME类型转换为Go的time.Time类型 timeout: 设置连接超时时间,需要添加单位,如:readTimeout=1m30s readTimeout: 设置读操作的超时时间 writeTimeout: 设置写入操作的超时时间 serverPubKey:指定连接数据库服务器的公钥文件 tls=false :是否启用TLS / SSL加密连接到服务器 可使用true或false来开启或关闭该功能,还可以传入特殊值 preferred 表示仅在服务器明确告知要使用TLS时才使用TSL skip-verify 表示跳过SSL证书验证,或提供证书文件的路径来验证SSL连接 **其他自定义参数** 任何其他参数都被解释为系统变量,用于对mysql进行更精细的设置 如autocommit=1
使用Open()打开pgsql数据库时的可用参数
dbname 要连接到的数据库的名称 user 登录身份的用户 password 用户的密码 host 要连接到的主机。以 / 开头的值适用于 unix 域套接字。(默认为 localhost) port 要绑定到的端口。(默认值为 5432) sslmode 是否使用 SSL(默认为 require) disable 禁用 SSL require 始终 SSL(跳过验证) verify-ca 始终 SSL(验证是否由受信任的CA签名) verify-full 始终 SSL(验证是否由受信任的CA和主机名签名与证书中的证书是否匹配) fallback_application_name - 如果未提供,则要回退到的application_name connect_timeout 连接的最长等待时间(以秒为单位)。零或 未指定表示无限期等待。 sslcert 证书文件位置。该文件必须包含 PEM 编码的数据。 sslkey 密钥文件位置。该文件必须包含 PEM 编码的数据。 sslrootcert 根证书文件的位置。文件 必须包含 PEM 编码数据。