sql操作的系统函数 如果你觉得用起来比较啰嗦的话 你还可以选择开源库,这里简单介绍下sqlx这个开源库
sqlx 的连接数据库
// 定义一x全局对象 这是并发安全的对象 注意这个是sqlx了 不是sql
var db *sqlx.DB
func initMysql() (err error) {
dsn := "root:1234qwer@tcp(127.0.0.1:3306)/go_test"
// 原生的 是open 这里直接用connect 就行了 里面包含了ping的操作
db, err = sqlx.Connect("mysql", dsn)
if err != nil {
panic(err)
}
db.SetConnMaxLifetime(time.Second * 10)
// 设置最大的连接数 默认是无限制 如果超出限制了 就会排队等待
db.SetMaxOpenConns(200)
// 设置最大的空闲连接数 默认是无限制 业务量小的时候 可以把多余的连接释放掉,只保留一定数量的连接数
db.SetMaxIdleConns(10)
return nil
}
复制代码
sqlx的查询
// 这里注意首字母要大写了
// 因为sqlx是用的反射来对结构体进行赋值,所以是跨包的,
// 那自然这个结构体的 field 要首字母大写了
type user struct {
Id int `db:"id"`
Age int `db:"age"`
Name string `db:"name"`
}
func queryRow() {
sqlStr := "select id,age,name from user where id=?"
var u user
//queryRow 之后 一定要执行scan 否则 持有的数据库连接 不会释放
err := db.Get(&u, sqlStr, 1)
if err != nil {
fmt.Println(err)
}
fmt.Println("result:", u)
}
复制代码
可以看出来,这查询就比之前的原生的查询要简单很多,使用很方便。
其实这里的原理和java中的json序列化很像,都是利用反射。
只不过在java中 我们一般是利用注解 来标识 field和 json中key的关系
而 这里是用的`` 符号 仅此而已
查询多行也是一样的
func queryRow() {
sqlStr := "select id,age,name from user where id=?"
var u user
//queryRow 之后 一定要执行scan 否则 持有的数据库连接 不会释放
err := db.Get(&u, sqlStr, 1)
if err != nil {
fmt.Println(err)
}
fmt.Println("result:", u)
}
复制代码
也是能简化不少 我们的操作
crud 操作
sqlx的crud操作和sql里面的操作是一样的 这里不再重复演示
func insert() {
sqlStr := "insert into user(name,age) values(?,?)"
ret, err := db.Exec(sqlStr, "李彦宏", 99)
if err != nil {
fmt.Println(err)
return
}
id, err2 := ret.LastInsertId()
if err2 != nil {
fmt.Println("get lastid error:", err2)
return
}
fmt.Println("insert success,id: ", id)
}
复制代码
简化操作
在之前每次插入或者更新数据的时候 如果参数过多,那我们的占位符和真正的数据 很有可能就写错了,而且可读性不佳
sqlx提供了NamesExec操作 可以简化我们的操作 以kv的形式 来操作数据
func betterInsert() {
sqlStr := `insert into user(name,age) values(:name,:age) `
_, err := db.NamedExec(sqlStr, map[string]interface{}{
"name": "大强子",
"age": 17,
})
if err != nil {
panic(err)
}
return
}
复制代码
同样的 查询语句也一样有类似的方法NamedXXX 有兴趣的可以自行查找sqlx 相关的文档。这里只是抛砖引玉一下
大家要谨记,这些api没必要一个个过,只需要记住一个类似的,然后其余的时候只要知道用的时候 去哪里查询文档 即可
事务的操作
sqlx的事物操作 与原生的 事务操作 有所不同,主要区别就是 sqlx 依赖defer 来做回滚和提交的操作
func transactionDemo() error {
tx, err := db.Begin()
if err != nil {
fmt.Println("begin trans failed")
return err
}
defer func() {
// 如果这个函数有panic 则 回滚以后再panic
if p := recover(); p != nil {
tx.Rollback()
panic(p)
} else if err != nil {
// 如果有错误 也回滚
fmt.Println("rollback")
tx.Rollback()
} else {
err = tx.Commit()
fmt.Println("commit")
}
}()
sqlstr1 := "update user set age=130 where id=?"
_, err = tx.Exec(sqlstr1, 1)
if err != nil {
return err
}
sqlstr2 := "update user set age=130 where id=?"
_, err = tx.Exec(sqlstr2, 2)
if err != nil {
return err
}
err = tx.Commit()
if err != nil {
return err
}
return nil
}
复制代码
我个人是比较喜欢这种defer的写法的 因为不容易出错 特别是当你的事务特别复杂的时候
sqlx的批量插入
有时候我们会经常碰到批量插入数据的场景,最简单的做法 当然是 写一个for循环 每次都插入一条
直到循环结束,但是这样会重复连接数据库 造成不必要的压力。
所以通常我们会一次性插入
sql语句 形如:
当然在程序里面我们要使用占位符来处理,那他的参数如下:
显然我们要 完成类似的操作 是要做一些 字符串拼接的操作的
这样写起来很麻烦
func insertUsers(users []user) error {
// 存放 (?, ?) 的slice
valueStrings := make([]string, 0, len(users))
// 存放values的slice
valueArgs := make([]interface{}, 0, len(users)*2)
// 遍历users准备相关数据
for _, u := range users {
// 此处占位符要与插入值的个数对应
valueStrings = append(valueStrings, "(?, ?)")
valueArgs = append(valueArgs, u.Name)
valueArgs = append(valueArgs, u.Age)
}
// strings.Join(valueStrings, ",") ===》(?, ?),(?, ?),(?, ?)
// 自行拼接要执行的具体语句 形如:INSERT INTO user (name, age) VALUES (?, ?),(?, ?),(?, ?)
stmt := fmt.Sprintf("INSERT INTO user (name, age) VALUES %s",
strings.Join(valueStrings, ","))
fmt.Println(valueArgs)
_, err := db.Exec(stmt, valueArgs...)
return err
}
复制代码
users := []user{
{
Name: "kk1",
Age: 11,
},
{
Name: "kk2",
Age: 12,
},
{
Name: "kk1",
Age: 13,
},
}
insertUsers(users)
复制代码
简化版的写法
func insertMoreUsers(users []user) error {
_, err := db.NamedExec("INSERT INTO user (name, age) VALUES (:name, :age)", users)
return err
}
复制代码
in函数简单介绍
func searchByIDs(ids []int)(users []user, err error){
//把id 填到sql语句中
query, args, err := sqlx.In("SELECT name, age FROM user WHERE id IN (?)", ids)
if err != nil {
return
}
// sqlx.In 返回带 `?` 的查询语句, 记得要用rebind 重新绑定下
query = db.Rebind(query)
err = db.Select(&users, query, args...)
return
}
复制代码
近期评论