基本 CURD

概述

在我们通过创建链接可以获得一个 sqlx.SqlConn,接着我们就可以完成各种数据库操作。 我们强烈建议使用 goctl model 自动生成 sql 代码,无需手动录入。

SqlConn 基本的方法如下

  1. type (
  2. // SqlConn only stands for raw connections, so Transact method can be called.
  3. SqlConn interface {
  4. Session
  5. // RawDB is for other ORM to operate with, use it with caution.
  6. // Notice: don't close it.
  7. RawDB() (*sql.DB, error)
  8. Transact(fn func(Session) error) error
  9. TransactCtx(ctx context.Context, fn func(context.Context, Session) error) error
  10. }
  11. // StmtSession interface represents a session that can be used to execute statements.
  12. StmtSession interface {
  13. Close() error
  14. Exec(args ...any) (sql.Result, error)
  15. ExecCtx(ctx context.Context, args ...any) (sql.Result, error)
  16. QueryRow(v any, args ...any) error
  17. QueryRowCtx(ctx context.Context, v any, args ...any) error
  18. QueryRowPartial(v any, args ...any) error
  19. QueryRowPartialCtx(ctx context.Context, v any, args ...any) error
  20. QueryRows(v any, args ...any) error
  21. QueryRowsCtx(ctx context.Context, v any, args ...any) error
  22. QueryRowsPartial(v any, args ...any) error
  23. QueryRowsPartialCtx(ctx context.Context, v any, args ...any) error
  24. }
  25. )

ExecCtx

我们提供了 ExecCtx 方法来完成各种增删改的操作。 简单示例:

  1. var conn sqlx.SqlConn // should be created by NewConn
  2. r, err := conn.ExecCtx(context.Background(), "delete from user where `id` = ?", 1)

一般我们用于输入的参数都是使用 ? 占位,接着通过 args 传入,这样可以有效防止 sql 注入等问题。

本个方法如果执行的sql 出现错误,也将会触发熔断。并且会有一定机制在服务恢复正常之后自动放行。详情见熔断。

QueryRowCtx

我们提供了 QueryRowCtx 进行普通的查询操作, 简单示例:

  1. type User struct {
  2. Id int64 `db:"id"`
  3. Name string `db:"name"`
  4. }
  5. var conn sqlx.SqlConn
  6. var u User
  7. err := conn.QueryRowCtx(context.Background(), &u, "select id, name from user where id = ? limit 1", 1)
  8. if err != nil {
  9. fmt.Println(err)
  10. return
  11. }
  12. _ = u

这样我们就可以从 user 表中查出 id 为 1 的数据。相关常见的错误可以见下方 常见错误

QueryRowPartialCtx

QueryRowPartialCtx 其实和 QueryRowCtx 都是提供用户查询数据使用的。 但是我们为了保证 User 中定义的所有字段都能过准确的被查询处理,所以设计 QueryRowCtx 的时候,强制校验查询出来的列需要与定义的 field 一致。 例如如下定义和Sql会报错。

  1. type User struct {
  2. Id int64 `db:"id"`
  3. Name string `db:"name"`
  4. Age int `db:"age"`
  5. }
  6. var conn sqlx.SqlConn
  7. var u User
  8. err := conn.QueryRowCtx(context.Background(), &u, "select id, name from user where id = ? limit 1", 1)
  9. if err != nil { // err == ErrNotMatchDestination
  10. fmt.Println(err) // not matching destination to scan
  11. return
  12. }

因为我们定义的 age ,并没有在 sql 中查询出来,会导致变量不一致的情况。如果用户确实有宽表,只需要查询部分字段,我们提供了 QueryRowPartialCtx 进行查询,这个方法即使查询的列不够也不会报错。

  1. type User struct {
  2. Id int64 `db:"id"`
  3. Name string `db:"name"`
  4. Age int `db:"age"`
  5. }
  6. var conn sqlx.SqlConn
  7. var u User
  8. err := conn.QueryRowPartialCtx(context.Background(), &u, "select id, name from user where id = ? limit 1", 1)
  9. if err != nil { // err == nil
  10. fmt.Println(err)
  11. return
  12. }
  13. _ = u // age is default 0

QueryRowsCtx

我们也提供了 QueryRowsCtx 进行批量查询的语句, 简单示例:

  1. type User struct {
  2. Id int64 `db:"id"`
  3. Name string `db:"name"`
  4. }
  5. var conn sqlx.SqlConn
  6. var users []*User
  7. err := conn.QueryRowsCtx(context.Background(), &users, "select id, name from user where name = ?", "dylan")
  8. if err != nil {
  9. fmt.Println(err)
  10. return
  11. }
  12. _ = users

这样我们就可以查询所有叫 dylan 的 users。注意当数据库中没有 user 的时候,我们是不会返回 ErrNotFound 的,这块和 QueryRowCtx 是不同的。

常见的错误

在我们执行 sql 语句中一些常见的错误如下:

  1. var (
  2. // ErrNotMatchDestination is an error that indicates not matching destination to scan.
  3. ErrNotMatchDestination = errors.New("not matching destination to scan")
  4. // ErrNotReadableValue is an error that indicates value is not addressable or interfaceable.
  5. ErrNotReadableValue = errors.New("value not addressable or interfaceable")
  6. // ErrNotSettable is an error that indicates the passed in variable is not settable.
  7. ErrNotSettable = errors.New("passed in variable is not settable")
  8. // ErrUnsupportedValueType is an error that indicates unsupported unmarshal type.
  9. ErrUnsupportedValueType = errors.New("unsupported unmarshal type")
  10. ErrNotFound = sql.ErrNoRows
  11. )

当然还有包括 sql 底层网络错误,这里不在列举。