【goframe】ORM驱动开发


原文: https://www.bookstack.cn/read/GoFrame-1.13/database-gdb-driver.md

  • 驱动开发
    • 驱动接口
      • Driver接口
      • DB接口
    • 驱动注册
    • 新增第三方驱动
    • 自定义回调处理

https://godoc.org/github.com/gogf/gf/database/gdb#Driver

开发者自定义的驱动需要实现以下接口:

  1. // Driver is the interface for integrating sql drivers into package gdb.
  2. type Driver interface {
  3. // New creates and returns a database object for specified database server.
  4. New(core *Core, node *ConfigNode) (DB, error)
  5. }

其中的New方法用于根据Core数据库基础对象以及ConfigNode配置对象创建驱动对应的数据库操作对象,需要注意的是,返回的数据库对象需要实现DB接口。而数据库基础对象Core已经实现了DB接口,因此开发者只需要”继承”Core对象,然后根据需要覆盖对应的接口实现方法即可。

https://godoc.org/github.com/gogf/gf/database/gdb#DB

DB接口是数据库操作的核心接口,这里主要对接口的几个重要方法做说明:

  1. Open方法用于创建特定的数据库连接对象,返回的是标准库的*sql.DB通用数据库对象。
  2. Do*系列方法的第一个参数linkLink接口对象,该对象在master-slave模式下可能是一个主节点对象,也可能是从节点对象,因此如果在继承的驱动对象实现中使用该link参数时,注意当前的运行模式。slave节点在大部分的数据库主从模式中往往是不可写的。
  3. HandleSqlBeforeCommit方法将会在每一条SQL提交给数据库服务端执行时被调用做一些提交前的回调处理。
  4. 其他接口方法详见接口文档或者源码文件。

https://github.com/gogf/gf/blob/master/database/gdb/gdb_driver_mysql.go
  • https://github.com/gogf/gf/blob/master/database/gdb/gdb_driver_mssql.go
  • https://github.com/gogf/gf/blob/master/database/gdb/gdb_driver_pgsql.go
  • https://github.com/gogf/gf/blob/master/database/gdb/gdb_driver_oracle.go
  • https://github.com/gogf/gf/blob/master/database/gdb/gdb_driver_sqlite.go
  • 更多: https://github.com/gogf/gf/blob/master/database/gdb
  • 自定义回调处理

    我们来看一个自定义回调处理的示例,我们需要将所有执行的SQL语句记录到monitor表中,以方便于进行SQL审计。

    为简化示例编写,我们这里实现了一个自定义的MySQL驱动,该驱动继承于gdb模块中已经实现的DriverMysql,并按照需要修改覆盖相应的接口方法。由于所有的SQL语句执行必定会通过DoQuery或者DoExec接口,因此我们在自定义的驱动中实现并覆盖这两个接口方法即可。

    1. package driver
    2. import (
    3. "database/sql"
    4. "github.com/gogf/gf/database/gdb"
    5. "github.com/gogf/gf/frame/g"
    6. "github.com/gogf/gf/os/gtime"
    7. )
    8. // MyDriver is a custom database driver, which is used for testing only.
    9. // For simplifying the unit testing case purpose, MyDriver struct inherits the mysql driver
    10. // gdb.DriverMysql and overwrites its functions DoQuery and DoExec.
    11. // So if there's any sql execution, it goes through MyDriver.DoQuery/MyDriver.DoExec firstly
    12. // and then gdb.DriverMysql.DoQuery/gdb.DriverMysql.DoExec.
    13. // You can call it sql "HOOK" or "HiJack" as your will.
    14. type MyDriver struct {
    15. *gdb.DriverMysql
    16. }
    17. func init() {
    18. // It here registers my custom driver in package initialization function "init".
    19. // You can later use this type in the database configuration.
    20. if err := gdb.Register("MyDriver", &MyDriver{}); err != nil {
    21. panic(err)
    22. }
    23. }
    24. // New creates and returns a database object for mysql.
    25. // It implements the interface of gdb.Driver for extra database driver installation.
    26. func (d *MyDriver) New(core *gdb.Core, node *gdb.ConfigNode) (gdb.DB, error) {
    27. return &MyDriver{
    28. &gdb.DriverMysql{
    29. Core: core,
    30. },
    31. }, nil
    32. }
    33. // DoQuery commits the sql string and its arguments to underlying driver
    34. // through given link object and returns the execution result.
    35. func (d *MyDriver) DoQuery(link gdb.Link, sql string, args ...interface{}) (rows *sql.Rows, err error) {
    36. tsMilli := gtime.TimestampMilli()
    37. rows, err = d.DriverMysql.DoQuery(link, sql, args...)
    38. if _, err := d.DriverMysql.InsertIgnore("monitor", g.Map{
    39. "sql": gdb.FormatSqlWithArgs(sql, args),
    40. "cost": gtime.TimestampMilli() - tsMilli,
    41. "time": gtime.Now(),
    42. "error": err.Error(),
    43. }); err != nil {
    44. panic(err)
    45. }
    46. return
    47. }
    48. // DoExec commits the query string and its arguments to underlying driver
    49. // through given link object and returns the execution result.
    50. func (d *MyDriver) DoExec(link gdb.Link, sql string, args ...interface{}) (result sql.Result, err error) {
    51. tsMilli := gtime.TimestampMilli()
    52. result, err = d.DriverMysql.DoExec(link, sql, args...)
    53. if _, err := d.DriverMysql.InsertIgnore("monitor", g.Map{
    54. "sql": gdb.FormatSqlWithArgs(sql, args),
    55. "cost": gtime.TimestampMilli() - tsMilli,
    56. "time": gtime.Now(),
    57. "error": err.Error(),
    58. }); err != nil {
    59. panic(err)
    60. }
    61. return
    62. }

    我们看到,这里在包初始化方法init中使用了gdb.Register("MyDriver", &MyDriver{})来注册了了一个自定义名称的驱动。我们也可以通过gdb.Register("mysql", &MyDriver{})来覆盖已有的框架mysql驱动为自己的驱动。

    驱动名称mysql为框架默认的DriverMysql驱动的名称。

    由于这里我们使用了一个新的驱动名称MyDriver,因此在gdb配置中的type数据库类型时,需要填写该驱动名称。以下是一个使用配置的示例:

    1. [database]
    2. type = "MyDriver"
    3. link = "root:12345678@tcp(127.0.0.1:3306)/test"