Описание типа DBStats database/sql
Categories:
type DBStats
type DBStats struct {
MaxOpenConnections int // Максимальное количество открытых соединений с базой данных.
// Состояние пула
OpenConnections int // Количество установленных соединений, как используемых, так и простаивающих.
InUse int // Количество соединений, используемых в данный момент.
Idle int // Количество простаивающих соединений.
// Счетчики
WaitCount int64 // Общее количество ожидающих соединений.
WaitDuration time.Duration // Общее время, заблокированное в ожидании нового соединения.
MaxIdleClosed int64 // Общее количество соединений, закрытых из-за SetMaxIdleConns.
MaxIdleTimeClosed int64 // Общее количество соединений, закрытых из-за SetConnMaxIdleTime.
MaxLifetimeClosed int64 // Общее количество соединений, закрытых из-за SetConnMaxLifetime.
}
DBStats содержит статистику базы данных.
type IsolationLevel
type IsolationLevel int
IsolationLevel - это уровень изоляции транзакции, используемый в TxOptions.
const (
LevelDefault IsolationLevel = iota
LevelReadUncommitted
LevelReadCommitted
LevelWriteCommitted
LevelRepeatableRead
LevelSnapshot
LevelSerializable
LevelLinearizable
)
Различные уровни изоляции, которые драйверы могут поддерживать в DB.BeginTx. Если драйвер не поддерживает заданный уровень изоляции, может быть возвращена ошибка.
См. https://en.wikipedia.org/wiki/Isolation_(database_systems)#Isolation_levels.
func (IsolationLevel) String
func (i IsolationLevel) String() string
String возвращает имя уровня изоляции транзакции.
type NamedArg
type NamedArg struct {
// Name - имя параметра-заместителя.
//
// Если пусто, то будет использоваться
// порядковая позиция в списке аргументов.
//
// Имя не должно содержать префикса символа.
Name string
// Value - это значение параметра.
// Ему могут быть присвоены те же типы значений, что и аргументам запроса
//.
Value any
// содержит отфильтрованные или неэкспонированные поля
}
NamedArg - это именованный аргумент. Значения NamedArg могут использоваться в качестве аргументов DB.Query или DB.Exec и связываться с соответствующим именованным параметром в операторе SQL.
Для более краткого способа создания значений NamedArg см. функцию Named.
func Named
func Named(name string, value any) NamedArg
Named предоставляет более лаконичный способ создания значений NamedArg.
Пример
db.ExecContext(ctx, `
delete from Invoice
where
TimeCreated < @end
and TimeCreated >= @start;`,
sql.Named("start", startTime),
sql.Named("end", endTime),
)
type Null
type Null[T any] struct {
V T
Valid bool
}
Null представляет значение, которое может быть нулевым. Null реализует интерфейс Scanner, поэтому его можно использовать в качестве места сканирования:
var s Null[string]
err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&s)
...
if s.Valid {
// используем s.V
} else {
// NULL значение
}
T должен быть одним из типов, принимаемых driver.Value.
func (*Null[T]) Scan
func (n *Null[T]) Scan(value any) error
func (Null[T]) Value
func (n Null[T]) Value() (driver.Value, error)
type NullBool ¶
type NullBool struct {
Bool bool
Valid bool // Valid is true if Bool is not NULL
}
NullBool представляет bool, который может быть нулевым. NullBool реализует интерфейс Scanner, поэтому его можно использовать в качестве места сканирования, аналогично NullString.
func (*NullBool) Scan
func (n *NullBool) Scan(value any) error
Scan реализует интерфейс Scanner.
func (NullBool) Value
func (n NullBool) Value() (driver.Value, error)
Value реализует интерфейс driver.Valuer.
type NullByte
type NullByte struct {
Byte byte
Valid bool // Valid is true if Byte is not NULL
}
NullByte представляет байт, который может быть нулевым. NullByte реализует интерфейс Scanner, поэтому его можно использовать в качестве места сканирования, аналогично NullString.
func (*NullByte) Scan
func (n *NullByte) Scan(value any) error
Scan реализует интерфейс Scanner.
func (NullByte) Value
func (n NullByte) Value() (driver.Value, error)
Value реализует интерфейс driver.Valuer.
type NullFloat64 ¶
type NullFloat64 struct {
Float64 float64
Valid bool // Valid is true if Float64 is not NULL
}
NullFloat64 представляет float64, который может быть нулевым. NullFloat64 реализует интерфейс Scanner, поэтому его можно использовать в качестве места сканирования, аналогично NullString.
func (*NullFloat64) Scan ¶
func (n *NullFloat64) Scan(value any) error
Scan реализует интерфейс Scanner.
func (NullFloat64) Value ¶
func (n NullFloat64) Value() (driver.Value, error)
Value реализует интерфейс driver.Valuer.
type NullInt16
type NullInt16 struct {
Int16 int16
Valid bool // Valid is true if Int16 is not NULL
}
NullInt16 представляет int16, который может быть нулевым. NullInt16 реализует интерфейс Scanner, поэтому его можно использовать в качестве места сканирования, аналогично NullString.
func (*NullInt16) Scan
func (n *NullInt16) Scan(value any) error
Scan реализует интерфейс Scanner.
func (NullInt16) Value
func (n NullInt16) Value() (driver.Value, error)
Value реализует интерфейс driver.Valuer.
type NullInt32
type NullInt32 struct {
Int32 int32
Valid bool // Valid is true if Int32 is not NULL
}
NullInt32 представляет int32, который может быть нулевым. NullInt32 реализует интерфейс Scanner, поэтому его можно использовать в качестве места сканирования, аналогично NullString.
func (*NullInt32) Scan
func (n *NullInt32) Scan(value any) error
Scan реализует интерфейс Scanner.
func (NullInt32) Value
func (n NullInt32) Value() (driver.Value, error)
Value реализует интерфейс driver.Valuer.
type NullInt64
type NullInt64 struct {
Int64 int64
Valid bool // Valid is true if Int64 is not NULL
}
NullInt64 представляет int64, который может быть нулевым. NullInt64 реализует интерфейс Scanner, поэтому его можно использовать в качестве места сканирования, аналогично NullString.
func (*NullInt64) Scan
func (n *NullInt64) Scan(value any) error
Scan реализует интерфейс Scanner.
func (NullInt64) Value
func (n NullInt64) Value() (driver.Value, error)
Value реализует интерфейс driver.Valuer.
type NullString
type NullString struct {
String string
Valid bool // Valid is true if String is not NULL
}
NullString представляет строку, которая может быть нулевой. NullString реализует интерфейс Scanner, поэтому его можно использовать в качестве места сканирования:
var s NullString
err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&s)
...
if s.Valid {
// использовать s.String
} else {
// NULL значение
}
func (*NullString) Scan
func (ns *NullString) Scan(value any) error
Scan реализует интерфейс Scanner.
func (NullString) Value
func (ns NullString) Value() (driver.Value, error)
Value реализует интерфейс driver.Valuer.
type NullTime
type NullTime struct {
Time.Time
Valid bool // Valid is true if Time is not NULL
}
NullTime представляет время time.Time, которое может быть нулевым. NullTime реализует интерфейс Scanner, поэтому его можно использовать в качестве места сканирования, аналогично NullString.
func (*NullTime) Scan
func (n *NullTime) Scan(value any) error
Scan реализует интерфейс Scanner.
func (NullTime) Value
func (n NullTime) Value() (driver.Value, error)
Value реализует интерфейс driver.Valuer.
Практическое использование Null-типов в Go
Null-типы (NullString
, NullInt64
, NullTime
и др.) нужны для работы с NULL-значениями из базы данных. Разберём на реальных примерах.
Интерфейсы
- Scanner - позволяет сканировать (читать) значение из БД
- driver.Valuer - позволяет преобразовывать значение для записи в БД
Полный пример с NullString и NullTime
Пример
package main
import (
"database/sql"
"log"
"time"
_ "github.com/go-sql-driver/mysql"
)
type UserProfile struct {
ID int64
Name sql.NullString
Bio sql.NullString
DeletedAt sql.NullTime
}
func main() {
db, err := sql.Open("mysql", "user:password@/dbname")
if err != nil {
log.Fatal(err)
}
defer db.Close()
// 1. Запись данных с NULL-значениями
profile := UserProfile{
Name: sql.NullString{String: "Иван Иванов", Valid: true},
Bio: sql.NullString{}, // NULL
DeletedAt: sql.NullTime{Time: time.Now(), Valid: false}, // Будет записан как NULL
}
_, err = db.Exec(
"INSERT INTO users (name, bio, deleted_at) VALUES (?, ?, ?)",
profile.Name,
profile.Bio,
profile.DeletedAt,
)
if err != nil {
log.Fatal(err)
}
// 2. Чтение данных с возможными NULL-значениями
var user UserProfile
err = db.QueryRow(`
SELECT id, name, bio, deleted_at
FROM users
WHERE id = ?
`, 1).Scan(
&user.ID,
&user.Name,
&user.Bio,
&user.DeletedAt,
)
if err != nil {
log.Fatal(err)
}
// 3. Обработка NULL-значений
log.Println("ID:", user.ID)
if user.Name.Valid {
log.Println("Name:", user.Name.String)
} else {
log.Println("Name not set")
}
if user.Bio.Valid {
log.Println("Bio:", user.Bio.String)
} else {
log.Println("Bio not set")
}
if user.DeletedAt.Valid {
log.Println("Deleted at:", user.DeletedAt.Time)
} else {
log.Println("Not deleted")
}
}
Как работают Null-типы?
1. Scan
(чтение из БД)
Пример
func (ns *NullString) Scan(value interface{}) error {
if value == nil {
ns.String, ns.Valid = "", false
return nil
}
ns.Valid = true
return convertAssign(&ns.String, value)
}
2. Value
(запись в БД)
Пример
func (ns NullString) Value() (driver.Value, error) {
if !ns.Valid {
return nil, nil
}
return ns.String, nil
}
Пример с пользовательским Null-типом
Создадим свой NullStatus
для enum-поля:
Пример
type NullStatus struct {
Status string
Valid bool
}
func (ns *NullStatus) Scan(value interface{}) error {
if value == nil {
ns.Status, ns.Valid = "", false
return nil
}
ns.Valid = true
switch v := value.(type) {
case []byte:
ns.Status = string(v)
case string:
ns.Status = v
default:
return fmt.Errorf("unsupported type: %T", value)
}
return nil
}
func (ns NullStatus) Value() (driver.Value, error) {
if !ns.Valid {
return nil, nil
}
return ns.Status, nil
}
Когда использовать Null-типы?
- Когда поле в БД может быть NULL
- Когда нужно отличать “нулевое значение” от “неустановленного”
- При работе с опциональными полями
Альтернативы
В новых версиях Go можно использовать указатели:
Пример
var name *string
err := db.QueryRow("SELECT name FROM users WHERE id = 1").Scan(&name)
if name != nil {
// есть значение
}
Но Null-типы предоставляют более удобный интерфейс и явный флаг Valid
.