在很多使用ORM工具的场景下,也可以使用go-sqlmock库 Mock数据库操作进行测试,今天这篇内容我就以 GORM 为例,讲解怎么给项目中的 ORM 数据库操作做单元测试。..., userId).Updates(updated).Error return } 接下来我们就用 go-sqlmock 工具给这几个 DAO 函数做一下 Mock 测试。...让sqlmock 使用 QueryMatcherEqual 匹配器,该匹配器把mock.ExpectQuery 和 mock.ExpectExec 的参数作为预期要执行的SQL语句跟实际要执行的SQL进行相等比较...这个SQL怎么获取呢?其实我们先随便写一个SQL,执行一次测试,在报错信息里就会告知CreateUser操作在写表时 GORM 真正要执行的 SQL 啦。...目前没有办法 Mock 测试 GORM 的UPDATE,除非用 GORM 的 Exec 方法直接执行要更新的SQL,不过那就失去使用ORM的意义了,所以这个先跳过,如果有这方面经验的大佬,可以在留言里指导一下
从上次发文说起 在上次发布的文章《在项目里怎么给 GORM 做单元测试》中对 ORM 的 Update 操作的测试中,因为 ORM 库每次做更新操作时,都会针对updated_at字段进行自动更新,导致我们在写...在很多使用ORM工具的场景下,也可以使用go-sqlmock库 Mock数据库操作进行测试,今天这篇内容我就以 GORM 为例,讲解怎么给项目中的 ORM 数据库操作做单元测试。..., userId).Updates(updated).Error return } 接下来我们就用 go-sqlmock 工具给这几个 DAO 函数做一下 Mock 测试。...让sqlmock 使用 QueryMatcherEqual 匹配器,该匹配器把mock.ExpectQuery 和 mock.ExpectExec 的参数作为预期要执行的SQL语句跟实际要执行的SQL进行相等比较...其实我们先随便写一个SQL,执行一次测试,在报错信息里就会告知CreateUser操作在写表时 GORM 真正要执行的 SQL 啦, 也可以通过GORM提供的Debug()方法获取到。
它可以模拟 SQL 查询、插入、更新等操作,并且可以验证 SQL 语句的执行情况,非常适合用于单元测试中。...二、安装 go get github.com/DATA-DOG/go-sqlmock 三、基本用法 使用 sqlmock 进行 MySQL 数据库集成测试的基本步骤如下: 创建模拟 DB 连接: import...mock 来替代真实的数据库连接 // db 可以传递给被测试的函数进行测试 } 设置模拟 SQL 查询和预期结果: // 模拟 SQL 查询并设置预期结果 rows := sqlmock.NewRows...然后,使用 gorm.DB 的 Create 方法将用户信息插入到数据库中。如果插入操作遇到唯一性约束错误(例如邮箱或手机号已存在),方法会返回一个特定的错误 ErrUserDuplicate。...提供了一个使用 GORM 进行数据库操作的 DAO 层,用于处理用户数据的创建。
2. sqlmock 简介在使用gorm等orm框架时,由于需要和数据库进行交互,并且CICD服务器在对代码检测的时候,往往也无法连接真正的数据库,因此编写单元测试,就会变得很困难。...go-sqlmock 本质是一个实现了 sql/driver 接口的 mock 库,它的设计目标是支持在测试中,模拟任何 sql driver 的行为,而不需要一个真正的数据库连接。...安装 go-sqlmockgo get github.com/DATA-DOG/go-sqlmock4. sqlmock实战首先我们模拟一下,在实际开发中会使用到gorm来对数据库查询操作。.../driver/mysql" "gorm.io/gorm" "github.com/DATA-DOG/go-sqlmock")// 初始化sqlmockfunc initTest() (*gorm.DB.../driver/mysql" "gorm.io/gorm" "github.com/DATA-DOG/go-sqlmock")func initTest() (*gorm.DB, sqlmock.Sqlmock
在TestMain方法中初始化go-sqlmock ,这样整个dao下的测试用例就都能使用它了,TestMain是在当前package下最先运行的一个函数,无论你运行哪个测试用例TestMain都会先被...= nil { panic(err) } // 把项目使用的DB连接换成sqlmock的DB连接 dbMasterConn, _ := gorm.Open(mysql.New(mysql.Config...SQL语句进行匹配,如果使用QueryMatcherEqual 作为匹配器的话,那么我们写预期SQL时就要写完整的SQL了。...(time.Time) return ok } 其实在使用SQL完全匹配模式时才必须用它,因为参数提供的Time.Now()做为UpdatedAt的时间,这与SQL执行时真正的UpdateAt时间是有很小的差异的...,这个时候我们可以提供AnyTime做为更新时间,这样sqlmock在做预期SQL和实际SQL的匹配时,遇到了AnyTime类型的预期值,就会按照这里指定的规则,判断字段值只要是time.Time 类型就能验证通过
`deleted_at` IS NULL AND ` = 1 4.2 更新单个列 当使用 Update 更新单个列时,你需要指定条件,否则会返回 ErrMissingWhereClause 错误,查看...,并返回 ErrMissingWhereClause 错误 对此,你必须加一些条件,或者使用原生 SQL,或者启用 AllowGlobalUpdate 模式,例如: db.Model(&User{})....result.Error) // 错误 五、Update高级选项(了解) 5.1 使用 SQL 表达式更新 GORM 允许使用 SQL 表达式更新列,例如: // user 的 ID 是 `1` db.First...Hook 和时间追踪 如果您想在更新时跳过 Hook 方法且不追踪更新时间,可以使用 UpdateColumn、UpdateColumns,其用法类似于 Update、Updates // 更新单个列..., "%灰太狼%") 阻止全局删除 如果在没有任何条件的情况下执行批量删除,GORM 不会执行该操作,并返回 ErrMissingWhereClause错误 对此,你必须加一些条件,或者使用原生 SQL
GORM 将生成一条 SQL 来插入所有数据,以返回所有主键值,并触发 Hook 方法。 当这些记录可以被分割成多个批次时,GORM会开启一个事务来处理它们。...当查询数据库时它添加了 LIMIT 1 条件,且没有找到记录时,它会返回 ErrRecordNotFound 错误// 获取第一条记录(主键升序)db.First(&user)// SELECT * FROM...`code` LIMIT 1根据主键检索如果主键是数字类型,您可以使用 内联条件 来检索对象。 当使用字符串时,需要额外的注意来避免SQL注入;查看 Security 部分来了解详情。...更新单个列当使用 Update 更新单列时,需要有一些条件,否则将会引起ErrMissingWhereClause 错误,查看 阻止全局更新 了解详情。...当使用 struct 更新时,默认情况下GORM 只会更新非零值的字段// 根据 `struct` 更新属性,只会更新非零值的字段db.Model(&user).Updates(User{Name: "
默认值 可以使用 GORM 标签 default 设置默认值,插入数据时,设置的默认值会被用于填充值为零值的字段。 需要注意的是,如果默认值本身是数据类型的零值,将不会被保存到数据库。...Update 方法更新单个列时,需要指定条件,否则会返回 ErrMissingWhereClause 的错误。..., 19).Update("age", 21) 当使用 Model 方法时,并且该对象的主键有值,该值会被用于更新条件。...{} 参数,需要注意的是,当使用 struct 作为参数时,GORM 只会更新字段的值不是字段类型的零值的字段。...如果希望执行全局更新,需要指定条件,或使用原生 SQL,或启用 AllowGlobalUpdate 模式。 更新的记录数和更新操作的错误 获取受影响的行数和更新操作的错误。
不过上面生成的函数没有校验返回的错误内容,如有需要可以自己稍微修改一下。 三、解决常见的依赖等问题 解决常见的依赖等问题目前有两种思路: 通过mock方式替换实际依赖,并通过打桩操作其返回内容。...通过本地启动一个模拟依赖环境,比如模拟redis服务等,然后直接访问模拟服务。...看到mock字眼大家大概也知道它是怎么使用的了,也是通过对执行sql语句打桩来完成测试。...*sql.DB,而是用到一些第三方 ORM 框架,那么需要想办法让这些框架使用我们的 mock db,比如对于 gorm 框架,可以这么配置: sqlDB, dbMock, err := sqlmock.New...&gorm.Config{}) 谈到gorm框架,那么问题来了,如果我不直接操作*sql.DB而是用的框架,但我不知道最后生成的sql是什么那该怎么办?
事务模板 // 开始事务 tx := db.Begin() // 在事务中做一些数据库操作(从这一点使用'tx',而不是'db') tx.Create(...) // ... // 发生错误时回滚事务...执行性能, GORM 支持自动的 Prepared Statement 缓冲,启用后,由 Gorm 生成的 SQL 或者 RAW SQL 都会进行预处理并缓存,Prepare Statement 可与数据库事务协同工作...results { // 批量处理数据 } // 批量更新数据,在使用 Save 处理批量数据时,会使用 Insert OnConflict DoNothing 模式...='hello', age=18 WHERE id IN (10, 11); 更新选定字段 如果您想要在更新时选定、忽略某些字段,您可以使用 Select、Omit // 使用 Map 进行 Select...在更新数据时,如果使用了 struct 来更新数据,默认只会更新非零值字段,如果使用map更新数据,则会更新全部字段,在使用 struct 更新时,也可以使用 Select 方法来选择想要更新的字段,
} 二、gorm 框架使用 Gorm 是 golang 的一个 orm 框架,它提供了对数据库操作的封装,使用起来相当便利。...所以如果对 mysql 使用操作不熟悉,建议也可以使用 gorm 框架操作 mysql 数据库。...(logger.Silent), //打印详细日志,可在代码测试时关闭,打开后为静默输出 }) 连接比较简单,直接调用 gorm.Open 传入数据库地址即可。...配置文件管理工具 viper[2] 从零开发区块链应用(二)--mysql 安装及数据库表的安装创建[3] 从零开发区块链应用(三)--mysql 初始化及 gorm 框架使用[4] 从零开发区块链应用...框架使用: https://learnblockchain.cn/article/3448 [5] 从零开发区块链应用(四)--自定义业务错误信息: https://learnblockchain.cn
Gorm 入门介绍与基本使用 目录 Gorm 入门介绍与基本使用 一、ORM简介 1.1 什么是ORM 1.2 使用ORM的好处 1.2.1 避免直接操作SQL语句 1.2.2 提高代码的可维护性 1.2.3...你可以根据实际情况调整这些参数。...你可以根据实际情况调整文件路径。...你需要根据实际情况替换这些值。...{}) 六、加入日志打印sql 6.1 打印日志 Gorm 有一个 默认 logger 实现,默认情况下,它会打印慢 SQL 和错误 Logger 接受的选项不多,您可以在初始化时自定义它,例如: newLogger
,我推荐的使用方式有2个特点: 尽可能简单,不要出现魔法变量,比如常量字符串 不要让框架强约束表结构的设计,也是为了后续迁移框架、甚至语言时成本更低 查询 中文文档链接 - https://gorm.io...其中,希望大家能重点看一下默认值问题: 我们固然可以通过在定义字段时,排除这些默认值的情况,如定义int类型字段时跳过0、从1开始。...但在实际的项目中,定义往往很难控制,我们不得不做一定的妥协,这部分hard code的成本也是可以接受的。 我们不能因为框架里的一些特性,过度地限制其余组件的使用。...db.Delete(&email) 3.使用GORM的思考 GORM是一个非常重量级的工具,尤其是*gorm.DB提供了大量的类似于Builder模式的方法,用来拼接SQL。...整个使用过程,对于一个不熟悉SQL语言的同学来说是很痛苦的,需要大量调试问题的时间;而对于熟悉SQL的朋友也会很疑惑,例如First等这种自定义命名的底层实现。
本文将以学生表、课程表、分数表的关联关系为核心场景,手把手演示Gorm的核心功能,帮助你快速掌握Gorm的使用精髓。...,重复执行相同SQL时提升性能展开代码语言:GoAI代码解释packagemainimport("gorm.io/driver/mysql""gorm.io/gorm""gorm.io/gorm/logger.../日志级别:Info(打印所有SQL)、Warn(警告+错误)、Error(仅错误)Colorful:true,//彩色打印},)//连接数据库并配置参数varerrerrordb,err=gorm.Open...`id`LIMIT1注意:如果查询无结果,Gorm会返回gorm.ErrRecordNotFound错误,可通过errors.Is判断:展开代码语言:GoAI代码解释import"errors"iferrors.Is...实际开发中建议结合官方文档,根据业务需求灵活调整配置和查询方式。
gorm库是go语言中一个非常强大的ORM(对象关系映射)库,它能够帮助我们很好的操作数据库和映射数据库表为go对象。在技术面试中,gorm的使用与设计理念也常作为面试题出现。...总而言之,gorm库实际上就是将SQL的所有语法规则代码化了,gorm库方法的调用过程就是写SQL的过程。...可以避免ErrRecordNotFound错误的额外判断。 当查询满足某条件的多个对象时使用Find,可以一次性查找出满足条件的所有记录。...true, }) 04、gorm常见问题讨论 4.1 为什么使用gorm创建对象时,时间为什么时对时错?...DryRun置为true时,实际就是在这两步中间插入了Return。在构建完成SQL语句后Return,在外部方法打印SQL语句。这就是DryRun功能的实现逻辑。
使用 ORM 组件,可以让开发者通过操作对象的方式完成对数据库的操作(读写),避免手动书写 SQL 和完成数据到对象的转换,让我们更方便的操作数据库。...理论上 ORM 可以让我们脱离 SQL,但实际上还是需要懂 SQL 才能更好地使用 ORM。 2.GORM 是什么 GORM 是一个流行的 Golang ORM 库。...Map Find/Create,使用 SQL 表达式、Context Valuer 进行 CRUD SQL 构建器,Upsert,锁,Optimizer/Index/Comment Hint,命名参数...go get -u gorm.io/driver/postgres go get -u gorm.io/driver/sqlserver 驱动包按照自己实际使用的 DB 选择即可。...Updates 方法支持 struct 和 map[string]interface{} 参数。当使用 struct 更新时,默认情况下,GORM 只会更新非零值的字段。
如果您遵循 GORM 的约定,您就可以少写的配置、代码。 如果约定不符合您的实际要求,GORM 允许你配置它们。...First 方法返回符合指定条件的首个记录值;值得注意的是,使用 First 方法进行查询时,如果查找不到数据会返回 ErrRecodeNotFound 错误。...可以使用 Find 查询多条记录,而 Find 方法在查询不到数据的时候并不会返回错误。...假设有一个电商网站数据库,涉及创建订单和配置库存两个操作,如果创建订单完成后配置库存失败了,那么理论上创建订单也应该被自动回滚以避免数据不一致,通过事务系统,我们可以将这两个操作划入一个事务,这样,当其中一个操作出现错误...如果您已经为模型定义了指定的方法,它会在创建、更新、查询、删除时自动被调用。如果任何回调返回错误,GORM 将停止后续的操作并回滚事务。
但结构体为零值时 sql 不执行 gorm.io 版本必须传两个参数,传结构体用Updates 4,where条件不一致 jinzhu版在调用 Where 时会创建一个副本,同一个 DB 在多行调用 Where...conditions, order by primary key gorm使用builder模式将SQL各种表达通过实现Build方法来生成对应字符串。...github.com/jinzhu/gorm/main.go // First find first record that match given conditions, order by primary...: 1,reflect导致的底层的性能不高(这点还能接受) 2,interface{}如果传入了不支持的复杂数据类型时,排查问题麻烦,往往要运行程序时才会报错 3,高频拼接重复SQL - 在一个程序运行过程中...,执行的SQL语句都比较固定,而变化的往往是参数;从GORM的实现来看,每次执行都需要重新拼接一次SQL语句,是有不小的优化空间的,比如引入一定的cache。
需要注意的是,当使用链式调用传入行内条件查询时,这些查询不会被传参给后续的中间方法。..., 42).Rows()//// SELECT COALESCE(age,'42') FROM users;Order使用 Order 从数据库查询记录时,当第二个参数设置为 true 时,将会覆盖之前的定义条件..., 3).Scan(&result)更新更新所有字段Save 方法在执行 SQL 更新操作时将包含所有字段,即使这些字段没有被修改。...: 0, Actived: false})更新选中的字段如果你在执行更新操作时只想更新或者忽略某些字段,可以使用 Select,Omit方法。...获取更新影响的记录数db.Model(User{}).Updates(User{Name: "hello", Age: 18}).RowsAffected带有表达式的 SQL 更新DB.Model(&product
好处很明显:写代码快多了,不用反复写SQL编译时就能发现错误,不用等到运行时才崩溃换数据库方便,MySQL换PostgreSQL基本不用改代码连接池、事务这些都帮你处理好了代码看起来更清晰,一眼就知道在干什么但也有坑...:多了一层抽象,性能肯定有损耗学习成本不低,每个ORM都有自己的语法复杂查询写起来别扭,有时候还不如直接写SQL出问题时不好调试,生成的SQL可能和你想的不一样1.3 Go 语言中的 ORM 选择Go生态里的...8.2.4 错误处理检查所有数据库操作的错误使用事务确保数据一致性合理处理记录不存在的情况记录和监控数据库错误8.3 GORM vs 原生 SQL 特性GORM原生 SQL开发效率高中等学习成本中等低性能良好优秀灵活性中等高类型安全高低代码维护容易中等...8.4 选择建议适合使用 GORM 的场景:快速开发原型和中小型项目团队对 SQL 不够熟悉需要跨数据库兼容性重视开发效率和代码维护性适合使用原生 SQL 的场景:对性能要求极高的项目需要复杂的 SQL...GORM 作为 Go 语言最流行的 ORM 框架,能够大幅提高开发效率,但也要注意在性能敏感的场景下合理选择使用方式。在实际项目中,建议根据具体需求在 ORM 和原生 SQL 之间找到平衡点。