介绍
为系统提供存储能力的数据库有很多,包括关系型、非关系型
主流的关系型数据库有 Oracle、DB2、MySQL、Microsoft SQL Server、Microsoft Access ...
非关系型 mongodb、redis、CouchDB ...
在 Go lang 中提供了操作数据库接口 database/sql
包,没有提供具体的数据库驱动
在使用database/sql
包时必须注入一个数据库驱动(必须有一个驱动)
操作数据
使用 go-sql-driver 驱动
安装数据库驱动
go get -u github.com/go-sql-driver/mysql
复制代码
初始化数据库连接
使用 database/sql
提供了建立连接
func Open(driverName, dataSourceName string) (*DB, error) {}
复制代码
- driverName 驱动名称
- dataSourceName 数据库连接地址
- 返回操作数据库 DB
初始化,获取 DB
func InitDivider() (db *sql.DB) {
url := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8", "root", "123456", "127.0.0.1", "3306", "moose")
db, err := sql.Open("mysql", url)
if err != nil {
fmt.Println(err)
return
}
return db
}
复制代码
- url 包括数据的账号、密码、地址、端口、数据库名
建立表
使用之前数据库脚本建立一个 t_user_info 用户信息表
DROP TABLE IF EXISTS `t_user_info`;
CREATE TABLE `t_user_info` (
`user_id` bigint(20) NOT NULL COMMENT '用户Id',
`username` varchar(64) COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '用户名',
`account_id` bigint(20) NOT NULL,
`account_name` varchar(64) COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '用户名',
`phone` varchar(11) COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '手机号',
`gender` char(1) COLLATE utf8_bin NOT NULL COMMENT '性别 male 1; female 2;un_known or hide 0',
`avatar` varchar(255) COLLATE utf8_bin NOT NULL COMMENT '头像',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`user_id`),
UNIQUE KEY `uniq_phone` (`phone`),
UNIQUE KEY `uniq_user_id` (`user_id`),
UNIQUE KEY `uniq_username` (`username`),
UNIQUE KEY `uniq_account_id` (`account_id`),
UNIQUE KEY `uniq_account_name` (`account_name`),
KEY `idx_create_time` (`create_time`),
KEY `idx_update_time` (`update_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='用户信息表';
复制代码
更多数据库脚本地址
以下操作全部操作
前提: 创建一个测试查询方法,传入操作数据库句柄(DB)
增加
func TestInsert(db *sql.DB) {
sql := `INSERT INTO t_user_info(user_id, username, account_id, account_name, gender, phone, avatar) values(?,?,?,?,?,?,?)`
_, err := db.Exec(sql, "1", "测试用户", "10", "测试账号", 1, "18732132132", "https://moose-plus.oss-cn-shenzhen.aliyuncs.com/avatar.png")
if err != nil {
fmt.Println(err)
return
}
fmt.Println("添加成功")
}
func main() {
db := InitDivider()
defer db.Close()
TestInsert(db)
}
复制代码
λ go run main.go
"添加成功"
复制代码
如果 id 是自增长,db.Exec
第一个参数可以获取到返回结果
func (db *DB) Exec(query string, args ...interface{}) (Result, error) {}
// A Result summarizes an executed SQL command.
type Result interface {
// LastInsertId returns the integer generated by the database
// in response to a command. Typically this will be from an
// "auto increment" column when inserting a new row. Not all
// databases support this feature, and the syntax of such
// statements varies.
LastInsertId() (int64, error)
// RowsAffected returns the number of rows affected by an
// update, insert, or delete. Not every database or database
// driver may support this.
RowsAffected() (int64, error)
}
复制代码
查看数据库也存在一条刚刚添加数据
修改
func TestUpdate(db *sql.DB) {
sql := `UPDATE t_user_info SET username = ? WHERE user_id = ?`
result, err := db.Exec(sql, "修改名字", "1")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(result)
}
复制代码
删除
func TestDelete(db *sql.DB) {
sql := `DELETE FROM t_user_info WHERE user_id = ?`
result, err := db.Exec(sql, "1")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(result)
}
复制代码
查看数据库,数据被删除了
查询
UserInfo 结构体
type UserInfo struct {
UserId string
UserName string
Avatar string
...
}
复制代码
func TestQueryRow(db *sql.DB) {
// 查询 SQL
sql := "select user_id, avatar, username from t_user_info"
var userInfo UserInfo
err := db.QueryRow(sql).Scan(&userInfo.UserId, &userInfo.UserName, &userInfo.Avatar)
if err != nil {
fmt.Println("sacn error :: ", err)
return
}
fmt.Println(userInfo)
}
func main() {
db := InitDivider()
// 延迟关闭,在 main 方法执行完
defer db.Close()
TestQueryRow(db)
}
复制代码
λ go run main.go
{785919644501544960 https://moose-plus.oss-cn-shenzhen.aliyuncs.com/2020-12-23/avatar.png 江景}
复制代码
注意 在查询 sql, select field1, field2, field3 需要和 Scan(field1, field2, field3)保持对应,要不然会出现错乱
查询返回多条数据
func TestQuery(db *sql.DB) {
sql := "select user_id, avatar, username from t_user_info where user_id IN(?,?)"
rows, err := db.Query(sql, "785919644501544960", "790883082524954600")
if err != nil {
fmt.Println(err)
return
}
for rows.Next() {
var userInfo UserInfo
err = rows.Scan(&userInfo.UserId, &userInfo.UserName, &userInfo.Avatar)
if err != nil {
fmt.Println("发送错误")
return
}
fmt.Println(userInfo)
}
}
复制代码
λ go run main.go
{785919644501544960 https://moose-plus.oss-cn-shenzhen.aliyuncs.com/2020-12-23/avatar.png 江景}
{790883082524954600 https://default.png 李白}
复制代码
-
查询多条使用 Query
-
Query 查询结果返回
func (*sql.DB).Query(query string, args ...interface{}) (*sql.Rows, error)
复制代码
- 遍历 Rows,使用 Next 判断是否还有下一条
func (rs *Rows) Next() bool
复制代码
- 数据封装和单条数据一致 Scan
Sql 注入问题
通过 SQL 语法里的一些组合,执行 SQL 语句,返回想要的结果
使用 db.Prepare(sql),将 sql 进行预编译,返回 Stmt,使用 Stmt 进行数据库操作
func (db *DB) Prepare(query string) (*Stmt, error)
...
stmt, err := db.Prepare(sql)
stmt.Exec()
...
复制代码
数据库事务
执行一条 SQL,保证原子性,要么全部成功,要么全部失败
func (db *DB) Begin() (*Tx, error)
tx, _ := db.Begin()
// db.BeginTx()
tx.Commit()
tx.Rollback()
复制代码
执行 SQL 之前开启事务 db.Begin(),如果需要回滚执行 tx.Rollback(), 不需要回滚执行 tx.Commit()
TODO
go 在操作数据库过程中,还是有些麻烦的,市面上也有封装操作数据的第三方包,还有一些 orm 框架,简化数据操作。
近期评论