上面这段代码就是一个简单的sqlx数据库事务示例,先通过db.Beginx开启事务,然后执行SQL语句,最后提交事务 。
如果想要更改默认的数据库隔离级别,可以使用另一个扩展方法:
tx, err = db.BeginTxx(context.Background(), &sql.TxOptions{Isolation: sql.LevelRepeatableRead})
sqlx干了什么通过上边的实战,基本上就可以使用sqlx进行开发了 。为了更好地使用sqlx,我们可以再了解下sqlx是怎么做到上边这些扩展的 。
Go的标准库中没有提供任何具体数据库的驱动,只是通过database/sql库定义了操作数据库的通用接口 。sqlx中也没有包含具体数据库的驱动,它只是封装了常用SQL的操作方法,让我们的SQL写起来更爽 。
MustXXXsqlx提供两个几个MustXXX方法 。
Must方法是为了简化错误处理而出现的,当开发者确定SQL操作不会返回错误的时候就可以使用Must方法,但是如果真的出现了未知错误的时候,这个方法内部会触发panic,开发者需要有一个兜底的方案来处理这个panic,比如使用recover 。
这里是MustExec的源码:
func MustExec(e Execer, query string, args ...interface{}) sql.Result {res, err := e.Exec(query, args...)if err != nil {panic(err)}return res}
NamedXXX对于需要传递SQL参数的方法,sqlx都扩展了命名参数的传参方式 。这让我们可以在更高的抽象层次处理数据库操作,而不必关心数据库操作的细节 。
这种方法的内部会解析我们的SQL语句,然后从传递的struct、map或者slice中提取命名参数对应的值,然后形成新的SQL语句和参数集合,再交给底层database/sql的方法去执行 。
这里摘抄一些代码:
func NamedExec(e Ext, query string, arg interface{}) (sql.Result, error) {q, args, err := bindNamedMApper(BindType(e.DriverName()), query, arg, mapperFor(e))if err != nil {return nil, err}return e.Exec(q, args...)}
NamedExec 内部调用了 bindNamedMapper,这个方法就是用于提取参数值的 。其内部分别对Map、Slice和Struct有不同的处理 。
func bindNamedMapper(bindType int, query string, arg interface{}, m *reflectx.Mapper) (string, []interface{}, error) {...switch {case k == reflect.Map && t.Key().Kind() == reflect.String:...return bindMap(bindType, query, m)case k == reflect.Array || k == reflect.Slice:return bindArray(bindType, query, arg, m)default:return bindStruct(bindType, query, arg, m)}}
以批量插入为例,我们的代码是这样写的:
insertPersonArray := []Person{{Name: "BOSIMA", City: "Wu Han", AddTime: time.Now(), UpdateTime: time.Now()},{Name: "BOSSMA", City: "Xi An", AddTime: time.Now(), UpdateTime: time.Now()},{Name: "BOMA", City: "Cheng Du", AddTime: time.Now(), UpdateTime: time.Now()},}insertPersonArrayResult, err := db.NamedExec("INSERT INTO Person (Name, City, AddTime, UpdateTime) VALUES(:Name, :City, :AddTime, :UpdateTime)", insertPersonArray)
经过bindNamedMapper处理后SQL语句和参数是这样的:
文章插图
文章插图
这里使用了反射,有些人可能会担心性能的问题,对于这个问题的常见处理方式就是缓存起来,sqlx也是这样做的 。
XXXScan这些Scan方法让数据行到对象的映射更为方便,sqlx提供了StructScan、SliceScan和MapScan,看名字就可以知道它们映射的数据结构 。而且在这些映射能力的基础上,sqlx提供了更为抽象的Get和Select方法 。
这些Scan内部还是调用了database/sql的Row.Scan方法 。
以StructScan为例,其使用方法为:
queryPerson := &Person{}err = row.StructScan(queryPerson)
经过sqlx处理后,调用Row.Scan的参数是:文章插图
推荐阅读
- Windows操作系统|Win11大更新就绪:微软详解重要新功能 CPU效率暴增、全新任务管理器
- 面试|魔兽怀旧服:曾经的毕业职业,wlk后期,操作不亚于“钢琴手”!
- 自媒体运营的“六大工具”操作更高效,收入扩大化
- 拿下域控后,我还是对大佬的操作念念不忘
- docker MySQL数据库的备份与还原,以及每天定时自动备份
- 如何在地图上添加你门店的位置,操作来了,很简单
- 计算机辅助设计母版的操作方法
- MySQL 8.0.27 zip 版本安装
- MySQL主从同步出现的诡异HA_ERR_KEY_NOT_FOUND故障
- 企业文化宣传如何操作