需要注意,框架SQL捕获的原理是,任何SQL操作生成的SQL语句模板加上SQL执行参数,在被提交给底层数据库引擎前会被框架拦截,并通过框架组件自动格式化生成可供人工阅读的字符串,仅供参考和调试,并不是完整提交给底层数据库引擎的SQL语句。捕获的SQL语句和ORM组件开启调试模式后输出的SQL语句是相同的,它们都由相同组件生成。

CatchSQL

我们可以使用gdb.CatchSQL方法来捕获指定范围内执行的SQL列表。该方法的定义如下:

  1. // CatchSQL catches and returns all sql statements that are EXECUTED in given closure function.
  2. // Be caution that, all the following sql statements should use the context object passing by function `f`.
  3. func CatchSQL(ctx context.Context, f func(ctx context.Context) error) (sqlArray []string, err error)

可以看到,该方法通过一个闭包函数来执行SQL语句,在闭包函数执行的所有SQL操作都将被记录并作为[]string类型。这里需要注意的是,闭包中执行的SQL操作都应当传递ctx上下文对象,否则SQL操作对应的语句无法记录。使用示例:

user.sql

  1. CREATE TABLE `user` (
  2. `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  3. `passport` varchar(45) NULL,
  4. `password` char(32) NULL,
  5. `nickname` varchar(45) NULL,
  6. `create_time` timestamp(6) NULL,
  7. PRIMARY KEY (id)
  8. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

main.go

  1. package main
  2. import (
  3. "context"
  4. _ "github.com/gogf/gf/contrib/drivers/mysql/v2"
  5. "github.com/gogf/gf/v2/database/gdb"
  6. "github.com/gogf/gf/v2/frame/g"
  7. "github.com/gogf/gf/v2/os/gctx"
  8. "github.com/gogf/gf/v2/os/gtime"
  9. )
  10. type User struct {
  11. Id int
  12. Passport string
  13. Password string
  14. Nickname string
  15. CreateTime *gtime.Time
  16. }
  17. func initUser(ctx context.Context) error {
  18. _, err := g.Model("user").Ctx(ctx).Data(User{
  19. Id: 1,
  20. Passport: "john",
  21. Password: "12345678",
  22. Nickname: "John",
  23. }).Insert()
  24. return err
  25. }
  26. func main() {
  27. var ctx = gctx.New()
  28. sqlArray, err := gdb.CatchSQL(ctx, func(ctx context.Context) error {
  29. return initUser(ctx)
  30. })
  31. if err != nil {
  32. panic(err)
  33. }
  34. g.Dump(sqlArray)
  35. }

执行后,终端输出:

  1. [
  2. "SHOW FULL COLUMNS FROM `user`",
  3. "INSERT INTO `user`(`id`,`passport`,`password`,`nickname`,`created_at`,`updated_at`) VALUES(1,'john','12345678','John','2023-12-19 21:43:57','2023-12-19 21:43:57') ",
  4. ]

ToSQL

我们可以通过gdb.ToSQL来将给定的SQL操作转换为SQL语句,并不真正提交执行。该方法的定义如下:

  1. // ToSQL formats and returns the last one of sql statements in given closure function
  2. // WITHOUT TRULY EXECUTING IT.
  3. // Be caution that, all the following sql statements should use the context object passing by function `f`.
  4. func ToSQL(ctx context.Context, f func(ctx context.Context) error) (sql string, err error)

可以看到,该方法通过一个闭包函数来预估SQL语句,在闭包函数中的所有SQL操作都将被预估,但只会返回最后一条SQL语句作为string类型返回。这里需要注意的是,闭包中的SQL操作都应当传递ctx上下文对象,否则SQL操作对应的语句无法记录。使用示例:

user.sql

  1. CREATE TABLE `user` (
  2. `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  3. `passport` varchar(45) NULL,
  4. `password` char(32) NULL,
  5. `nickname` varchar(45) NULL,
  6. `create_time` timestamp(6) NULL,
  7. PRIMARY KEY (id)
  8. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

main.go

  1. package main
  2. import (
  3. "context"
  4. _ "github.com/gogf/gf/contrib/drivers/mysql/v2"
  5. "github.com/gogf/gf/v2/database/gdb"
  6. "github.com/gogf/gf/v2/frame/g"
  7. "github.com/gogf/gf/v2/os/gctx"
  8. "github.com/gogf/gf/v2/os/gtime"
  9. )
  10. type User struct {
  11. Id int
  12. Passport string
  13. Password string
  14. Nickname string
  15. CreateTime *gtime.Time
  16. }
  17. func initUser(ctx context.Context) error {
  18. _, err := g.Model("user").Ctx(ctx).Data(User{
  19. Id: 1,
  20. Passport: "john",
  21. Password: "12345678",
  22. Nickname: "John",
  23. }).Insert()
  24. return err
  25. }
  26. func main() {
  27. var ctx = gctx.New()
  28. sql, err := gdb.ToSQL(ctx, func(ctx context.Context) error {
  29. return initUser(ctx)
  30. })
  31. if err != nil {
  32. panic(err)
  33. }
  34. g.Dump(sql)
  35. }

执行后,终端输出:

  1. "INSERT INTO `user`(`id`,`passport`,`password`,`nickname`,`created_at`,`updated_at`) VALUES(1,'john','12345678','John','2023-12-19 21:49:21','2023-12-19 21:49:21') "