在Go中访问数据库需要用到sql.DB
接口:它可以创建语句(statement)和事务(transaction),执行查询,获取结果。
使用数据库时,除了database/sql
包本身,还需要引入想使用的特定数据库驱动。
官方不提供实现,先下载第三方的实现,https://github.com/golang/go/wiki/SQLDrivers查看各种各样的实现版本。
开发环境准备
通过docker搭建MySQL服务器,首先创建initsql目录, 在initsql目录下创建测试数据文件student.sql,内容如下
SET NAMES utf8mb4;
CREATE DATABASE `test` DEFAULT CHARSETER SET utf8mb4 COLLATE utf8mb4_bin;
USE test;
-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) NOT NULL,
`gender` tinyint(4) NOT NULL COMMENT '1男 2女',
`number` char(8) NOT NULL,
`department` varchar(20) NOT NULL,
`major` varchar(32) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_number` (`number`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='学生信息';
-- ----------------------------
-- Records of student
-- ----------------------------
BEGIN;
INSERT INTO `student` VALUES (1, '沈京兵', 1, '20190001', '计算机学院', '计算机科学与工程');
INSERT INTO `student` VALUES (2, '范剑', 2, '20190002', '计算机学院', '计算机科学与工程');
INSERT INTO `student` VALUES (3, '范统', 1, '20190003', '管理学院', '信息管理与信息系统');
INSERT INTO `student` VALUES (4, '史珍香', 2, '20190004', '管理学院', '信息管理与信息系统');
INSERT INTO `student` VALUES (5, '曾桃燕', 1, '20190005', '经济学院', '金融');
INSERT INTO `student` VALUES (6, '朱逸群', 2, '20190006', '法学院', '法学');
INSERT INTO `student` VALUES (7, '秦寿生', 1, '20190007', '经济学院', '国际经济与贸易');
INSERT INTO `student` VALUES (8, '杜子腾', 1, '20190008', '经济学院', '国际经济与贸易');
INSERT INTO `student` VALUES (9, '杜琦燕', 2, '20190009', '外国语', '西班牙语');
INSERT INTO `student` VALUES (10, '赵邀靖', 2, '20190010', '外国语', '阿拉伯语');
COMMIT;
设置student.sql 可执行权限
chmod a+x student.sql
在当期目录创建mysql 目录
mkdir mysql
整体目录结构
tree
.
├── initsql
│ └── student.sql
└── mysql
2 directories, 1 file
启动docker
docker run -d -p3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=123456 -v $PWD/mysql:/var/lib/mysql -v $PWD/initsql:/docker-entrypoint-initdb.d mysql:5.7
当导入一个包时,该包下的文件里所有init()函数都会被执行,然而,有些时候我们并不需要把整个包都导入进来,仅仅是是希望它执行init()函数而已。这个时候就可以使用 import 引用该包。_
"database/sql"
_ "github.com/go-sql-driver/mysql"
面的mysql驱动中引入的就是mysql包中各个init()方法,你无法通过包名来调用包中的其他函数。导入时,驱动的初始化函数会调用sql.Register将自己注册在database/sql包的全局变量sql.drivers中,以便以后通过sql.Open访问。
package main
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
"log"
)
func main() {
db, err := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/test")
if err != nil {
log.Fatal(err)
}
// 验证链接
if err := db.Ping(); err != nil {
log.Fatal(err)
}
rows, err := db.Query("SELECT name,number FROM student LIMIT 10")
var name, num string
for rows.Next() {
if err := rows.Scan(&name, &num); err == nil {
log.Println(name, num)
} else {
log.Fatal(err)
}
}
}
使用 sql.Open()
连接数据库,第一个参数是驱动名称,import 语句 _ "github.com/go-sql-driver/mysql"
包导入时会注册 mysql的驱动,第二个参数是数据库名称,sql.Open()中的数据库连接串格式为:"``用户名:密码@tcp(IP:端口)/数据库?charset=utf8``"
。
通常不会约束你查询必须用Query,只是Query会返回结果集,而Exec不会返回。所以如果你执行的是增删改操作一般用Exec会好一些。Exec返回的结果是Result
,Result
接口允许获取执行结果的元数据:
type Result interface {
// 用于返回自增ID,并不是所有的关系型数据库都有这个功能。
LastInsertId() (int64, error)
// 返回受影响的行数。
RowsAffected() (int64, error)
}
参数设置
SetMaxOpenConns(maxOpenConns)
func (db *DB) SetMaxOpenConns(n int)
连接池最多同时打开的连接数。
这个maxOpenConns理应要设置得比mysql服务器的max_connections值要小。
一般设置为: 服务器cpu核心数 * 2 + 服务器有效磁盘数。参考这里
可用show variables like ‘max_connections’; 查看服务器当前设置的最大连接数。
SetMaxIdleConns(maxIdleConns)
func (db *DB) SetMaxIdleConns(n int)
连接池里最大空闲连接数。必须要比maxOpenConns小;如果n大于最大开启连接数,则新的最大闲置连接数会减小到匹配最大开启连接数的限制
SetConnMaxIdleTime(maxIdleTime)
连接池里面的连接最大空闲时长。
当连接持续空闲时长达到maxIdleTime后,该连接就会被关闭并从连接池移除,哪怕当前空闲连接数已经小于SetMaxIdleConns(maxIdleConns)设置的值。
连接每次被使用后,持续空闲时长会被重置,从0开始从新计算;
用show processlist; 可用查看mysql服务器上的连接信息,Command表示连接的当前状态,Command为Sleep时表示休眠、空闲状态,Time表示此状态的已持续时长;
SetConnMaxLifetime(maxLifeTime)
连接池里面的连接最大存活时长。
maxLifeTime必须要比mysql服务器设置的wait_timeout小,否则会导致golang侧连接池依然保留已被mysql服务器关闭了的连接。
wait_timeout
mysql服务器的wait_timeout默认是8 hour,可通过show variables like ‘wait_timeout’查看。
参考
https://www.cnblogs.com/Dominic-Ji/articles/11660056.html
https://github.com/8treenet/gcache
https://blog.csdn.net/wangshubo1989/article/details/75257614
https://xuchao918.github.io/2019/06/13/Go%E6%93%8D%E4%BD%9CMySql%E6%95%B0%E6%8D%AE%E5%BA%93%E7%9A%84%E6%96%B9%E5%BC%8F/
https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_wait_timeout
https://blog.csdn.net/qq_39384184/article/details/103954821
https://learnku.com/go/t/49809
https://www.cnblogs.com/show58/p/12622409.html
https://juejin.cn/post/6844904087427776519