李林超博客
首页
归档
留言
友链
动态
关于
归档
留言
友链
动态
关于
首页
GO
正文
08.Beego框架ORM介绍
Leefs
2022-08-04 AM
3225℃
0条
[TOC] ### 一、介绍 对象关系映射(Object Relational Mapping,简称ORM), 它的作用是映射数据库和对象之间的关系,方便我们在实现数据库操作的时候不用去写复杂的sql语句,把对数据库的操作上升到对于对象的操作。 beego ORM 是一个强大的 Go 语言 ORM 框架。它的灵感主要来自 Django ORM 和 SQLAlchemy。它支持go语言中所有的类型存储,允许直接使用原生的SQL语句,采用GRUD风格能够轻松上手,能自动Join关联表,并允许跨数据库兼容查询。 **beego支持的数据库类型** - MySQL:[github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) - PostgreSQL:[github.com/lib/pq](https://github.com/lib/pq) - Sqlite3:[github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) **使用不同的数据库,需要导入不同的数据库驱动:** ```go import ( // 导入mysql驱动 _ "github.com/go-sql-driver/mysql" // 导入sqlite3驱动 _ "github.com/mattn/go-sqlite3" // 导入Postgres驱动 _ "github.com/lib/pq" ) ``` 如需使用上面某种数据库,请先go get,并且导入库的时候需要在前面使用 "_" 符号。 ### 二、ORM特性 - 支持 Go 的所有类型存储 - 轻松上手,采用简单的 CRUD 风格 - 自动 Join 关联表 - 跨数据库兼容查询 - 允许直接使用 SQL 查询/映射 - 严格完整的测试保证 ORM 的稳定与健壮 ### 三、数据库链接 > 本次以MySQL数据库为例对Beego整合ORM和连接数据库进行演示 #### 3.1 安装包 (1)因为beego orm是独立的模块,所以需要单独安装包。 ```go // 安装beego orm包 go get github.com/beego/beego/v2/client/orm ``` (2)安装mysql驱动 ```go go get github.com/go-sql-driver/mysql ``` *注意:beego orm包操作什么数据库,就需要单独安装对应的数据库驱动。* #### 3.2 导入包 ```go import ( // 导入orm包 "github.com/beego/beego/v2/client/orm" // 导入mysql驱动 _ "github.com/go-sql-driver/mysql" ) ``` 本次在main.go文件中进行导入。 #### 3.3 连接数据库 操作数据库之前首先需要配置好mysql数据库连接参数,通常在beego项目中,我们都会在main.go文件,对数据库进行配置,方便整个项目操作数据库。 ```go package main import ( _ "beegodemo/routers" "github.com/beego/beego/v2/server/web" // 导入orm包 "github.com/beego/beego/v2/client/orm" // 导入mysql驱动 _ "github.com/go-sql-driver/mysql" ) // 通过init函数配置mysql数据库连接信息 func init() { // 这里注册一个default默认数据库,数据库驱动是mysql. // 第三个参数是数据库dsn, 配置数据库的账号密码,数据库名等参数 // dsn参数说明: // username - mysql账号 // password - mysql密码 // db_name - 数据库名 // 127.0.0.1:3306 - 数据库的地址和端口 orm.RegisterDataBase("default", "mysql", "username:password@tcp(127.0.0.1:3306)/db_name?charset=utf8&parseTime=true&loc=Local") // 打开调试模式,开发的时候方便查看orm生成什么样子的sql语句 orm.Debug = true } func main() { web.Run() } ``` ##### MySQL数据库连接参数详解 **注册数据库的函数原型:** ```go func RegisterDataBase(aliasName, driverName, dataSource string, params ...int) error ``` **参数说明** | 参数名 | 说明 | | :--------- | :---------------------------------------- | | aliasName | 数据库的别名,用来在 ORM 中切换数据库使用 | | driverName | 驱动名字 | | dataSource | 数据库连接字符串 | | params | 附加参数 | *注意:ORM 必须注册一个别名为 **default** 的数据库,作为默认使用的数据库。* **mysql数据库连接字符串DSN (Data Source Name):** ```go username:password@protocol(address)/dbname?param=value ``` **参数说明** | 参数名 | 说明 | | :---------- | :----------------------------------------------------------- | | username | 数据库账号 | | password | 数据库密码 | | protocol | 连接协议,一般就是tcp | | address | 数据库地址,可以包含端口。例: localhost:3306 , 127.0.0.1:3306 | | dbname | 数据库名字 | | param=value | 最后面问号(?)之后可以包含多个键值对的附加参数,多个参数之间用&连接。 | **常用附加参数说明** | 参数名 | 默认值 | 说明 | | :---------- | :----- | :----------------------------------------------------------- | | charset | none | 设置字符集,相当于 SET NAMES
语句 | | loc | UTC | 设置时区,可以设置为Local,表示根据本地时区走 | | parseTime | false | 是否需要将 mysql的 DATE 和 DATETIME 类型值转换成GO的time.Time类型。 | | readTimeout | 0 | I/O 读超时时间, sql查询超时时间. 单位 ("ms", "s", "m", "h"), 例子: "30s", "0.5m" or "1m30s". | | timeout | 0 | 连接超时时间,单位("ms", "s", "m", "h"), 例子: "30s", "0.5m" or "1m30s". | **示例** ```go root:123456@(127.0.0.1:3306)/test?charset=utf8&timeout=5s&loc=Local&parseTime=true ``` #### 3.4 其他设置(非必须) **(1)数据库连接池设置** **数据库连接词参数主要有下面两个:** | 参数 | 说明 | 示例 | | --------------- | -------------------------------------------- | ----------------------------------- | | SetMaxIdleConns | 根据数据库的别名,设置数据库的最大空闲连接 | orm.SetMaxIdleConns("default", 20) | | SetMaxOpenConns | 根据数据库的别名,设置数据库的最大数据库连接 | orm.SetMaxOpenConns("default", 100) | **(2)数据库调试模式** ```go orm.Debug = true ``` 打开调试模式,当执行orm查询的时候,会打印出对应的sql语句。 ### 四、定义模型 **4.1 创建结构体字段** + 在models目录中创建文件`userDemo.go`,并创建对应结构体字段 ```go package models import ( "github.com/astaxie/beego/orm" "time" ) type UserDemo struct { Id int32 `json:"id" pk:"auto;column(id)"` //主键自增,列名设为id Name string `json:"name" orm:"size(15);column(name)"` //设置varchar长度为15,列名为name Password string `json:"password" orm:"size(15);column(password)"` //设置varchar长度为15,列名为password Age int32 `json:"age" orm:"column(age)"` //int32默认生成int类型长度为11,列名为age Email string `json:"email" orm:"size(30);column(email);null"` //设置varchar长度为30,列名为email,可为空(默认不能为空) Tel string `json:"tel" orm:"size(11);column(tel)"` //设置varchar长度为11,列名为tel Address string `json:"address" orm:"null"` //设置字段可为空 CreateTime time.Time `json:"createTime" orm:"auto_now_add;type(datetime);null"` //auto_now_add第一次保存时才设置时间,可为空 UpdataTime time.Time `json:"updataTime" orm:"auto_now;type(datetime);null"` //auto_now每次model保存时都会对时间自动更新,可为空 } ``` + json标签表示以JSON格式返回字段的字段名 + orm标签在生成表时进行映射,会在后面章节做详细介绍 *作为一个GO语言小白必须要吐槽一下这里的`time.Time`字段类型。在进行下面的功能操作时,不论是从前端接收时间类型参数,还是通过JSON方式返回数据,在进行时间格式化的时候都很麻烦。* *个人觉得还是把时间类型定义成string类型比较好,需要进行时间操作在单独进行类型转换。* **4.2 注册数据库表** + 在`userDemo.go`文件的init()函数中注册数据库表 用orm.RegisterModel()函数,参数是结构体对象,如果有多个表,可以用 `,`隔开,多new几个对象: ```go func init() { //向orm注册UserDemo模型 //以下两种方式都可以 //orm.RegisterModel(new(UserDemo)) orm.RegisterModel(&UserDemo{}) //使用RegisterModelWithPrefix为表名设置前缀:prefix_user_demo //orm.RegisterModelWithPrefix("prefix_", new(UserDemo)) } ``` **4.3 生成表** + 在main.go文件的init()函数中通过orm.RunSyncdb()函数生成表 ```go orm.RunSyncdb("default",false,true) ``` **参数说明** + **参数一**:数据库的别名和连接数据库的第一个参数相对应。 + **参数二**:是否强制更新,一般我们写的都是false,如果写true的话,每次项目编译一次数据库就会被清空一次,fasle的话会在数据库发生重大改变(比如添加字段)的时候更新数据库。 + **参数三**:生成表过程是否可见,如果设置成true,生成表的时候执行的SQL语句就会在终端看到。 注意:因为注册表方法在models包下,所以想要使注册方法RegisterModel生效需要在main.go文件下引入如下包。 ```go import _ "go_project/models" ``` + go_project为项目名称,根据自己项目名称进行相应修改 **main.go文件完整代码** ```go package main import ( "github.com/astaxie/beego" "github.com/astaxie/beego/orm" _ "go_project/models" _ "go_project/routers" //导入mysql驱动,这是必须的 _ "github.com/go-sql-driver/mysql" ) func init() { //初始化数据库连接 orm.RegisterDataBase("default", "mysql", "username:password@tcp(127.0.0.1:3306)/db_name?charset=utf8") //生成表 orm.RunSyncdb("default",false,true) // 打开调试模式,开发的时候方便查看orm生成什么样子的sql语句 orm.Debug = true } func main() { beego.Run() } ``` **执行main函数,控制台输出创建表语句:** ```sql create table `user_demo` -- -------------------------------------------------- -- Table Structure for `go_project/models.UserDemo` -- -------------------------------------------------- CREATE TABLE IF NOT EXISTS `user_demo` ( `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(15) NOT NULL DEFAULT '' , `password` varchar(15) NOT NULL DEFAULT '' , `age` integer NOT NULL DEFAULT 0 , `email` varchar(30), `tel` varchar(11) NOT NULL DEFAULT '' , `address` varchar(255), `create_time` datetime, `updata_time` datetime ) ENGINE=InnoDB; ``` **表被成功创建** ![08.Beego框架ORM介绍01.jpg](https://lilinchao.com/usr/uploads/2022/08/268674467.jpg) ### 五、基本操作 + 在`controllers`文件夹下创建`UserController.go`文件,用来处理接收到的参数和返回数据 + 在models文件夹下创建`userDemo.go`文件,用来操作数据库 #### 5.1 添加数据 + **`UserController.go`文件增加如下方法** ```go func (d *UserController) Create(){ // 定义保存json数据的struct对象 userDemo := &models.UserDemo{} // 获取body内容 bodyData := d.Ctx.Input.RequestBody // 反序列json数据,结果保存至userDemo if err := json.Unmarshal(bodyData, userDemo); err == nil { // 解析参数失败 log.Fatal(err) return } id, err := userDemo.Insert() if err != nil { log.Fatal(err) return } //如果添加成功,返回对应的ID d.Data["json"] = id d.ServeJSON() } ``` + **`models/userDemo.go`文件下新增添加方法** ```go func (u *UserDemo) Insert() (int64, error) { return orm.NewOrm().Insert(u) } ``` + **调用添加接口进行测试** ![08.Beego框架ORM介绍02.jpg](https://lilinchao.com/usr/uploads/2022/08/3974571153.jpg) #### 5.2 批量添加 + **`UserController.go`文件** ```go /* 批量添加 */ func (d *UserController) CreateBatch(){ users := []models.UserDemo{} bodyData := d.Ctx.Input.RequestBody err := json.Unmarshal(bodyData, &users) if err != nil { log.Fatal(err) return } num, err := models.InsertBatch(&users) if err != nil { log.Fatal(err) return } d.Data["json"] = num d.ServeJSON() } ``` + **`models/userDemo.go`文件新增InsertBatch()函数**(注意,这里是函数,不是方法) ```go func InsertBatch(users *[]UserDemo) (int64, error) { // 调用InsertMulti函数批量插入, 第一个参数指的是并行插入的行数,如果为1表示顺序插入 return orm.NewOrm().InsertMulti(1,users) } ``` + **调用接口进行测试** ![08.Beego框架ORM介绍03.jpg](https://lilinchao.com/usr/uploads/2022/08/1242681883.jpg) #### 5.3 更新操作 > 更新操作有两种方式: > > + 更新所有字段,当不传值时默认为空值,对数据库原有值进行覆盖操作 > + 根据非空字段进行更新相应参数(比较常用) + **`UserController.go`文件** ```go func (d *UserController) Update(){ userDemo := &models.UserDemo{} bodyData := d.Ctx.Input.RequestBody err := json.Unmarshal(bodyData, userDemo) if err != nil { log.Fatal(err) return } //更新所有值 //_, err = userDemo.Update() //更新特定字段 err = userDemo.UpdateChoose() if err != nil { log.Fatal(err) return } d.Data["json"] = "更新成功" d.ServeJSON() } ``` + **`models/userDemo.go`文件** ```go //该方式会更新所有字段,当不传值时会置空 func (u *UserDemo) Update() (int64, error) { return orm.NewOrm().Update(u) } //根据非空字段进行更新相应参数 func (u *UserDemo) UpdateChoose(fields ...string) error { param := make([]string, 0, 6) if len(fields) > 0{ param = fields } else { if u.Name != "" { param = append(param, "name") } if u.Password != "" { param = append(param, "password") } if u.Age > 0 { param = append(param, "age") } if u.Email != "" { param = append(param, "email") } if u.Tel != "" { param = append(param, "tel") } if u.Address != "" { param = append(param, "address") } } o := orm.NewOrm() if _, err := o.Update(u, param...); err != nil { return err } return nil } ``` + **测试根据根据传入字段更新特定值** ![08.Beego框架ORM介绍04.jpg](https://lilinchao.com/usr/uploads/2022/08/2246978515.jpg) #### 5.4 查询操作 > 查询操作有如下两种方式: > > + 查询表中所有字段中的数据,并返回 > + 查询出规定某些字段的数据,对于未被查询的其他字段返回空 *本次是针对单条数据的查询* + **`UserController.go`文件** ```go func (d *UserController) Read(){ id, _ := d.GetInt32("id") if id < 0 { return } user := models.UserDemo{Id: id} //方式一:查询出所有字段 //err := user.Read() //方式二:根据传入的字段查询出对应的信息 err := user.Read("id","name","age","email","tel","address") if err != nil { log.Fatal(err) return } d.Data["json"] = user d.ServeJSON() } ``` + **`models/userDemo.go`文件** ```go func (d *UserDemo) Read(fields ...string) error { if len(fields) == 0 { err := orm.NewOrm().Read(d) return err } //拼接数据格式 columns := utils.SliceToFlat(fields) //拼接查询语句 sql := fmt.Sprintf("select id,%s from %s where id=?", columns, TALE_NAME) return orm.NewOrm().Raw(sql, d.Id).QueryRow(d) } ``` + **拼接数据格式工具** ```go package utils func SliceToFlat(data []string) string { length := len(data) if length == 0 { return "" } result := "" for k, v := range data { result += v if k < (length - 1) { result += "," } } return result } ``` + **接口测试根据传入的字段查询出对应的信息** ![08.Beego框架ORM介绍05.jpg](https://lilinchao.com/usr/uploads/2022/08/1119063488.jpg) #### 5.5 删除数据 + **`UserController.go`文件** ```go func (d *UserController) Delete(){ id, _ := d.GetInt32("id") if id < 0 { return } //根据Id进行删除操作 user := models.UserDemo{Id: id} //调用删除方法 err := user.Delete() if err != nil { log.Fatal(err) return } d.Data["json"] = "删除成功" d.ServeJSON() } ``` + **models/userDemo.go文件** ```go func (u *UserDemo) Delete() error { if _, err := orm.NewOrm().Delete(u); err != nil { return err } return nil } ``` + **测试删除接口** ![08.Beego框架ORM介绍06.jpg](https://lilinchao.com/usr/uploads/2022/08/2260276882.jpg) ### 六、ORM标签 | 标签 | 说明 | 示例 | | ------------------- | ------------------------------------------------------------ | ----------------------------------- | | auto | 当 Field 类型为 int, int32, int64, uint, uint32, uint64 时,可以设置字段为自增健 | `orm:"auto"` | | pk | 设置为主键,适用于自定义其他类型为主键 | `orm:"pk;atuo"`(主键自增长) | | `-` | 设置 `-` 即可忽略 struct 中的字段 | `orm:"-"` | | null | 数据库表默认为 NOT NULL,设置 null 代表允许为空 | `orm:"null"` | | index | 为单个字段增加索引 | `orm:"index"` | | unique | 为单个字段增加 unique 键,让该属性的内容不能重复 | `orm:"unique"` | | column | 为字段设置 db 字段的名称,就是设置列名 | `orm:"column(user_name)"` | | size | 设置字段大小 | `orm:"size(15)"` | | `digits / decimals` | 设置 float32, float64 类型的浮点精度 | `orm:"digits(12);decimals(4)"` | | auto_now | 每次 model 保存时都会对时间自动更新 | `orm:"auto_now_add;type(datetime)"` | | auto_now_add | 第一次保存时才设置时间 | `orm:"auto_now;type(datetime)"` | | default | 为字段设置默认值,类型必须符合(目前仅用于级联删除时的默认值) | | + **type标签** + 设置为 date 时,`time.Time` 字段的对应 db 类型使用 date ```go Created time.Time `orm:"auto_now_add;type(date)"` ``` + 设置为 datetime 时,`time.Time` 字段的对应 db 类型使用 datetime ```go Created time.Time `orm:"auto_now_add;type(datetime)"` ``` *说明:多个tag之间用分号(;)分割,可参考:`orm:"pk;auto"`*
标签:
Beego
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:
https://lilinchao.com/archives/2296.html
上一篇
07.Beego框架请求参数和响应数据
下一篇
09.Beego框架ORM高级查询
评论已关闭
栏目分类
随笔
2
Java
326
大数据
229
工具
31
其它
25
GO
47
NLP
4
标签云
排序
Redis
设计模式
Golang基础
Netty
Hbase
JavaSE
工具
Http
MyBatis
字符串
Spark
JVM
哈希表
Typora
ClickHouse
高并发
FastDFS
Beego
SQL练习题
Sentinel
线程池
Docker
查找
gorm
Linux
数据结构和算法
Azkaban
稀疏数组
数据结构
友情链接
申请
范明明
庄严博客
Mx
陶小桃Blog
虫洞
评论已关闭