李林超博客
首页
归档
留言
友链
动态
关于
归档
留言
友链
动态
关于
首页
GO
正文
08.Beego框架ORM介绍
Leefs
2022-08-04 AM
2549℃
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://www.lilinchao.com/archives/2296.html
上一篇
07.Beego框架请求参数和响应数据
下一篇
09.Beego框架ORM高级查询
取消回复
评论啦~
提交评论
栏目分类
随笔
2
Java
326
大数据
229
工具
31
其它
25
GO
47
标签云
数学
Docker
容器深入研究
线程池
微服务
数据结构和算法
字符串
Kibana
并发编程
Quartz
Spark RDD
SpringCloud
Yarn
MyBatisX
稀疏数组
栈
ajax
序列化和反序列化
Stream流
Nacos
国产数据库改造
Jquery
Jenkins
BurpSuite
工具
二叉树
Shiro
数据结构
Map
JVM
友情链接
申请
范明明
庄严博客
Mx
陶小桃Blog
虫洞