数据库

概述

想要通过代码来控制数据库,那么在代码中,首先需要连接到数据库,只有打开了一个连接(socket),才可以通过代码来对数据库进行操作

而一般情况下,数据库并不是通过 go 语言写的,那么如何连接呢,就需要调用数据库的 API 接口,而想要调用该接口,则需要使用第三方库才可以,这个第三方库,这个库会提供几种"method",包括连接数据库,对数据库执行操作等。

GORM

参考:

GORM 是一个出色的 ORM 库,旨在对开发人员友好。

  • 全功能ORM(几乎)
  • 关联(包含一个,包含多个,属于,多对多,多种包含)
  • Callbacks(创建/保存/更新/删除/查找之前/之后)
  • 预加载(急加载)
  • 事务
  • 复合主键
  • SQL Builder
  • 自动迁移
  • 日志
  • 可扩展,编写基于GORM回调的插件
  • 每个功能都有测试
  • 开发人员友好

常用示例

gorm模糊查询和分页查询同时查总条数

func (u *userService) GetuserList(offset, limit int, search User) (users []User, count int, err error) {
 if search.Name != "" {
  u.mysql = u.mysql.Where("name LIKE ?", search.Name+"%")
 }
 if search.Category != "" {
  u.mysql = u.mysql.Where("age =?", search.Age)
 }

 err = u.mysql.Offset(offset).Limit(limit).Find(&users).Offset(-1).Limit(-1).Count(&count).Error
 return users, count, err
}

这简单的一小段已经包含了gorm的模糊查询动态条件分页查询数据条数。 这就是一个最常见的列表查询,列表需要支持条件查询,模糊查询,分页,从代码可以直接看到。

  1. if代码是动态组装条件。
  2. err = u.mysql.Offset(offset).Limit(limit).Find(&users).Offset(-1).Limit(-1).Count(&count).Error 这行代码包含了数据列表查询和数据条数。
  3. 有些需要注意的地方是u.mysql.Offset(offset).Limit(limit).Find(&users) 用于查询数据列表,
  4. .Offset(-1).Limit(-1).Count(&count)用户查询条数,Offset(-1)和Limit(-1)很重要,不加的话会在统计条数后也加上offset和limit,导致查不到条数。 查询结果:
SELECT * FROM `user`   LIMIT 10 OFFSET 0;
SELECT count(*) FROM `user`;

常见问题

为 For 循环中的多个 Or 创建分组

参考:

   for _, field := range queryCardDesc.QField {
    result = result.Or(field+" LIKE ?", "%"+queryCardDesc.Keyword+"%")
   }

上面的例子通过 result=result.Where(result) 分组将会异常,产生多次 SQL,就像这样:

SELECT count(*) FROM `card_descs` WHERE (effect LIKE '%奥米加%' OR sc_name LIKE '%奥米加%' OR evo_cover_effect LIKE '%奥米加%') OR sc_name LIKE '%奥米加%' OR evo_cover_effect LIKE '%奥米加%' OR effect LIKE '%奥米加%' AND color LIKE '%红%'

可以通过如此方式解决:

   f := func(queryCardDesc *models.CardDescQuery, result *gorm.DB) *gorm.DB {
    // 通过 Session() 创建一个新的 DB 实例,避免影响原来的 DB 实例。用以实现为多个 Or 分组的功能
    newResult := result.Session(&gorm.Session{NewDB: true})
    for _, field := range queryCardDesc.QField {
     newResult = newResult.Or(field+" LIKE ?", "%"+queryCardDesc.Keyword+"%")
    }
    return newResult
   }(queryCardDesc, result)

Redis

go get -u -v github.com/garyburd/redigo/redis

package main

import (
 "fmt"
 "github.com/garyburd/redigo/redis" // 引入redis第三方库
)

func main() {
    // 连接到redis
     c, err := redis.Dial("tcp", "127.0.0.1:6379")
 if err != nil {
  fmt.Println("Connect to redis error", err)
  return
 }
    // 注意关闭连接
 defer c.Close()
    // 通过go代码向redis写入数据
 _, err = c.Do("SET", "mykey", "superWang")
 if err != nil {
  fmt.Println("redis set failed:", err)
 }
    // 通过go代码读取redis中的数据,由于返回的值为 interface{} ,所以需要转换成字符串,才能正常显示
 username, err := redis.String(c.Do("GET", "mykey"))
 if err != nil {
  fmt.Println("redis get failed:", err)
 } else {
  fmt.Printf("Get mykey: %v \n", username)
 }
}

最后修改 June 26, 2024: prometheus (13b61e0c)