这是我参与「第三届青训营 -后端场」笔记创作活动的第3篇笔记
1.database/sql
在Go语言标准库中提供了进行数据库操作的 database/sql 库
1.1:基本用法
(1)import实现,使用driver+DSN初始化DB连接
import (
"database/sql"
"github.com/go-sql-driver/mysql"
)
func main() {
db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/hello")
}
(2)执行一条sql通过rows取回返回的数据并关闭链接
func main() {
db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/hello")
rows, err := db.Query("select id, name from users where id=?", 2)
if err != nil {
//输出错误
}
defer rows.Close()
}
(3)数据,错误处理
var users []user
for rows.Next() {
var user User
err:=rows.Scan(&user.ID,&user.Name)
if err!=nil {
//...
}
users=append(users,user)
}
if rows.Err()!=nil{
//...
}
}
defer func(){
err=rows.Close()
}
1.2:设计原理
(1)池化技术: 池化技术 (Pool) 是一种很常见的编程技巧,在请求量大时能明显优化应用性能,降低系统频繁建连的资源开销,数据库连接池、线程池、对象池等,它们的特点都是将 “昂贵的”、“费时的” 的资源维护在一个特定的 “池子” 中,规定其最小连接数、最大连接数、阻塞队列等配置,方便进行统一管理和复用。
(2)DB连接类型:
直接连接: 直接连接Coon
预编译Stmt:
(1)stmt对于多次执行的语句比直接执行快,在查询前进行准备是Go语言中的习惯用法,多次使用的查询语句应当进行准备。准备查询的结果是一个准备好的语句,语句中可以包含执行时所需参数的占位符。准备查询比拼字符串的方式好很多,它可以转义参数,避免SQL注入。同时,准备查询对于一些数据库也省去了解析和生成执行计划的开销,有利于性能。
(2)使用方法
num := 12
stmt, err := db.Prepare("SELECT name FROM users WHERE num = ?")
if err != nil {
log.Fatal(err)
}
rows, err := stmt.Query(num)
(3)底层:在数据库层面,预编译Stmt是与单个数据库连接绑定的。通常的流程是:客户端向服务器发送带有占位符的查询语句用于准备,服务器返回一个语句ID,客户端在实际执行时,只需要传输语句ID和相应的参数。因此准备语句无法在连接之间共享,当使用新的数据库连接时,必须重新准备。
事务Tx:
(1)什么是事务
事务是关系型数据库的核心特性。Go中事务(Tx)是一个持有数据库连接的对象,它允许用户在同一个连接上执行上面的各类操作。
(2)使用方法
tx, err := db.Begin()
if err != nil {
log.Fatal(err)
}
(3)基本操作
通过db.Begin()来开启一个事务,Begin方法会返回一个事务对象Tx。在结果变量Tx上调用Commit()或者Rollback()方法会提交或回滚变更,并关闭事务。
(4)底层逻辑
在底层,Tx会从连接池中获得一个连接并在事务过程中保持对它的独占。事务对象Tx上的方法与数据库对象sql.DB的方法对应,事务对象也可以准备查询,由事务创建的准备语句会显式绑定到创建它的事务。
(3) 处理返回数据的几种方式:
ExecContext
ExecerContext是可以被Conn实现的、可选的接口,如果Conn并没有实现ExecerContext接口,那sql包的DB.Exec将会向后调用Excer,如果Conn也没有实现Execer接口,DB.Exec将首先prepare查询,执行语句、然后关闭语句。ExecerContext 可能返回 ErrSkip错误。ExecerContext必须认真对待context的超时,当context被取消时,需要返回。
type ExecerContext interface {
ExecContext(ctx context.Context, query string, args []NamedValue) (Result, error)
}
QueryContext读取所有
QueryerContext 是一个可选的接口,Conn可能会实现它,如果Conn没有实现QueryerContext,那么sql包在执行DB.Query会降级调用Queryer;如果Conn也没有实现Queryer,DB.Query 首先会prepare一个查询语句,然后执行这个语句,然后再关闭它QueryerContext可能会返回 ErrSkip。QueryerContext必须认真对待context的超时,当context被cancel掉时,需要返回。
type QueryerContext interface {
QueryContext(ctx context.Context, query string, args []NamedValue) (Rows, error)
}
QueryRowContext只读取一行
2.GORM
orm:
ORM(Object Relational Mapping)框架采用元数据来描述对象与关系映射的细节,元数据一般采用XML格式,并且存放在专门的对象一映射文件中。简单理解为一种框架的格式。它的作用是在关系型数据库和对象之间作一个映射。
GORM:
Golang写的orm库。
2.1:基本用法
(1)连接数据库
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
func main() {
用户名:密码@tcp(ip:port)/数据库?charset=utf8mb4&parseTime=True&loc=Local
dsn := "root:root123@tcp(127.0.0.1:3306)/test_gorm?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic(err)
}
}
(2)增删改查
// 增
db.Create(&User{
Name: "a",
Age: 22,
Addr: "北京市",
})
// 删
db.Delete(&user)
// 改
user.Name = "b"
db.Save(&user)
fmt.Println(user)
// 查
var user User
db.First(&user)
fmt.Println(user)