这是我参与「第三届青训营 -后端场」笔记创作活动的的第3篇笔记。
后端开发的工作中往往离不开与数据库打交道。我们可以用sql语句直接操作数据库,但更方便的做法是使用ORM(Object Relational Mapping)框架进行编码,这样可以更专注于业务逻辑的实现。Golang中使用最为广泛的便是GORM框架。
GORM框架是建立在database/sql包之上的。database/sql包中分别定义了对数据库的连接接口和操作接口,GORM可以差不多视作在其上再封装一层操作接口。
SQL语句的生成
GORM的db对象在执行每一个方法的时候,都会产生一个GORM STATEMENT对象,最后的方法则为Finisher Method,中间的则为Chain Method。
db.Where("id = ?", 1).Find(&user)
以上的Where则为Chain Method,Find则为Finisher Method,最终生成的对象被称为Select Statement。
插件的工作
在GORM STATEMENT对象执行时,都会根据其对象类型执行相应的Callbacks,插件需要注册到相应的对象类型的Callback中。比如Create类型Statement的Callback注册了以下的插件。
db.Callback().Create().Register("gorm:begin_transaction", BeginTransction)
db.Callback().Create().Register("gorm:before_create", BeforeCreate)
db.Callback().Create().Register("gorm:save_before_associations", SaveBeforeAssociations)
db.Callback().Create().Register("gorm:create", Create)
db.Callback().Create().Register("gorm:save_after_associations", SaveAfterAssociations)
db.Callback().Create().Register("gorm:after_create", AfterCreate)
db.Callback().Create().Register("gorm:commit_or_rollback_transaction", CommitOrRollback)
连接池
database/sql中实现了连接池,而GORM额外定义了DB Conn的接口,这么做在实现读写分离时,就可以根据GORM STATEMENT的类型决定使用哪一个DB Conn接口操作读数据库或写数据库。
优化
通过ORM框架操作数据库比使用原生sql多了将ORM语句解析成sql语句的消耗,可以通过开启statement预编译将使用过的sql主体的解析方式缓存起来加快执行速度。
全局模式:
db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{PrepareStmt: true})
会话模式:
tx := db.Session(&Session{PrepareStmt: true})
开启后要注意以传入参数的形式生成SQL语句,避免缓存达到上限。
此外,还可以在DSN中加入interpolateParams=false这一设置,默认为true是为了防止传统字符集下sql注入的问题,但现在使用UTF-8编码的情况下,已经不需要这一功能了,将其设为false性能更高。