Beego ORM 对象关系映射

1 ORM 对象关系映射

对象关系映射(英语:Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序设计技术,用于实现面向对象编程语言里不同类型系统数据之间的转换。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。如今已有很多免费和付费的ORM产品,而有些程序员更倾向于创建自己的ORM工具。

对数据表的操作和咱们的面向对象的概念对应起来

  • 数据表的操作 <=> 面向对象

    • 也就是说对数据表的操作其实就是一个面向对象的过程

    • 结构体、结构体的实例、结构体的方法

  • 表的定义(通过列定义) <=> 结构体(通过属性定义)

    • 数据表中有对表的定义,通过列来定义也就是对应的结构体中通过属性定义。

  • 表中的数据 <=> 结构体的属性实例

    • 表中的每一个数据就对应到结构体中每个属性的实例

  • 对数据的操作 <=> 结构体中的方法

    • 在数据表中对数据的操作其实就是对应到结构体中的方法

ORM 其实指的就是上面这几方面的映射:

  1. 表和结构体的映射

  2. 数据与结构体实例的映射

  3. 数据操作与方法的映射

1.1 ORM 映射的好处:

  1. 通过定义结构体,自动生成(工具)表

  2. 通过对结构体实例的方法调用,对表进行操作

    在自动生成表的这个过程中会涉及到一个工具,这个工具的功能就是结构体如何与数据表进行对应,对于结构体方法的调用如何转换成数据库中的 SQL 语句。这中间的转换通过 ORM 框架来实现的。

  3. 对使用的数据库没有关系,也就是说 ORM 支持多种数据库操作,比如我现在使用的是 MySQL 后期想换成 mariadb、PGSQL 等数据库,ORM 框架层面的代码不用替换,因为对数据库的操作的话都是 ORM 框架里面来做的,只要 ORM 支持我们只需要修改一下配置,比如数据库链接和驱动的配置就 OK 了,但是 ORM 并不是万能的,比如当我们想实现复杂的 sql,或者对性能要求比较高的话还需要通过 sql 来实现

1.2 beego 中的 ORM

在 beego 中也提供了 ORM 的模块支持

  • 数据库 => 配置类信息

    • 在使用 orm 的时候需要告诉 orm 我们使用的数据库是什么

  • 操作 => orm 包内提供的接口(函数、方法)

    • 对于数据库的操作的话我们都需要使用到 ORM 包内提供的接口(函数、方法)来进行操作

  • 我们定义的数据表,肯定 orm 框架不知道的,所以我们需要自己定义结构体来对应数据表

1.2.1 ORM 初使用范例

在 orm 中只会添加表的信息,不会删除表中的信息

在使用 orm 必须有以下几步操作:

  1. 导入驱动(初始化)

  2. 导入 orm 包

  3. 在 orm 包中注册驱动

  4. 注册数据库(填写数据库的配置信息)

  5. 注册模型

  6. 注册完成之后就可以进行操作,操作分为 DDL DML DQL

    • 如果表不存在就会创建对应的表(他会把结构体的名称对应到表名,把结构体的属性名称对应到表里面的列名,结构体属性的类型对应到表的类型上)

    • 如果表存在会检查结构体对应的属性在数据表列中是否在存在,如果属性不存在就会自动在该表中添加列

    • 还会检查索引是否存在,索引如果不存在就会自动添加索引

package main

import (
    "fmt"
    "time"

    // 注册 mysql 驱动
    _ "github.com/go-sql-driver/mysql"

    // 导入 orm 包
    "github.com/astaxie/beego/orm"
)

// 定义模型
type User struct {
    ID       int64
    Name     string
    Password string
    Sex      bool
    Tel      string
    Addr     string
    Age      string
    Created  *time.Time
    Updated  *time.Time
    Deleted  *time.Time
}

func main() {
    // 1.在 orm 包中注册驱动(mysql)
    // RegisterDriver 函数第一个参数是数据名字,第二个参数是注册的数据库驱动类型
    err := orm.RegisterDriver("mysql", orm.DRMySQL)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 2.注册数据库(使用数据库配置信息,有三个参数)
    // RegisterDataBase 第一个参数别名在 beego 中要求必须注册一个 default 别名的数据库
    // RegisterDataBase 第二个参数注册数据库的类型
    // RegisterDataBase 第三个参数就是我们的 dsn 连接信息
    dsn := "root:root@tcp(10.0.0.10:3306)/hellodb?charset=utf8mb4&loc=Local&parseTime=true"
    err = orm.RegisterDataBase("default", "mysql", dsn)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 3.注册模型,之前需要定义模型,注册是指针类型的实例
    orm.RegisterModel(&User{})

    /* 4.操作,操作分为 DDL DML DQL
    RunSyncdb 用来同步数据库的,会检查结构体对应的表是否存在
    func RunSyncdb(name string, force bool, verbose bool) error
        第一个参数对那个数据库操作就是通过别名来指定
        第二个参数是否先删除所有表
        第三个参数显示详细信息

    orm.RunSyncdb("default", false, true)
        1.这里对 default 这个别名的数据库进行操作
        2.不删除所有表的信息
        3.显示详细信息
    */
    orm.RunSyncdb("default", false, true)
}
# 运行程序输出创建时的 sql 语句
[11:24:30 root@go testorm]#go run orm.go 
create table `user` 
    -- --------------------------------------------------
    --  Table Structure for `main.User`
    -- --------------------------------------------------
    CREATE TABLE IF NOT EXISTS `user` (
        #ID 由结构体中的属性转为 i_d 表名
        `i_d` bigint AUTO_INCREMENT NOT NULL PRIMARY KEY,
        `name` varchar(255) NOT NULL DEFAULT '' ,
        `password` varchar(255) NOT NULL DEFAULT '' ,
        `sex` bool NOT NULL DEFAULT FALSE ,
        `tel` varchar(255) NOT NULL DEFAULT '' ,
        `addr` varchar(255) NOT NULL DEFAULT '' ,
        `age` varchar(255) NOT NULL DEFAULT '' ,
        `created` datetime NOT NULL,
        `updated` datetime NOT NULL,
        `deleted` datetime NOT NULL
    ) ENGINE=InnoDB;

# 进入数据库
[11:24:40 root@go testorm]#mysql -uroot -proot

# 进入到 hellodb 库
MariaDB [(none)]> use hellodb;

# 查看当前 hellodb 库中 user 表就创建出来了
MariaDB [hellodb]> desc user;
+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| i_d      | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| name     | varchar(255) | NO   |     |         |                |
| password | varchar(255) | NO   |     |         |                |
| sex      | tinyint(1)   | NO   |     | 0       |                |
| tel      | varchar(255) | NO   |     |         |                |
| addr     | varchar(255) | NO   |     |         |                |
| age      | varchar(255) | NO   |     |         |                |
| created  | datetime     | NO   |     | NULL    |                |
| updated  | datetime     | NO   |     | NULL    |                |
| deleted  | datetime     | NO   |     | NULL    |                |
+----------+--------------+------+-----+---------+----------------+
10 rows in set (0.010 sec)

总结:

  1. orm 创建的数据表名和程序中的结构体、属性名称对应:

    • 驼峰式转化为下划线式,非首字母的大写字母前加_并将所有字符转为小写

      • 如在程序中的结构体名称UserAAA,对应到数据库表中就是user_a_a_a

      • 如在结构体中ID 属性,对应到数据表中就是i_d

  2. 程序中结构体的属性类型与数据表中的类型对应:

    • int 类型对应数据库中的 INT (INTEGHR)

    • int64 类型对应数据库中的 bigint

    • string 类型对应数据库中的 varchar(255)

    • *time.Time 类型对应数据库中的 datetime

    • bool 类型对应数据库中的 tinyint(1)

  3. beego ORM 对数据列表类型的修饰:

    • 一般都是 NOT NULL 不允许为空

  4. 对 string、bool 都会设置默认值

  5. 如果结构体属性名称有 Id 且为 int 或者 int 系列,并且未指定主键,在 beego orm 中自动会将这个 id 设置为自动增长的主键

1.3 自定义 ORM 数据属性 (sql DML 操作)

如果我们的 user 结构体并不想按照 orm 的数据库中列名的命名规范来定义怎么办呢?如果我这个数据库中的列名也不想按照 orm 中的定义,而且我们还想修改我们的数据列表中的属性。这些就需要使用到 tag 来实现

1.3.1 自定义表名

一般这种自定义表名的方式使用较少

如果我们想自定义写入到数据库中的表名的话就必须要通过方法。

在 beego 中定义了 TableName 的方法,如果在程序中有 tablename 这个方法的话会通过 tablename 的返回值去作为该结构体和返回值去关联

// TableName 方法,返回的值 string 是自定义的表名
func (u *User) TableName() string {
    return "aaa"
}

范例:

package main

import (
    "fmt"
    "time"

    // 注册 mysql 驱动
    _ "github.com/go-sql-driver/mysql"

    // 导入 orm 包
    "github.com/astaxie/beego/orm"
)

// 定义模型
type User struct {
    ID       int64
    Name     string
    Password string
    Sex      bool
    Tel      string
    Addr     string
    Age      string
    Created  *time.Time
    Updated  *time.Time
    Deleted  *time.Time
}

// 这里定义 tablename 返回值为 aaa ,这时候就会中在 hellodb 数据库中创建一张 aaa 的表
func (u *User) TableName() string {
    return "aaa"
}

func main() {
    // 1.在 orm 包中注册驱动(mysql)
    err := orm.RegisterDriver("mysql", orm.DRMySQL)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 2.注册数据库(使用数据库配置信息,有三个参数)
    dsn := "root:root@tcp(10.0.0.10:3306)/hellodb?charset=utf8mb4&loc=Local&parseTime=true"
    err = orm.RegisterDataBase("default", "mysql", dsn)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 3.注册模型,之前需要定义模型,注册是指针类型的实例
    orm.RegisterModel(&User{})

    // 4.操作,操作分为 DDL DML DQL
    orm.RunSyncdb("default", false, true)
}
# 执行程序,就会发现 user 结构体自定义表名的 aaa 已经创建
[14:31:09 root@go testorm]#go run orm.go 
create table `aaa`        # aaa 表已经创建
    -- --------------------------------------------------
    --  Table Structure for `main.User`
    -- --------------------------------------------------
    CREATE TABLE IF NOT EXISTS `aaa` (
        `i_d` bigint AUTO_INCREMENT NOT NULL PRIMARY KEY,
        `name` varchar(255) NOT NULL DEFAULT '' ,
        `password` varchar(255) NOT NULL DEFAULT '' ,
        `sex` bool NOT NULL DEFAULT FALSE ,
        `tel` varchar(255) NOT NULL DEFAULT '' ,
        `addr` varchar(255) NOT NULL DEFAULT '' ,
        `age` varchar(255) NOT NULL DEFAULT '' ,
        `created` datetime NOT NULL,
        `updated` datetime NOT NULL,
        `deleted` datetime NOT NULL
    ) ENGINE=InnoDB;

1.3.2 自定义列名

如果我们想自定义结构体的属性名称写入到数据库中的列名去,该怎么定义呢

当然也是通过标签实现

orm 标签:

 `orm:"column(自定义列名)"`

范例:

package main

import (
    "fmt"
    "time"

    // 注册 mysql 驱动
    _ "github.com/go-sql-driver/mysql"

    // 导入 orm 包
    "github.com/astaxie/beego/orm"
)

// 定义模型
type User struct {
    // 通过 orm 标签自定义列名,这里是将 id 写入到数据表中是 uid
    ID       int64 `orm:"column(uid)"`
    Name     string
    Password string
    Sex      bool
    Tel      string
    Addr     string
    Age      string
    Created  *time.Time
    Updated  *time.Time
    Deleted  *time.Time
}

// 这里定义 tablename 返回值为 a1,创建一个 a1 的表
func (u *User) TableName() string {
    return "a1"
}

func main() {
    // 1.在 orm 包中注册驱动(mysql)
    err := orm.RegisterDriver("mysql", orm.DRMySQL)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 2.注册数据库(使用数据库配置信息,有三个参数)
    dsn := "root:root@tcp(10.0.0.10:3306)/hellodb?charset=utf8mb4&loc=Local&parseTime=true"
    err = orm.RegisterDataBase("default", "mysql", dsn)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 3.注册模型,之前需要定义模型,注册是指针类型的实例
    orm.RegisterModel(&User{})

    // 4.操作,操作分为 DDL DML DQL
    orm.RunSyncdb("default", false, true)
}

执行之后就创建成功

1.3.3 删除表在重建表,并自定义表属性

这里通过修改 RunSyncdb 的第二个参数,将其改为 true 他就会将原来的表先删除然后再重新建立一张新的表

package main

import (
    "fmt"
    "time"

    // 注册 mysql 驱动
    _ "github.com/go-sql-driver/mysql"

    // 导入 orm 包
    "github.com/astaxie/beego/orm"
)

// 定义模型
type User struct {
    // 通过 orm 标签自定义列名,这里是将 id 写入到数据表中是 uid
    ID int64 `orm:"column(uid)"`
    // 通过 orm 标签自定义属性长度
    Name     string `orm:"size(64)"`
    Password string
    Sex      bool
    Tel      string
    Addr     string
    Age      string
    Created  *time.Time
    Updated  *time.Time
    Deleted  *time.Time
}

// 这里定义 tablename 返回值为 a1
func (u *User) TableName() string {
    return "a1"
}

func main() {
    // 1.在 orm 包中注册驱动(mysql)
    err := orm.RegisterDriver("mysql", orm.DRMySQL)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 2.注册数据库(使用数据库配置信息,有三个参数)
    dsn := "root:root@tcp(10.0.0.10:3306)/hellodb?charset=utf8mb4&loc=Local&parseTime=true"
    err = orm.RegisterDataBase("default", "mysql", dsn)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 3.注册模型,之前需要定义模型,注册是指针类型的实例
    orm.RegisterModel(&User{})

    // 4.操作,操作分为 DDL DML DQL
    // 这里将 RunSyncdb 第二个参数改为 true
    orm.RunSyncdb("default", true, true)
}

执行

1.3.4 自定义表中的主键

我们可以通过pk,并且在自定义属性中可以通过分号来定义多个自定义属性

执行

1.3.5 自定义属性值自动增长

可以通过 auto 来实现数据表的自动增长

执行程序

1.3.6 自定义数据类型

假如我想修改我们的某个结构体,通过 orm 存储到数据库的类型,就可以通过type 标签

执行程序

比如我想修改结构体中的 time.time 为数据库中的 date 类型也可以实现修改

执行程序

1.3.7 自定义值为 null

如果我们允许 time.time 为 null 就可以自定义为 null

执行程序,没有 null 值

1.3.8 自定义唯一索引

如果想设置某一个值的唯一索引就可以通过下面操作设置unique

执行程序

1.3.9 自定义索引

通过indexx 设置索引

执行索引创建成功

1.3.10 自定义属性默认值

比如我想把 name 属性的默认值改为 aaa,就可以通过下面的操作 default(aaa)

设置默认值 aaa

执行程序设置成功

1.3.11 自定义联合索引

联合索引有多个列,一个元素肯定有多个索引,所以返回值是一个切片,一个索引可能有多列,所以元素也是一个切片

执行程序所以创建成功

1.3.12 自定义数据类型总结

/*  标签 orm
    自定义列名 column
    字符串长度 size
    指定其他类型 type
               decimal 类型 digits, decimals
    自定义主键 pk
    自定义主键自动增长 pk;auto
    默认值 default
    注释 description 
    允许为null 就是 null
    时间类型 auto_now_add 和 auto_now
    索引 index
    唯一索引 unique
*/

1.4 ORM 中对数据的操作(sql DML 操作)

在 ORM 中的 DML 语句可以分为以下两种:

  1. 对单个数据的 增、删、改、查

  2. 对批量数据的 增、删、改、查

对数据库的操作其实是对方法的调用

1.4.1 数据插入操作

1.4.1.1 插入单条数据操作

对数据库操作的话我们需要先有一个对象,叫做 orm 对象这里我定义的是 romer 对象,然后再通过 romer 的方法来对数据库进行操作,比如这里我要创建一个 user 对象而且一般都是指针类型

package main

import (
    "fmt"
    "time"

    // 注册 mysql 驱动
    _ "github.com/go-sql-driver/mysql"

    // 导入 orm 包
    "github.com/astaxie/beego/orm"
)

// 定义模型
type User struct {
    ID       int64      `orm:"column(uid);pk;auto"`
    Name     string     `orm:"size(64);"`
    Password string     `orm:"size(1024);"`
    Tel      string     `orm:"size(32);"`
    Addr     string     `orm:"type(text)"`
    Birthday *time.Time `orm:"type(date)"`
    Created  *time.Time `orm:"auto_now_add"`
    Updated  *time.Time `orm:"auto_now"`
    Deleted  *time.Time `orm:"null"`
}

func main() {
    // 1.在 orm 包中注册驱动(mysql)
    err := orm.RegisterDriver("mysql", orm.DRMySQL)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 2.注册数据库(使用数据库配置信息,有三个参数)
    dsn := "root:root@tcp(10.0.0.10:3306)/hellodb?charset=utf8mb4&loc=Local&parseTime=true"
    err = orm.RegisterDataBase("default", "mysql", dsn)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 3.注册模型,之前需要定义模型,注册是指针类型的实例
    orm.RegisterModel(&User{})

    // 4.同步数据库
    orm.RunSyncdb("default", false, true)

    // 5.通过 orm 对数据库进行操作,实现一个 ormer 对象
    ormer := orm.NewOrm()

    // 对 birthday 进行解析
    birthday, _ := time.Parse("2006-01-02", "1995-10-24")
    user := &User{
        Name:     "zz",
        Password: "1234",
        Birthday: &birthday,
    }

    // 通过 Insert 方法对数据库实现增加一行数据操作,并传入 user 结构体实例
    fmt.Println(ormer.Insert(user))
}

执行

[16:53:04 root@go testorm.v2]#go run orm.go 
table `user` already exists, skip
1 <nil>                      # 插入一条数据,1 为当前插入数据的 id = 1 ,err 返回值为 nil

# 查看数据库库 id = 1 的 zz 用户已经增加
MariaDB [hellodb]> select * from user;
+-----+------+----------+-----+------+------------+---------------------+---------------------+---------+
| uid | name | password | tel | addr | birthday   | created             | updated             | deleted |
+-----+------+----------+-----+------+------------+---------------------+---------------------+---------+
|   1 | zz   | 1234     |     |      | 1995-10-24 | 2021-08-16 16:53:11 | 2021-08-16 16:53:11 | NULL    |
+-----+------+----------+-----+------+------------+---------------------+---------------------+---------+
1 row in set (0.000 sec)

1.4.1.1.1 同时插入多个数据报错

但是当我们同时插入两条或者多条数据就会报错如下操作,

执行

[16:59:34 root@go testorm.v2]#go run orm.go 
table `user` already exists, skip
3 <nil>

# 报错 主键为 3 已经重复
0 Error 1062: Duplicate entry '3' for key 'PRIMARY'

这里我在程序中插入了两次,第一次执行增加了一个主键为 3 的 id ,第二次就报错主键为 3 已经重复。那他为什么会这样呢,我们通过下面范例进行讲解

在这次我将插入前和插入后都输出了 user 信息

[16:59:43 root@go testorm.v2]#go run orm.go 
table `user` already exists, skip

# 第一次插入之前 user 的信息是 id=0 name=zz password=123
&{0 zz 1234   1995-10-24 00:00:00 +0000 UTC <nil> <nil> <nil>}
4 <nil>

# 第一次插入以后 user 的信息就变为了 id=4 然后也更新了创建时间
&{4 zz 1234   1995-10-24 00:00:00 +0000 UTC 2021-08-16 17:05:36.682297607 +0800 CST 2021-08-16 17:05:36.68229951 +0800 CST <nil>}

# 但是在插入第二条数据的时候报错,因为他在 insert 之后会把默认的一些值回填给这个 user 对象,然后这个对象此时的 id 为 4 ,但是这时候在数据库中这个 user 表里 id 已经为 4 了,然后在这个时候 insert 就会指定他的 id 为 4 就会出现主键冲突问题
0 Error 1062: Duplicate entry '4' for key 'PRIMARY'

但是 insert 在执行的时候到底执行了什么样的 sql 语句呢?我们就可以开启 orm 的 debug 模式来看一下

1.4.1.1.2 orm debug 模式

我们可以通过 orm.Debug 开启 debug 模式,并且需要在创建数据库连接之前开启该模式

package main

import (
    "fmt"
    "time"

    // 注册 mysql 驱动
    _ "github.com/go-sql-driver/mysql"

    // 导入 orm 包
    "github.com/astaxie/beego/orm"
)

// 定义模型
type User struct {
    ID       int64      `orm:"column(uid);pk;auto"`
    Name     string     `orm:"size(64);"`
    Password string     `orm:"size(1024);"`
    Tel      string     `orm:"size(32);"`
    Addr     string     `orm:"type(text)"`
    Birthday *time.Time `orm:"type(date)"`
    Created  *time.Time `orm:"auto_now_add"`
    Updated  *time.Time `orm:"auto_now"`
    Deleted  *time.Time `orm:"null"`
}

func main() {
    // 在创建链接之前开启 debug 模式
    orm.Debug = true

    // 1.在 orm 包中注册驱动(mysql)
    err := orm.RegisterDriver("mysql", orm.DRMySQL)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 2.注册数据库(使用数据库配置信息,有三个参数)
    dsn := "root:root@tcp(10.0.0.10:3306)/hellodb?charset=utf8mb4&loc=Local&parseTime=true"
    err = orm.RegisterDataBase("default", "mysql", dsn)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 3.注册模型,之前需要定义模型,注册是指针类型的实例
    orm.RegisterModel(&User{})

    // 4.同步数据库
    orm.RunSyncdb("default", false, true)

    // 5.通过 orm 对数据库进行操作,实现一个 ormer 对象
    ormer := orm.NewOrm()

    // 对 birthday 进行解析
    birthday, _ := time.Parse("2006-01-02", "1995-10-24")
    user := &User{
        Name:     "zz",
        Password: "1234",
        Birthday: &birthday,
    }

    // 通过 Insert 方法对数据库实现增加一行数据操作,并传入 user 结构体实例
    fmt.Println(user)
    fmt.Println(ormer.Insert(user))
    fmt.Println(user)
    fmt.Println(ormer.Insert(user))
}

执行,第一次插入的时候并没有插入 id 值,第二次在插入的时候就有 uid 了

所以 orm.Insert 最终就是把要写入到数据库中的对象,转换成了 SQL 语句进行执行了,所以由此就引出了批量插入

1.4.1.2 批量插入数据操作

通过 orm.InsterMulti 实现批量插入操作

同时插入多个对象

类似sql语句

insert into table (name, age) values("slene", 28),("astaxie", 30),("unknown", 20)
ormer.InsertMulti(5, users)
// 有两个参数:
// 第1个参数是 int 值 5 ,也就是说我们一次提交 5 条数据写入到数据表中
// 第2个参数是传递切片也就是需要总共插入多少条数据到表中,len(users) 长度

package main

import (
    "fmt"
    "time"

    // 注册 mysql 驱动
    _ "github.com/go-sql-driver/mysql"

    // 导入 orm 包
    "github.com/astaxie/beego/orm"
)

// 定义模型
type User struct {
    ID       int64      `orm:"column(uid);pk;auto"`
    Name     string     `orm:"size(64);"`
    Password string     `orm:"size(1024);"`
    Tel      string     `orm:"size(32);"`
    Addr     string     `orm:"type(text)"`
    Birthday *time.Time `orm:"type(date)"`
    Created  *time.Time `orm:"auto_now_add"`
    Updated  *time.Time `orm:"auto_now"`
    Deleted  *time.Time `orm:"null"`
}

func main() {
    // 在创建链接之前开启 debug 模式
    orm.Debug = true

    // 1.在 orm 包中注册驱动(mysql)
    err := orm.RegisterDriver("mysql", orm.DRMySQL)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 2.注册数据库(使用数据库配置信息,有三个参数)
    dsn := "root:root@tcp(10.0.0.10:3306)/hellodb?charset=utf8mb4&loc=Local&parseTime=true"
    err = orm.RegisterDataBase("default", "mysql", dsn)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 3.注册模型,之前需要定义模型,注册是指针类型的实例
    orm.RegisterModel(&User{})

    // 4.同步数据库
    orm.RunSyncdb("default", false, true)

    // 5.通过 orm 对数据库进行操作,实现一个 ormer 对象
    ormer := orm.NewOrm()

    // 获取时间解析后的 birthday 
    birthday, _ := time.Parse("2006-01-02", "1995-10-24")

    // 批量操作
    users := []*User{}

    // 通过 for 循环创建 10 个用户
    for i := 0; i < 10; i++ {
        users = append(users, &User{Name: "zz", Password: "123", Birthday: &birthday})
    }
    // 有两个参数:
    // 第1个参数是 int 值 5 ,也就是说我们一次提交 5 条数据写入到数据表中
    // 第2个参数是传递切片也就是需要总共插入多少条数据到表中,len(users) 长度
    fmt.Println(ormer.InsertMulti(5, users))
}

1.4.2 数据查询操作

  • read 只读取一行数据,默认读取到匹配到的第一行,并且将读取到的数据返回给对象中

1.4.2.1 单条数据查询

1.4.2.1.1 对单条数据进行查询

查找的话一般在编辑或者删除的时候需要通过某一个 id 来获取信息。那这个时候怎么获取呢,也是先定义用户信息。

package main

import (
    "fmt"
    "time"

    // 注册 mysql 驱动
    _ "github.com/go-sql-driver/mysql"

    // 导入 orm 包
    "github.com/astaxie/beego/orm"
)

// 定义模型
type User struct {
    ID       int64      `orm:"column(uid);pk;auto"`
    Name     string     `orm:"size(64);"`
    Password string     `orm:"size(1024);"`
    Tel      string     `orm:"size(32);"`
    Addr     string     `orm:"type(text)"`
    Birthday *time.Time `orm:"type(date)"`
    Created  *time.Time `orm:"auto_now_add"`
    Updated  *time.Time `orm:"auto_now"`
    Deleted  *time.Time `orm:"null"`
}

func main() {
    // 在创建链接之前开启 debug 模式
    orm.Debug = true

    // 1.在 orm 包中注册驱动(mysql)
    err := orm.RegisterDriver("mysql", orm.DRMySQL)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 2.注册数据库(使用数据库配置信息,有三个参数)
    dsn := "root:root@tcp(10.0.0.10:3306)/hellodb?charset=utf8mb4&loc=Local&parseTime=true"
    err = orm.RegisterDataBase("default", "mysql", dsn)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 3.注册模型,之前需要定义模型,注册是指针类型的实例
    orm.RegisterModel(&User{})

    // 4.同步数据库
    orm.RunSyncdb("default", false, true)

    // 5.通过 orm 对数据库进行操作,实现一个 ormer 对象
    ormer := orm.NewOrm()

    // 定义用户信息,并想通过 id=10 的信息进行查询
    user := &User{ID: 10}
    // 通过 ormer.Read() 方法进行查询,有一个 error 返回值
    // 其实这里就是执行了一条 sql 语句 select * from user where id=10 ;
    fmt.Println(ormer.Read(user))

    // 然后再将查询到的 user 信息返回给 user 结构体
    fmt.Println(user)
}

执行

[18:17:41 root@go testorm.v3]#go run orm.go 
table `user` already exists, skip

# 这里其实就是执行的一条 sql 语句查询了 where uid = 10 的条数据
[ORM]2021/08/16 18:17:57  -[Queries/default] - [  OK / db.QueryRow /     0.4ms] - [SELECT `uid`, `name`, `password`, `tel`, `addr`, `birthday`, `created`, `updated`, `deleted` FROM `user` WHERE `uid` = ? ] - `10`
<nil>

# 然后再将查询到的 user 信息回显给 user 结构体 fmt.Println(user)
&{10 zz 123   1995-10-24 00:00:00 +0800 CST 2021-08-16 17:59:13 +0800 CST 2021-08-16 17:59:13 +0800 CST <nil>}

1.4.2.1.2 通过指定字段进行单条数据查询

当然也可以通过其他字段进行查询,比如我这里通过 name 字段进行查询,默认找到第一条数据

指定对 name 字段进行查找

package main

import (
    "fmt"
    "time"

    // 注册 mysql 驱动
    _ "github.com/go-sql-driver/mysql"

    // 导入 orm 包
    "github.com/astaxie/beego/orm"
)

// 定义模型
type User struct {
    ID       int64      `orm:"column(uid);pk;auto"`
    Name     string     `orm:"size(64);"`
    Password string     `orm:"size(1024);"`
    Tel      string     `orm:"size(32);"`
    Addr     string     `orm:"type(text)"`
    Birthday *time.Time `orm:"type(date)"`
    Created  *time.Time `orm:"auto_now_add"`
    Updated  *time.Time `orm:"auto_now"`
    Deleted  *time.Time `orm:"null"`
}

func main() {
    // 在创建链接之前开启 debug 模式
    orm.Debug = true

    // 1.在 orm 包中注册驱动(mysql)
    err := orm.RegisterDriver("mysql", orm.DRMySQL)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 2.注册数据库(使用数据库配置信息,有三个参数)
    dsn := "root:root@tcp(10.0.0.10:3306)/hellodb?charset=utf8mb4&loc=Local&parseTime=true"
    err = orm.RegisterDataBase("default", "mysql", dsn)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 3.注册模型,之前需要定义模型,注册是指针类型的实例
    orm.RegisterModel(&User{})

    // 4.同步数据库
    orm.RunSyncdb("default", false, true)

    // 5.通过 orm 对数据库进行操作,实现一个 ormer 对象
    ormer := orm.NewOrm()

    // 定义用户信息,并想通过 name=zz 的信息进行查询
    user := &User{Name: "zz"}
    // 通过 ormer.Read() 方法进行查询,默认返回第一条
    // 第一个参数是对 user 这个对象进行查找,第二个参数是对 Name 字段进行查找
    fmt.Println(ormer.Read(user, "Name"))

    // 然后再将查询到的 user 信息返回给 user 结构体
    fmt.Println(user)
}

执行

[18:32:07 root@go testorm.v3]#go run orm.go 
table `user` already exists, skip

# 这里执行 sql 语句
[ORM]2021/08/16 18:33:19  -[Queries/default] - [  OK / db.QueryRow /     0.8ms] - [SELECT `uid`, `name`, `password`, `tel`, `addr`, `birthday`, `created`, `updated`, `deleted` FROM `user` WHERE `name` = ? ] - `zz`
<nil>

# 默认将查找到的第一条数据进行输出
&{1 zz 1234   1995-10-24 00:00:00 +0800 CST 2021-08-16 16:53:11 +0800 CST 2021-08-16 16:53:11 +0800 CST <nil>}

1.4.2.1.3 通过多个字段进行单条数据查询

当然也可以通过多个属性字段进行查询

package main

import (
    "fmt"
    "time"

    // 注册 mysql 驱动
    _ "github.com/go-sql-driver/mysql"

    // 导入 orm 包
    "github.com/astaxie/beego/orm"
)

// 定义模型
type User struct {
    ID       int64      `orm:"column(uid);pk;auto"`
    Name     string     `orm:"size(64);"`
    Password string     `orm:"size(1024);"`
    Tel      string     `orm:"size(32);"`
    Addr     string     `orm:"type(text)"`
    Birthday *time.Time `orm:"type(date)"`
    Created  *time.Time `orm:"auto_now_add"`
    Updated  *time.Time `orm:"auto_now"`
    Deleted  *time.Time `orm:"null"`
}

func main() {
    // 在创建链接之前开启 debug 模式
    orm.Debug = true

    // 1.在 orm 包中注册驱动(mysql)
    err := orm.RegisterDriver("mysql", orm.DRMySQL)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 2.注册数据库(使用数据库配置信息,有三个参数)
    dsn := "root:root@tcp(10.0.0.10:3306)/hellodb?charset=utf8mb4&loc=Local&parseTime=true"
    err = orm.RegisterDataBase("default", "mysql", dsn)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 3.注册模型,之前需要定义模型,注册是指针类型的实例
    orm.RegisterModel(&User{})

    // 4.同步数据库
    orm.RunSyncdb("default", false, true)

    // 5.通过 orm 对数据库进行操作,实现一个 ormer 对象
    ormer := orm.NewOrm()

    // 定义用户信息,并想通过对 name=zz 和 Password=1234 的信息进行查询
    user := &User{Name: "zz", Password: "1234"}
    // 通过 ormer.Read() 方法进行查询,默认返回第一条
    // 第一个参数是对 user 这个对象进行查找,第二个参数是对 Name 字段进行查找,第三个参数对 password 进行查找
    fmt.Println(ormer.Read(user, "Name", "Password"))

    // 然后再将查询到的 user 信息返回给 user 结构体
    fmt.Println(user)
}

执行默认找到第一条数据

[18:39:17 root@go testorm.v3]#go run orm.go 
table `user` already exists, skip

# 这里执行 sql 语句
[ORM]2021/08/16 18:39:51  -[Queries/default] - [  OK / db.QueryRow /     0.8ms] - [SELECT `uid`, `name`, `password`, `tel`, `addr`, `birthday`, `created`, `updated`, `deleted` FROM `user` WHERE `name` = ? AND `password` = ? ] - `zz`, `1234`
<nil>

# 默认将 uid=1 的数据进行输出
&{1 zz 1234   1995-10-24 00:00:00 +0800 CST 2021-08-16 16:53:11 +0800 CST 2021-08-16 16:53:11 +0800 CST <nil>}

1.4.2.2 多条数据查询

1.4.2.3 ORM 过滤条件:查询

在 orm 中还提供了查询集,支持对 sql 的各种查询上。在查询集中查询支持两种,一种是对满足条件的进行查询,第二种就是对不满足条件的进行查询,一般我们会使用满足条件的多一些调用的是 Queryset 的 Filter 方法

// 满足条件 Filter 方法
// 不满足条件 Exclude
// 并且这两个方法的参数都是一样的
// 对于查询一般有两种:
// 1.Count
// 2.过滤数据

1.4.2.3.1 Count 查询数据表总和

QueryTable 可以指定我们的表名和结构体的指针比如下面代码中的 user

package main

import (
    "fmt"
    "time"

    // 注册 mysql 驱动
    _ "github.com/go-sql-driver/mysql"

    // 导入 orm 包
    "github.com/astaxie/beego/orm"
)

// 定义模型
type User struct {
    // 开启 debug 模式
    orm.Debug = true

    
    // 通过 orm 标签自定义列名,这里是将 id 写入到数据表中是 uid
    ID int64 `orm:"column(uid);pk;auto"`
    // 通过 orm 标签自定义属性长度
    Name     string `orm:"size(64);default(aaa)"`
    Password string
    Sex      bool
    Tel      string `orm:"index"`
    Addr     string `orm:"type(text)"`
    Age      string
    Birthday *time.Time `orm:"type(date)"`
    Created  *time.Time
    Updated  *time.Time
    Deleted  *time.Time `orm:"null"`
}

func main() {
    // 1.在 orm 包中注册驱动(mysql)
    err := orm.RegisterDriver("mysql", orm.DRMySQL)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 2.注册数据库(使用数据库配置信息,有三个参数)
    dsn := "root:root@tcp(10.0.0.10:3306)/hellodb?charset=utf8mb4&loc=Local&parseTime=true"
    err = orm.RegisterDataBase("default", "mysql", dsn)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 3.注册模型,之前需要定义模型,注册是指针类型的实例
    orm.RegisterModel(&User{})

    // 4.操作,查询集
    ormer := orm.NewOrm()

    // 查询集第一个要指定查询那张表
    queryset := ormer.QueryTable(&User{})

    // 查询 Count 数据表总和
    fmt.Println(queryset.Count())
}

执行

# 查询到在 user 数据表中一共有 5 条数据
[22:14:05 root@go testorm]#go run orm.go 
[ORM]2021/08/18 20:17:24  -[Queries/default] - [  OK / db.QueryRow /     0.4ms] - [SELECT COUNT(*) FROM `user` T0 ]
5 <nil>

如果需要过滤出数据来我们需要定义过滤数据的切片

[22:25:23 root@go testorm]#go run orm.go 
5 <nil>
5 <nil>                   # 获取到 5 条数据
[0xc0001221c0 0xc000122230 0xc0001222a0 0xc000122310 0xc000122380]

1.4.2.3.2 Filter 通过条件查询
  • filter 函数主要有两个参数

    • 第一个参数就是就是列名__比较方法和那个字段进行比较(这里是两个下划线)

    • 第二个参数就是比较的值

比较方法:
= 比较方法叫 exact
> 比较方法叫 gt
< 比较方法叫 lt
>= 比较方法叫 gte
<= 比较方法叫 lte
in 比较方法叫 in
like:
    value%  以什么开头比较方法叫 startswith
    %value  以什么结尾比较方法叫 endswith
    %value% 包含什么比较方法叫   contains
is null 比较方法叫 isnull

如果是字符串是否忽略大小写,默认区分忽略,想忽略大小写使用 iexact、istartswith、iendswith、icontains

那这里的我想查询 id 大于 3 的如下代码范例

package main

import (
    "fmt"
    "time"

    // 注册 mysql 驱动
    _ "github.com/go-sql-driver/mysql"

    // 导入 orm 包
    "github.com/astaxie/beego/orm"
)

// 定义模型
type User struct {
    ID       int64      `orm:"column(uid);pk;auto"`
    Name     string     `orm:"size(64);"`
    Password string     `orm:"size(1024);"`
    Tel      string     `orm:"size(32);"`
    Addr     string     `orm:"type(text)"`
    Birthday *time.Time `orm:"type(date)"`
    Created  *time.Time `orm:"auto_now_add"`
    Updated  *time.Time `orm:"auto_now"`
    Deleted  *time.Time `orm:"null"`
}

func main() {
    orm.Debug = true
    
    // 1.在 orm 包中注册驱动(mysql)
    err := orm.RegisterDriver("mysql", orm.DRMySQL)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 2.注册数据库(使用数据库配置信息,有三个参数)
    dsn := "root:root@tcp(10.0.0.10:3306)/hellodb?charset=utf8mb4&loc=Local&parseTime=true"
    err = orm.RegisterDataBase("default", "mysql", dsn)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 3.注册模型,之前需要定义模型,注册是指针类型的实例
    orm.RegisterModel(&User{})

    // 4.操作,查询集
    ormer := orm.NewOrm()

    // 查询集第一个要指定查询那张表
    queryset := ormer.QueryTable(&User{})

    // 注意 Filter 之后不会改变原有结构体的值,所以需要重新赋值
    queryset = queryset.Filter("id__gt", 3)

    // 查询 Count 数据表总和
    fmt.Println(queryset.Count())

    // 定义 user 结构体的切片赋值给 users
    var users []*User
    // 通过 queryset.All 方法获取所有的数据
    fmt.Println(queryset.All(&users))
    for _, user := range users {
        fmt.Println(user)
    }
}

执行

[22:40:10 root@go testorm]#go run orm.go 
2 <nil>                   # id 大于 3 的数据一共只有两条
2 <nil>

# id 大于 3 的数据就已经查询并且输出
&{4 zz 1234   1995-10-24 00:00:00 +0800 CST 2021-08-16 17:05:36 +0800 CST 2021-08-16 17:05:36 +0800 CST <nil>}
&{5 zz 1234   1995-10-24 00:00:00 +0800 CST 2021-08-16 17:31:45 +0800 CST 2021-08-16 17:31:45 +0800 CST <nil>}

如果我们想通过 and 方式查询 ,我们就可以在跟 Filter() 函数,这里我想在查询 name 字段包含 zz

执行

# 这就是 id 大于 3 并且 name 字段包含 zz 的数据
[22:47:01 root@go testorm]#go run orm.go 
2 <nil>
2 <nil>
&{4 zz 1234   1995-10-24 00:00:00 +0800 CST 2021-08-16 17:05:36 +0800 CST 2021-08-16 17:05:36 +0800 CST <nil>}
&{5 zz 1234   1995-10-24 00:00:00 +0800 CST 2021-08-16 17:31:45 +0800 CST 2021-08-16 17:31:45 +0800 CST <nil>}

1.4.2.3.3 Exclude 不满足条件查询

这里是 id 大于 3 且 name 不包含 zz 的数据

执行

# 0 条因为在我们的数据库中该表 name 字段都是 zz
[22:52:04 root@go testorm]#go run orm.go 
0 <nil>
0 <nil>

# 查询数据库
MariaDB [hellodb]> select * from user;
+-----+------+----------+-----+------+------------+---------------------+---------------------+---------+
| uid | name | password | tel | addr | birthday   | created             | updated             | deleted |
+-----+------+----------+-----+------+------------+---------------------+---------------------+---------+
|   1 | zz   | 1234     |     |      | 1995-10-24 | 2021-08-16 16:53:11 | 2021-08-16 16:53:11 | NULL    |
|   2 | zz   | 1234     |     |      | 1995-10-24 | 2021-08-16 16:59:34 | 2021-08-16 16:59:34 | NULL    |
|   3 | zz   | 1234     |     |      | 1995-10-24 | 2021-08-16 16:59:43 | 2021-08-16 16:59:43 | NULL    |
|   4 | zz   | 1234     |     |      | 1995-10-24 | 2021-08-16 17:05:36 | 2021-08-16 17:05:36 | NULL    |
|   5 | zz   | 1234     |     |      | 1995-10-24 | 2021-08-16 17:31:45 | 2021-08-16 17:31:45 | NULL    |
+-----+------+----------+-----+------+------------+---------------------+---------------------+---------+
5 rows in set (0.000 sec)

1.4.2.3.4 只想查询表中的个别属性范例

如果我们在对表进行查询的时候我们只想查询一两个字段信息就可以通过下面代码实现

这里我只想查询 users 结构体中的 id 和 name 字段

执行

# 将 id 大于 3 的且只查询了 id 和 name 字段
[23:01:25 root@go testorm]#go run orm.go 
2 <nil>
2 <nil>
&{4 zz    <nil> <nil> <nil> <nil>}
&{5 zz    <nil> <nil> <nil> <nil>}

1.4.3.4.5 分页查询

有的时候我们想进行分页查询必须在 All 和 Count 之后,如下面代码,我想看前三条数据

执行

# 将 user 表中的前 3 条数据输出
[23:09:02 root@go testorm]#go run orm.go 
5 <nil>
3 <nil>
&{1 zz 1234   1995-10-24 00:00:00 +0800 CST 2021-08-16 16:53:11 +0800 CST 2021-08-16 16:53:11 +0800 CST <nil>}
&{2 zz 1234   1995-10-24 00:00:00 +0800 CST 2021-08-16 16:59:34 +0800 CST 2021-08-16 16:59:34 +0800 CST <nil>}
&{3 zz 1234   1995-10-24 00:00:00 +0800 CST 2021-08-16 16:59:43 +0800 CST 2021-08-16 16:59:43 +0800 CST <nil>}

如果我们想查询的数据是在 id 为 2 之后的第一条,就可以通过Limit().Offset() 的方式进行查询

执行

[23:10:09 root@go testorm]#go run orm.go 
5 <nil>                   # user 表中一共 5 条数据
1 <nil>                   # 查询到 1 条
&{3 zz 1234   1995-10-24 00:00:00 +0800 CST 2021-08-16 16:59:43 +0800 CST 2021-08-16 16:59:43 +0800 CST <nil>}

1.4.3 数据更新操作

对数据修改的话需要先查询到之后在进行修改,比如我这里查找 id=10 的数据,然后再进行更新,如果我们没有先查询就直接更新的话其他就会变成空

通过 Update() 方法进行修改,有两个返回值:1.更新的数量 2.更新时候出现的错误

package main

import (
    "fmt"
    "time"

    // 注册 mysql 驱动
    _ "github.com/go-sql-driver/mysql"

    // 导入 orm 包
    "github.com/astaxie/beego/orm"
)

// 定义模型
type User struct {
    ID       int64      `orm:"column(uid);pk;auto"`
    Name     string     `orm:"size(64);"`
    Password string     `orm:"size(1024);"`
    Tel      string     `orm:"size(32);"`
    Addr     string     `orm:"type(text)"`
    Birthday *time.Time `orm:"type(date)"`
    Created  *time.Time `orm:"auto_now_add"`
    Updated  *time.Time `orm:"auto_now"`
    Deleted  *time.Time `orm:"null"`
}

func main() {
    // 在创建链接之前开启 debug 模式
    orm.Debug = true

    // 1.在 orm 包中注册驱动(mysql)
    err := orm.RegisterDriver("mysql", orm.DRMySQL)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 2.注册数据库(使用数据库配置信息,有三个参数)
    dsn := "root:root@tcp(10.0.0.10:3306)/hellodb?charset=utf8mb4&loc=Local&parseTime=true"
    err = orm.RegisterDataBase("default", "mysql", dsn)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 3.注册模型,之前需要定义模型,注册是指针类型的实例
    orm.RegisterModel(&User{})

    // 4.同步数据库
    orm.RunSyncdb("default", false, true)

    // 5.通过 orm 对数据库进行操作,实现一个 ormer 对象
    ormer := orm.NewOrm()

    // 查询 id=10 的数据,并赋值给 user 这个对象
    user := &User{ID: 10}
    fmt.Println(ormer.Read(user))

    // 数据修改,这里将 user.Name 改为 zz123,密码改为 password123
    // 如果只更新一个属性的话只需要写一个对象的属性信息即可
    user.Name = "zz123"
    user.Password = "123456"

    // 更改完了数据之后就要更新数据库
    fmt.Println(ormer.Update(user))
}

执行

[18:49:59 root@go testorm.v4]#go run orm.go 
table `user` already exists, skip

# 查询到的数据其实执行的是 sql 语句
[ORM]2021/08/16 18:50:05  -[Queries/default] - [  OK / db.QueryRow /     0.7ms] - [SELECT `uid`, `name`, `password`, `tel`, `addr`, `birthday`, `created`, `updated`, `deleted` FROM `user` WHERE `uid` = ? ] - `10`
<nil>

# 查询到的数据
&{10 zz 123   1995-10-24 00:00:00 +0800 CST 2021-08-16 17:59:13 +0800 CST 2021-08-16 17:59:13 +0800 CST <nil>}

# 修改之后的数据其实执行的是 sql 语句
[ORM]2021/08/16 18:50:05  -[Queries/default] - [  OK /     db.Exec /     4.0ms] - [UPDATE `user` SET `name` = ?, `password` = ?, `tel` = ?, `addr` = ?, `birthday` = ?, `updated` = ?, `deleted` = ? WHERE `uid` = ?] - `zz123`, `123456`, ``, ``, `1995-10-24 00:00:00 +0800 CST`, `2021-08-16 18:50:05.075070565 +0800 CST`, `<nil>`, `10`
1 <nil>

# 通过数据库查询 uid=10 的数据,发现已经修改
MariaDB [hellodb]> select * from user where uid=10;
+-----+-------+----------+-----+------+------------+---------------------+---------------------+---------+
| uid | name  | password | tel | addr | birthday   | created             | updated             | deleted |
+-----+-------+----------+-----+------+------------+---------------------+---------------------+---------+
|  10 | zz123 | 123456   |     |      | 1995-10-24 | 2021-08-16 17:59:13 | 2021-08-16 18:50:05 | NULL    |
+-----+-------+----------+-----+------+------------+---------------------+---------------------+---------+
1 row in set (0.000 sec)

1.4.3.1 修改数据注意事项

如果我们没有先查询就直接更新的话其他字段就会变成空如下操作,因为他没有提前读取到 id=10 数据给 user 所以 orm 不知道我们需要修改的数据是哪个

1.先将查询操作注释

2.查看该字段原有数据

# uid=10 字段的原有数据
MariaDB [hellodb]> select * from user where uid=10;
+-----+----------+----------+-----+------+------------+---------------------+---------------------+---------+
| uid | name     | password | tel | addr | birthday   | created             | updated             | deleted |
+-----+----------+----------+-----+------+------------+---------------------+---------------------+---------+
|  10 | zz123456 | 123456   |     |      | 1995-10-24 | 2021-08-16 17:59:13 | 2021-08-16 18:54:00 | NULL    |
+-----+----------+----------+-----+------+------------+---------------------+---------------------+---------+
1 row in set (0.000 sec)

3.执行程序

[19:00:47 root@go testorm.v4]#go run orm.go 
table `user` already exists, skip
[ORM]2021/08/16 19:01:09  -[Queries/default] - [FAIL /     db.Exec /     0.8ms] - [UPDATE `user` SET `name` = ?, `password` = ?, `tel` = ?, `addr` = ?, `birthday` = ?, `updated` = ?, `deleted` = ? WHERE `uid` = ?] - `zz123456`, ``, ``, ``, `<nil>`, `2021-08-16 19:01:09.062741243 +0800 CST`, `<nil>`, `10` - Error 1048: Column 'birthday' cannot be null

# 程序直接报错 birthday 字段不能为 null
0 Error 1048: Column 'birthday' cannot be null

所以我们在进行更新操作的时候一定要主要需要先查询然后再更新

1.4.4 数据删除操作

删除一般我们都是按照 id 进行删除。

通过Delete 方法进行删除

package main

import (
    "fmt"
    "time"

    // 注册 mysql 驱动
    _ "github.com/go-sql-driver/mysql"

    // 导入 orm 包
    "github.com/astaxie/beego/orm"
)

// 定义模型
type User struct {
    ID       int64      `orm:"column(uid);pk;auto"`
    Name     string     `orm:"size(64);"`
    Password string     `orm:"size(1024);"`
    Tel      string     `orm:"size(32);"`
    Addr     string     `orm:"type(text)"`
    Birthday *time.Time `orm:"type(date)"`
    Created  *time.Time `orm:"auto_now_add"`
    Updated  *time.Time `orm:"auto_now"`
    Deleted  *time.Time `orm:"null"`
}

func main() {
    // 在创建链接之前开启 debug 模式
    orm.Debug = true

    // 1.在 orm 包中注册驱动(mysql)
    err := orm.RegisterDriver("mysql", orm.DRMySQL)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 2.注册数据库(使用数据库配置信息,有三个参数)
    dsn := "root:root@tcp(10.0.0.10:3306)/hellodb?charset=utf8mb4&loc=Local&parseTime=true"
    err = orm.RegisterDataBase("default", "mysql", dsn)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 3.注册模型,之前需要定义模型,注册是指针类型的实例
    orm.RegisterModel(&User{})

    // 4.同步数据库
    orm.RunSyncdb("default", false, true)

    // 5.通过 orm 对数据库进行操作,实现一个 ormer 对象
    ormer := orm.NewOrm()

    // 删除 id=10 的数据,并赋值给 user 这个对象
    user := &User{ID: 10}
    // 删除 user 这个对象,现在他的 id 为 10 也就是说删除 id 为 10 的表
    fmt.Println(ormer.Delete(user))
}

执行程序

[19:04:16 root@go testorm.v4 copy]#go run orm.go 
table `user` already exists, skip
[ORM]2021/08/16 19:06:41  -[Queries/default] - [  OK /     db.Exec /     2.6ms] - [DELETE FROM `user` WHERE `uid` = ?] - `10`

# 1 条数据删除成功,返回值为 nil
1 <nil>

# 通过在数据库中查询,这条数据已经为空表示我们已经删除
MariaDB [hellodb]> select * from user where uid=10;
Empty set (0.000 sec)

1.4.4.1 指定通过字段进行删除

这里我指定通过 password=123 的字段进行删除,将他写道 delete 方法中的第二个参数

执行程序

[19:06:41 root@go testorm.v4 copy]#go run orm.go 
table `user` already exists, skip
[ORM]2021/08/16 19:12:53  -[Queries/default] - [  OK /     db.Exec /     2.7ms] - [DELETE FROM `user` WHERE `password` = ?] - `123`
# 19 条数据删除成功,返回的错误为 nil
19 <nil>

1.4.4.2 指定多个字段删除

通过在后面写入多个参数实现对多个字段的删除

执行输出,我们可以发现通过 password 和 uid 进行删除

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇