【go语言】gorm 快速入门
一、orm
1.1 什么是 orm
ORM(对象关系映射,Object-Relational Mapping)是一种程序设计技术,用于在关系型数据库和面向对象编程语言之间进行转换和映射。ORM 允许开发者通过面向对象的方式与数据库交互,而无需直接编写复杂的 SQL 查询语句。
1.1.1 主要概念
-
对象与表的映射: ORM 将数据库中的表映射为程序中的对象,将表中的每一行映射为一个对象实例的属性。每个对象实例代表数据库中的一条记录。
-
自动生成 SQL 语句: ORM 允许开发者通过调用对象的方法来进行数据库操作(如增、删、改、查),ORM 会自动将这些操作转换为对应的 SQL 查询,减少了手动编写 SQL 语句的需要。
-
简化数据库操作: 使用 ORM 可以让开发者更多地专注于业务逻辑,而不是数据库的细节,使得数据库操作更加直观和高效。
1.1.2 orm 的基本操作
- 查询:通过对象属性或方法查询数据。
- 插入:将对象的属性值保存到数据库中。
- 更新:修改对象的属性并将变化同步到数据库。
- 删除:删除对象对应的数据库记录。
1.2 orm 的优缺点
1.2.1 优点
-
提高开发效率: ORM 通过封装数据库操作,减少了编写复杂 SQL 查询的需求,开发者可以专注于业务逻辑,而不必过多关注数据库的细节。
-
简化代码: ORM 通过将数据库表映射为对象,简化了增、删、改、查等操作。例如,插入数据时直接操作对象,而不需要编写 SQL 插入语句。
-
跨数据库支持: ORM 框架通常可以支持多种数据库(如 MySQL、PostgreSQL、SQLite 等),如果你需要切换数据库,通常只需修改配置,而不需要重写 SQL 查询代码,节省了迁移成本。
-
易于维护: 由于 ORM 将数据库操作与业务逻辑分离,代码更加模块化,数据库表的修改也可以通过修改对象模型来完成,减少了代码的重复性和冗余度。
-
防止 SQL 注入: ORM 框架通常会自动处理 SQL 注入问题,通过参数化查询来防止恶意注入,提高了应用程序的安全性。
-
易于测试: ORM 提供的对象模型可以更容易进行单元测试,因为可以直接对对象进行操作而不依赖于数据库本身。这对于开发和测试过程非常重要。
1.2.2 缺点
-
性能开销: ORM 通过映射机制进行操作,这可能会引入一定的性能开销。例如,对于复杂查询,ORM 可能会生成不够高效的 SQL 语句,导致性能下降。
-
不适合复杂查询: 对于复杂的多表连接、嵌套查询等 SQL 操作,ORM 可能不如手写 SQL 来得高效。在一些性能要求较高的应用中,手写 SQL 查询可能更加合适。
-
学习曲线: ORM 框架通常具有一定的学习曲线,尤其是对于不熟悉 ORM 框架的开发者。要理解 ORM 的工作原理以及如何处理复杂的数据库结构,可能需要花费额外的时间和精力。
-
抽象层问题: ORM 框架通常会对数据库结构进行抽象,有时这种抽象并不能完全符合业务需求。开发者可能需要绕过 ORM 框架,直接编写 SQL 来解决特定问题,从而失去了 ORM 的简化优势。
-
维护难度: 在一些非常复杂的项目中,ORM 自动生成的代码可能变得难以调试和维护,特别是当模型变得很庞大或涉及复杂的业务逻辑时,ORM 可能会变得不那么直观。
-
有限的功能支持: 虽然 ORM 可以处理常见的数据库操作,但它可能无法支持一些数据库特有的高级功能(如存储过程、触发器等)。这些特殊操作可能需要直接操作 SQL,无法通过 ORM 完全处理。
1.3 如何正确看待 orm 和 sql 的关系
ORM(对象关系映射)和 SQL(结构化查询语言)在数据库应用中是两个不同层次的概念。要正确看待它们的关系,可以从以下几个方面分析:
1.3.1 抽象层次的不同
- ORM:ORM 是一种抽象层,它的目标是将数据库的表和行映射成面向对象的模型,方便开发者用对象的方式进行操作。开发者不再直接编写 SQL,而是通过对对象的操作来实现数据库的增、删、改、查。
- SQL:SQL 是一种查询语言,用于直接与数据库进行交互。它描述了如何在数据库中插入、删除、更新和查询数据。SQL 更加接近底层,能够更精细地控制数据库的操作。
1.3.2 ORM 依赖于 SQL
尽管 ORM 提供了更高层次的抽象,但它最终仍然依赖于 SQL 来执行实际的数据库操作。ORM 框架将开发者的对象操作转化为 SQL 查询,然后发送给数据库。因此,ORM 本质上是在生成和执行 SQL,只是它为开发者隐藏了 SQL 的细节。
1.3.3 适用场景的差异
-
ORM:适用于大多数常规业务场景,尤其是对象和关系型数据库之间的映射较简单、SQL 查询不复杂的应用。ORM 带来的代码简化、可维护性和开发效率的提升是非常明显的。
-
SQL:适用于需要精确控制性能、进行复杂查询或处理大规模数据的场景。复杂的联接查询、多表操作、嵌套查询等情况,手写 SQL 通常能提供更高效的执行性能。而对于数据库的特殊功能(如存储过程、触发器等),ORM 可能无法完全胜任。
1.3.4 性能与灵活性
- ORM 的性能开销:ORM 在生成 SQL 时,可能不会为特定场景生成最优的查询。对于复杂查询,生成的 SQL 可能会不够高效,从而影响性能。在这种情况下,直接编写优化后的 SQL 查询会更加高效。
- SQL 的灵活性:SQL 给开发者提供了更大的灵活性,特别是在优化和调优查询时,开发者可以通过手写 SQL 完全控制查询的结构和执行计划。
1.3.5 开发效率与可维护性
- ORM 的开发效率:ORM 简化了开发过程,开发者可以避免手写大量的 SQL,特别是对数据库的 CRUD 操作(增、删、改、查)部分。它提供了更简洁、更直观的方式来与数据库交互,特别适用于标准化的数据库操作。
- SQL 的可维护性:尽管 ORM 能提升代码的可维护性,但手写 SQL 在处理特殊的查询逻辑或性能调优时,可能需要开发者对数据库有更深入的理解。随着项目的复杂性增加,手写 SQL 可以提供更高的可定制性和维护性,特别是在数据库结构或查询需求变化时。
1.3.6 灵活性和控制
- ORM 的限制:虽然 ORM 提供了自动化的数据库操作,但它的抽象有时可能不符合复杂的业务需求。比如,ORM 在执行一些复杂的关联查询或批量操作时,可能会引入额外的查询和性能开销。在这些情况下,手写 SQL 可以更加高效和灵活。
- SQL 的控制力:使用 SQL,开发者对查询的执行过程、性能优化和数据库的特殊操作有完全的控制权。手写 SQL 可以根据需要调整查询的执行顺序、索引使用等,从而在性能方面做到更精细的调优。
1.3.7 结合使用
在实际开发中,ORM 和 SQL 并不是对立的。许多情况下,开发者可以将它们结合起来使用:
- ORM 用于常见操作:对于常规的增、删、改、查等操作,ORM 可以提供快速的开发体验。
- SQL 用于复杂查询和优化:对于复杂的多表联接、性能敏感的查询、数据库的特殊功能,开发者可以直接编写 SQL,或者在 ORM 框架中直接嵌入 SQL 来满足需求。
1.3.8 总结
- ORM 是一种抽象层,旨在简化与数据库的交互,使开发者能够以面向对象的方式进行操作,适用于大多数简单的应用场景。
- SQL 是一种底层的查询语言,直接与数据库交互,提供了更高的灵活性、性能优化和控制权,适合复杂的查询和高性能要求的场景。
二、gorm 连接数据库
2.1 安装 GORM 包
首先,你需要安装GORM库。可以通过以下命令安装:
go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite # 如果你使用 SQLite
go get -u gorm.io/driver/mysql # 如果你使用 MySQL
go get -u gorm.io/driver/postgres # 如果你使用 PostgreSQL
2.2 编写连接代码
下面是一个简单的例子,展示如何连接MySQL数据库。你可以根据需要修改为其他类型的数据库连接。
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
"log"
)
func main() {
// 设置数据库连接字符串
dsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
// 连接数据库
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal("failed to connect to the database:", err)
}
log.Println("Database connection established successfully!")
// 你可以在这里执行数据库操作,比如迁移或CRUD操作
}
dsn
: 数据库连接字符串。user
和password
是你的MySQL用户名和密码,127.0.0.1:3306
是数据库地址和端口,dbname
是你要连接的数据库名称。gorm.Open()
: 用于连接数据库,第二个参数是数据库驱动。
- username:password:数据库的用户名和密码
- @protocol(address) :指定连接协议和数据库服务器的地址。
- /dbname:要连接的数据库名
注意:想要正确的处理
time.Time
,您需要带上parseTime
参数, (更多参数) 要支持完整的 UTF-8 编码,您需要将charset=utf8
更改为charset=utf8mb4
2.3 执行数据库迁移
在连接数据库后,你可以使用GORM的自动迁移功能创建数据库表。YourModel
是你定义的模型(struct)。
db.AutoMigrate(&YourModel{})
2.4 高级设置
MySQL 驱动程序提供了 一些高级配置 可以在初始化过程中使用,例如:
db, err := gorm.Open(mysql.New(mysql.Config{
DSN: "gorm:gorm@tcp(127.0.0.1:3306)/gorm?charset=utf8&parseTime=True&loc=Local", // DSN data source name
DefaultStringSize: 256, // string 类型字段的默认长度
DisableDatetimePrecision: true, // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
DontSupportRenameColumn: true, // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置
}), &gorm.Config{})
三、快速体验一下 CRUD
{
// Create
db.Create(&Product{Code: "D42", Price: 100})
// Read
var product Product
db.First(&product, 1) // 根据整型主键查找
db.First(&product, "code = ?", "D42") // 查找 code 字段值为 D42 的记录
// Update - 将 product 的 price 更新为 200
db.Model(&product).Update("Price", 200)
// Update - 更新多个字段
db.Model(&product).Updates(Product{Price: 200, Code: "F42"}) // 仅更新非零值字段
db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"})
// Delete - 删除 product
db.Delete(&product, 1)
}
在上述代码中,我们在执行完数据库迁移之后,就可以进行数据库的增删查改操作。