MySQL介绍以及Go操作MySQL
1. MySQL介绍
MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面 MySQL 是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一。
2. MySQL安装
2.1. 下载
2.2. 安装
2.3. 配置环境变量
将MySQL安装目录下的bin目录添加到环境变量中
2.4. 测试
# 查看MySQL版本
mysql --version
# 登录MySQL
mysql -u root -p
# 退出MySQL
exit
3. MySQL的索引
3.1. 索引的概念
索引是帮助MySQL高效获取数据的数据结构,索引是在存储引擎层实现的,而不是在服务器层实现的,所以不同的存储引擎具有不同的索引类型和实现,索引的类型也决定了它们如何实现以及它们可以提供的功能。
3.2. 索引的优点
- 大大减少了服务器需要扫描的数据行数
- 帮助服务器避免排序和临时表
- 将随机I/O变为顺序I/O
3.3. 索引的缺点
- 创建和维护索引需要时间成本,这种成本随着数据量的增加而增加
- 索引需要占物理空间,除了数据表占用的存储空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大
- 当对表中的数据进行增加、删除和修改的时候,索引也需要动态的维护,这样就降低了数据的维护速度
3.4. 索引的分类
- 普通索引
- 唯一索引
- 主键索引
- 组合索引
- 全文索引
Gorm操作
2. 连接 MySQL
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
func main() {
// DSN:Data Source Name
dsn := "root:123456@tcp(
// 连接数据库
db, err := sql.Open("mysql", dsn)
if err != nil {
fmt.Printf("dsn %s invalid, err:%v\n", dsn, err)
return
}
err = db.Ping()
if err != nil {
fmt.Printf("open %s failed, err:%v\n", dsn, err)
return
}
fmt.Println("连接数据库成功!")
}
3. 查询单条数据
func queryRowDemo() {
sqlStr := "select id, name, age from user where id=?"
var u user
// 非常重要:确保QueryRow之后调用Scan方法,否则持有的数据库链接不会被释放
err := db.QueryRow(sqlStr, 1).Scan(&u.id, &u.name, &u.age)
if err != nil {
fmt.Printf("scan failed, err:%v\n", err)
return
}
fmt.Printf("id:%d name:%s age:%d\n", u.id, u.name, u.age)
}
注意: QueryRow 之后必须调用 Scan 方法,因为该方法会释放数据库链接,如果不调用,会导致链接不会释放,从而导致数据库连接池被占用完毕,后续无法
优化: 使用 sync.Pool 进行优化
// db.go
package db
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
"sync"
)
var (
db *sql.DB
once sync.Once
)
func InitDB() (err error) {
once.Do(func() {
// DSN:Data Source Name
dsn := "root:123456@tcp(
db, err = sql.Open("mysql", dsn)
if err != nil {
fmt.Printf("open %s failed, err:%v\n", dsn, err)
return
}
err = db.Ping()
if err != nil {
fmt.Printf("open %s failed, err:%v\n", dsn, err)
return
}
})
return
}
```
var db *sql.DB
## 4. 查询多条数据
```go
func queryMultiRowDemo() {
sqlStr := "select id, name, age from user where id > ?"
rows, err := db.Query(sqlStr, 0)
if err != nil {
fmt.Printf("query failed, err:%v\n", err)
return
}
// 非常重要:关闭rows释放持有的数据库链接
defer rows.Close()
// 循环读取结果集中的数据
for rows.Next() {
var u user
err := rows.Scan(&u.id, &u.name, &u.age)
if err != nil {
fmt.Printf("scan failed, err:%v\n", err)
return
}
fmt.Printf("id:%d name:%s age:%d\n", u.id, u.name, u.age)
}
}
5. 插入数据
func insertRowDemo() {
sqlStr := "insert into user(name, age) values (?,?)"
ret, err := db.Exec(sqlStr, "小王子", 18)
if err != nil {
fmt.Printf("insert failed, err:%v\n", err)
return
}
theID, err := ret.LastInsertId() // 新插入数据的id
if err != nil {
fmt.Printf("get lastinsert ID failed, err:%v\n", err)
return
}
fmt.Printf("insert success, the id is %d.\n", theID)
}
6. 更新数据
func updateRowDemo() {
sqlStr := "update user set age=? where id = ?"
ret, err := db.Exec(sqlStr, 39, 1)
if err != nil {
fmt.Printf("update failed, err:%v\n", err)
return
}
n, err := ret.RowsAffected() // 操作影响的行数
if err != nil {
fmt.Printf("get RowsAffected failed, err:%v\n", err)
return
}
fmt.Printf("update success, affected rows:%d\n", n)
}
注意:
- 更新操作,Exec()返回的是结果对象,RowsAffected()返回的是影响的行数
- 插入操作,Exec()返回的是结果对象,LastInsertId()返回的是插入的 id
- 删除操作,Exec()返回的是结果对象,RowsAffected()返回的是影响的行数
- 查询操作,Query()返回的是行集对象,Next()用于循环每一行,Scan()用于读取每一列
7. 删除数据
func deleteRowDemo() {
sqlStr := "delete from user where id = ?"
ret, err := db.Exec(sqlStr, 1)
if err != nil {
fmt.Printf("delete failed, err:%v\n", err)
return
}
n, err := ret.RowsAffected() // 操作影响的行数
if err != nil {
fmt.Printf("get RowsAffected failed, err:%v\n", err)
return
}
fmt.Printf("delete success, affected rows:%d\n", n)
}
8. 更新注意事项
- sql 注入问题
func sqlInjectDemo(name string) {
// 自己拼接 sql 语句的字符串
sqlStr := fmt.Sprintf("select id, name, age from user where name='%s'", name)
fmt.Printf("SQL:%s\n", sqlStr)
var u user
err := db.QueryRow(sqlStr).Scan(&u.id, &u.name, &u.age)
if err != nil {
fmt.Printf("exec failed, err:%v\n", err)
return
}
fmt.Printf("user:%#v\n", u)
}
- 预处理方式解决 sql 注入问题
func prepareQueryDemo(name string) {
sqlStr := "select id, name, age from user where name=?"
stmt, err := db.Prepare(sqlStr)
if err != nil {
fmt.Printf("prepare failed, err:%v\n", err)
return
}
defer stmt.Close()
rows, err := stmt.Query(name)
if err != nil {
fmt.Printf("query failed, err:%v\n", err)
return
}
defer rows.Close()
for rows.Next() {
var u user
err := rows.Scan(&u.id, &u.name, &u.age)
if err != nil {
fmt.Printf("scan failed, err:%v\n", err)
return
}
fmt.Printf("id:%d name:%s age:%d\n", u.id, u.name, u.age)
}
}