GORM 实践 | 青训营

70 阅读4分钟

GORM 简介

通过驱动来连接数据库来连接数据库,目前支持 MySQL SQLServer PostgreSQL SQLite,也可以自定义或者复用驱动(如果该数据库支持 MySQL 的话)。这个框架能天然防止 SQL 注入问题,但是要注意,请使用占位符而非字符串拼接,这样才能防止 SQL 注入

mysql 配置

在 linux 环境中安装 mysql,设置用户名和密码,步骤如下

  1. apt 安装
  2. 编辑 mysql 配置文件 mysqld.cnf 跳过密码验证,重启登录
  3. 修改 mysql 表中的用户和密码,或者可以在表中创建新用户和密码
  4. 去掉配置文件中跳过密码验证那一行
  5. 建库建表
sudo apt install mysql
sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
文件中添加语句skip-grant-tables
service mysql restart

mysql -u mysql -p
mysql> use mysql         #指定表
mysql> flush privileges  #解除skip-grant状态才能设置密码

mysql> alter user 'root'@'localhost' identified mysql_native_password by '新密码'
mysql> CREATE USER 'rlk'@'localhost' IDENTIFIED BY '新密码';
mysql> quit
#然后记得去 /etc/mysql/mysql.conf.d/mysqld.cnf 中把 skip-grant-tables去掉, 不然 gnorm 连不上去!

建库建表,以部分大项目字段为例

CREATE DATABASE BASE;

CREATE TABLE videos (
id int not null auto_increment,
author_id int not null,
title varchar(255) not null,
createtime datetime default current_timestamp,
primary key(id)
)DEFAULT CHARSET=utf8;

使用

  1. 定义 gorm model 结构体(就和定义普通结构体一样),对应数据库的一张表,结构体的字段的蛇形命名即表的字段,当然,也可以用 gnorm 标签指定列名。ID 结构体字段默认是主键。
  2. 为 model 定义表名,gorm 提供了一个 TableName 接口,实现它就是直接 return 表名(string)。如果没有定义表名,默认表名是结构体名字的蛇形复数

蛇形命名, 即下划线小写命名法,蛇形复数,即将单词变成复数形式,如 Product -> products

  1. 连接数据库,dsn,里面是具体驱动配置。比如编码,是否引入时间解析。注意,这里的 db 连接初始化一次后给全局使用(所以搞个单例模式?)
import 
    "gorm.io/driver/mysql"
    "gorm.io/gorm"

func main() {
    db, err := gorm.Open(mysql.New(mysql.Config{
        DSN: "username:password@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local",
        //[username[:password]@][protocol[(address)]]/dbname[?param1=value1...]
    }), &gorm.Config{})
}
  1. 数据库操作,包括插入数据

    1. 创建:Create,可一条或多条,多条时传入切片。如果要实现表中存在即更新,不存在即创建,要加上修饰词 .Clauses(clause.OnConflict{})
    2. 查询:Find 多条 & First 一条,查询为空 First 会报错 Find 不会
    3. 删除:删除一条记录时,删除对象需要指定主键,否则会触发批量删除
    4. 更新:Update
u := User{Username: username, Password: password}
res := db.Create(&u)

videos := make([]Video, 0)
res := m.db.Where("createtime <= ?", t).Order("createtime desc").Limit(30).Find(&videos)
u := User{}
res := m.db.Where("id = ?", uid).First(&u)

db.Where("username = ?", "jinzhu").Delete(&email)

//依据条件更新
db.Model(&User{}).Where("username = ?", "z").Update("username", "hello")
//更新某一行
db.Model(&user).Update("username", "hello")

注意事项

  1. GORM 函数通常分为形容词和谓词,形容词决定执行过程中的条件,包括 where model order limit 等等,谓词则包括增删改查 Create Delete Find First Update。一条 GORM 语句可以对标一个 SQL 语句,可以带几个形容词,但只能带一个动词
  2. 默认关闭全局删除和全局更新:当试图执行不带任何条件的批量删除和更新时,GORM 将不会运行并返回ErrMissingWhereClause 错误,如果要执行,需要打开AllowGlobalUpdate 模式
  3. db 的链式调用(责任链):职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了
  4. 联表查询和 join 查询看文档:一个表一个结构体,所以肯定要多个结构体。基本不让调用,因为对数据库压力比较大,一般是取出所有数据,然后再自己拼接程序处理
  5. 别在 for 循环里执行 SQL,批量查询查很多行数据可以用 for,什么 create 一百行数据这种,别用 for 循环

小结

GORM 使用也算是基础中的基础了,它的中文文档内容非常丰富,遇到问题多去读文档即可 GORM 指南 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.