最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Golang使用sqlx操作sqlite3數(shù)據(jù)庫的完整指南

 更新時間:2025年12月31日 09:06:08   作者:李遲  
這篇文章主要為大家詳細(xì)介紹了Golang使用sqlx操作sqlite3數(shù)據(jù)庫的相關(guān)知識,本文會結(jié)合sqlx給出一些操作數(shù)據(jù)庫的示例,并將常見功能封裝了函數(shù)接口形式,希望對大家有所幫助

問題提出

幾年前,筆者寫了個golang工程,是和數(shù)據(jù)庫打交道的,當(dāng)時曾經(jīng)調(diào)查過xorm,但并不合適,于是使用較原始的方式實現(xiàn)功能,后來一直沿用。原始方式有一個好處,可以自由組合sql,達(dá)到不同的查詢目的。

最近又要和數(shù)據(jù)庫打交道,考慮到工程實用性,經(jīng)研究,決定使用sqlx將常見功能做成內(nèi)部接口形式。

實踐

設(shè)計說明

本文使用前面文章生成的結(jié)構(gòu)體作為演示數(shù)據(jù)表字段。為簡單起見,id不設(shè)置自增。另外,使用反射手段進(jìn)行建表、寫表、查表等操作。

結(jié)構(gòu)體定義:

type ResultData_t struct {
	Id        string `json:"id" db:"id"`
	Num       int    `json:"num" db:"num"`
	Etype     int    `json:"etype" db:"etype"`
	Timestamp string `json:"timestamp" db:"timestamp"`
	MCode     string `json:"mCode" db:"mCode"`
	MName     string `json:"mName" db:"mName"`
	Age       string `json:"age" db:"age"`
	Addr      string `json:"addr" db:"addr"`
	Mac       string `json:"mac" db:"mac"`
	Remark    string `json:"remark" db:"remark"`
}

變量定義:

var gTableName = "result_data"
var dbstr = "file:./database/result_data.db3?_journal_mode=WAL&_busy_timeout=5000&_foreign_keys=on"

引入第三方庫

庫如下:

"github.com/jmoiron/sqlx"
_ "modernc.org/sqlite"

要說明的是,本文采用"modernc.org/sqlite",這個庫實現(xiàn)了sqlite3,但不使用cgo,因此十分合適跨平臺,注意,該庫使用的數(shù)據(jù)庫驅(qū)動名為sqlite,而不是sqlite3。

筆者近年使用go作為主力語言,一個工程,如果不涉及底層庫,都會優(yōu)先考慮跨平臺性。比如,同一套代碼,在windows開發(fā)調(diào)試,再交叉編譯成linux或arm版本,基本不用開虛擬機(jī)了。

初始化數(shù)據(jù)庫

代碼如下,代碼會自動創(chuàng)建database/result_data.db3文件,默認(rèn)表為result_data。

type ResultWriter struct {
	db *sqlx.DB
}

func NewDB3Writer() *ResultWriter {
	return &ResultWriter{}
}

func getDB3File(dbname string) string {
	if !strings.HasPrefix(dbname, "file:") {
		return ""
	}
	filePart := dbname[5:] // 移除 "file:"
	parts := strings.Split(filePart, "?")
	if len(parts) == 0 {
		return ""
	}

	return com.GetFileDir(parts[0])
}

func (w *ResultWriter) CreateResultWriter(dbname string) (err error) {
	// SQLite 連接字符串(包含并發(fā)優(yōu)化參數(shù))
	// "file:./database/result_data.db3?_journal_mode=WAL&_busy_timeout=5000&_foreign_keys=on"

	// 確保目錄存在
	filePath := getDB3File(dbname)
	com.MkDir(filePath)

	dsn := dbname
	w.db, err = sqlx.Connect("sqlite", dsn)
	if err != nil {
		return err
	}

	w.db.SetMaxOpenConns(1) // SQLite 推薦單個連接
	w.db.SetMaxIdleConns(1)
	w.db.SetConnMaxLifetime(time.Hour)

	err = w.initTables()
	if err != nil {
		klog.Println("創(chuàng)建內(nèi)部數(shù)據(jù)庫失敗: ", err.Error())
	}

	return nil
}

func (w *ResultWriter) initTables() error {
	// w.initTableSimple()
	// 使用反射創(chuàng)建表
	err := dbutil.CreateTableFromStruct(w.db, gTableName, ResultData_t{}, "id")
	if err != nil {
		return fmt.Errorf("創(chuàng)建 result_data 表失敗: %v", err)
	}

	return nil
}

建表

在初始化的同時創(chuàng)建了數(shù)據(jù)表。可以調(diào)用initTableSimple,也可以調(diào)用CreateTableFromStruct。其中initTableSimple為直接指定字段創(chuàng)建表,實現(xiàn)函數(shù)如下:

// 直接指定字段創(chuàng)建表
func (w *ResultWriter) initTableSimple() error {
	createTableSQL := `
		CREATE TABLE IF NOT EXISTS result_data (
			id TEXT PRIMARY KEY,
			num INTEGER NOT NULL,
			etype INTEGER NOT NULL,
			timestamp TEXT NOT NULL,
			mCode TEXT NOT NULL,
			mName TEXT NOT NULL,
			age TEXT NOT NULL,
			addr TEXT NOT NULL,
			mac TEXT NOT NULL,
			remark TEXT
		)
	`

	_, err := w.db.Exec(createTableSQL)
	if err != nil {
		return err
	}

	// 創(chuàng)建常用索引
	indexes := []string{
		"CREATE INDEX IF NOT EXISTS idx_result_data_timestamp ON result_data(timestamp)",
	}

	for _, indexSQL := range indexes {
		_, err = w.db.Exec(indexSQL)
		if err != nil {
			return fmt.Errorf("創(chuàng)建索引失敗: %v", err)
		}
	}

	return nil
}

CreateTableFromStruct則使用結(jié)構(gòu)體建表,通用性強(qiáng)一些,實現(xiàn)如下:

func CreateTableFromStruct(db *sqlx.DB, tableName string, model interface{}, primaryKey string, indices ...string) error {
	if db == nil {
		return fmt.Errorf("數(shù)據(jù)庫連接為空")
	}

	var t reflect.Type
	if model == nil {
		return fmt.Errorf("model 參數(shù)不能為 nil")
	}

	v := reflect.ValueOf(model)
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
		t = v.Type()
	} else {
		t = reflect.TypeOf(model)
	}

	if t.Kind() != reflect.Struct {
		return fmt.Errorf("model 必須是結(jié)構(gòu)體")
	}

	var columns []string
	var hasPrimaryKey bool

	// 遍歷結(jié)構(gòu)體字段
	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)

		// 獲取字段名(優(yōu)先使用 db tag,其次使用字段名)
		columnName := field.Tag.Get("db")
		if columnName == "" || columnName == "-" {
			// 如果 db tag 為空或為 "-",跳過該字段
			continue
		}

		// 獲取字段類型
		fieldType := field.Type

		// 處理指針類型
		if fieldType.Kind() == reflect.Ptr {
			fieldType = fieldType.Elem()
		}

		// 根據(jù)字段類型確定 SQL 類型
		var sqlType string
		switch fieldType.Kind() {
		case reflect.String:
			sqlType = "TEXT"
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			sqlType = "INTEGER"
		case reflect.Float32, reflect.Float64:
			sqlType = "REAL"
		case reflect.Bool:
			sqlType = "INTEGER" // SQLite 用 0/1 表示布爾值
		case reflect.Struct:
			// 處理 time.Time 類型
			if fieldType.String() == "time.Time" {
				sqlType = "TEXT"
			} else {
				sqlType = "TEXT" // 其他結(jié)構(gòu)體序列化為 JSON 存儲
			}
		case reflect.Slice, reflect.Array, reflect.Map:
			// 數(shù)組/切片/映射序列化為 JSON 存儲
			sqlType = "TEXT"
		default:
			// 默認(rèn)使用 TEXT 類型
			sqlType = "TEXT"
		}

		// 構(gòu)建列定義
		columnDef := fmt.Sprintf("%s %s", columnName, sqlType)

		// 檢查是否是主鍵
		// isPrimaryKey := false
		if primaryKey != "" {
			// 使用指定的主鍵
			if columnName == primaryKey {
				columnDef += " PRIMARY KEY"
				// isPrimaryKey = true
				hasPrimaryKey = true
			}
		} else {
			// 自動判斷:如果字段名為 "id" 且沒有顯式指定主鍵
			if columnName == "id" && !hasPrimaryKey {
				columnDef += " PRIMARY KEY AUTOINCREMENT"
				// isPrimaryKey = true
				hasPrimaryKey = true
			}
		}

		// 檢查 NOT NULL 約束
		notNullTag := field.Tag.Get("dbNotNull")
		if notNullTag == "true" || notNullTag == "1" {
			columnDef += " NOT NULL"
		}

		// 檢查 UNIQUE 約束
		uniqueTag := field.Tag.Get("dbUnique")
		if uniqueTag == "true" || uniqueTag == "1" {
			columnDef += " UNIQUE"
		}

		// 添加 DEFAULT 值
		defaultTag := field.Tag.Get("dbDefault")
		if defaultTag != "" {
			columnDef += " DEFAULT " + defaultTag
		}

		columns = append(columns, columnDef)
	}

	if len(columns) == 0 {
		return fmt.Errorf("沒有找到有效的字段")
	}

	// 建表語句
	createTableSQL := fmt.Sprintf(`
		CREATE TABLE IF NOT EXISTS %s (
			%s
		)
	`, tableName, strings.Join(columns, ",\n\t\t"))

	// 執(zhí)行
	_, err := db.Exec(createTableSQL)
	if err != nil {
		return fmt.Errorf("創(chuàng)建表 %s 失敗: %v", tableName, err)
	}

	// fmt.Printf("debug 創(chuàng)建表語句:[%v]\n", createTableSQL)

	// 創(chuàng)建索引
	for _, field := range indices {
		if field != "" {
			indexSQL := fmt.Sprintf("CREATE INDEX IF NOT EXISTS idx_%s_%s ON %s(%s)",
				tableName, field, tableName, field)
			_, err = db.Exec(indexSQL)
			if err != nil {
				return fmt.Errorf("創(chuàng)建索引 %s 失敗: %v", field, err)
			}
		}
	}

	return nil
}

寫表

func InsertTable[T any](db *sqlx.DB, tableName string, model []T, skipid ...string) (int64, string, error) {
	if len(model) == 0 {
		return 0, "", nil
	}

	// 獲取第一個記錄的結(jié)構(gòu)信息
	t := reflect.TypeOf(model[0])
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}

	// 可指定過濾的字段名,有的庫可能會使用自增的id,因此要過濾
	getskip := func(id string) bool {
		for i := range skipid {
			if skipid[i] == id {
				return true
			}
		}
		return false
	}

	// 收集所有 db tag(排除 id 字段)
	var fieldNames []string
	var dbTags []string

	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		dbTag := field.Tag.Get("db")

		if dbTag != "" && dbTag != "-" && !getskip(dbTag) {
			fieldNames = append(fieldNames, field.Name)
			dbTags = append(dbTags, dbTag)
		}
	}

	// 構(gòu)建帶命名參數(shù)的 SQL
	var namedParams []string
	for _, tag := range dbTags {
		namedParams = append(namedParams, ":"+tag)
	}

	query := fmt.Sprintf(`
        INSERT INTO %s (%s)
        VALUES (%s)
    `, tableName,
		strings.Join(dbTags, ", "),
		strings.Join(namedParams, ", "))

	// 執(zhí)行批量插入
	result, err := db.NamedExec(query, model)
	if err != nil {
		return 0, query, fmt.Errorf("表 %s: %v", tableName, err)
	}

	// fmt.Printf("debug insert: [%v]\n", query)

	rows, err := result.RowsAffected()
	if err != nil {
		return int64(len(model)), query, nil // 有些數(shù)據(jù)庫可能不支持
	}

	return rows, query, nil
}

查表

查表同樣使用了反射的技術(shù),主要調(diào)用genSelectItem將結(jié)構(gòu)體各字段組成select語句。

比如:

SELECT id, num, etype, timestamp, mCode, mName, age, addr, mac, remark FROM result_data  WHERE id = 'id_8'

SELECT id, num, etype, timestamp, mCode, mName, age, addr, mac, remark FROM result_data

事實上,在結(jié)構(gòu)體ResultData_t定義時,就使用了db指定了各字段的名稱,如下:

Id        string `json:"id" db:"id"`
Num       int    `json:"num" db:"num"`

這也是genSelectItem可處理任意結(jié)構(gòu)體的原因,該函數(shù)見下文的實現(xiàn)。

查表分2類,一是單個查詢QueryOne,調(diào)用者知道只有一個結(jié)果時,可使用該函數(shù)。如果查詢多個,則使用QueryTable函數(shù)。

這2個函數(shù)實現(xiàn)如下:

func QueryOne[T any](db *sqlx.DB, tableName string, model T, where string, args ...interface{}) (*T, error) {
	sqlstr := genSelectItem(model, tableName, where)

	var result T
	err := db.Get(&result, sqlstr, args...)
	if err != nil {
		return nil, fmt.Errorf("表 %s: %v", tableName, err)
	}

	return &result, nil
}

func QueryTable[T any](db *sqlx.DB, tableName string, model T, where string) ([]T, string, error) {
	mysqlstr := fmt.Sprintf("SELECT * FROM %v %v", tableName, where)

	sqlstr := genSelectItem(model, tableName, where)

	var results []T
	err := db.Select(&results, sqlstr)
	if err != nil {
		return nil, mysqlstr, fmt.Errorf("表 %s: %v", tableName, err)
	}

	return results, mysqlstr, nil
}

接口工具函數(shù)集

本文所用的工具函數(shù)集如下:

package db

import (
	"fmt"
	"reflect"
	"strings"

	"github.com/jmoiron/sqlx"
)

func CreateTableFromStruct(db *sqlx.DB, tableName string, model interface{}, primaryKey string, indices ...string) error {
	if db == nil {
		return fmt.Errorf("數(shù)據(jù)庫連接為空")
	}

	var t reflect.Type
	if model == nil {
		return fmt.Errorf("model 參數(shù)不能為 nil")
	}

	v := reflect.ValueOf(model)
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
		t = v.Type()
	} else {
		t = reflect.TypeOf(model)
	}

	if t.Kind() != reflect.Struct {
		return fmt.Errorf("model 必須是結(jié)構(gòu)體")
	}

	var columns []string
	var hasPrimaryKey bool

	// 遍歷結(jié)構(gòu)體字段
	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)

		// 獲取字段名(優(yōu)先使用 db tag,其次使用字段名)
		columnName := field.Tag.Get("db")
		if columnName == "" || columnName == "-" {
			// 如果 db tag 為空或為 "-",跳過該字段
			continue
		}

		// 獲取字段類型
		fieldType := field.Type

		// 處理指針類型
		if fieldType.Kind() == reflect.Ptr {
			fieldType = fieldType.Elem()
		}

		// 根據(jù)字段類型確定 SQL 類型
		var sqlType string
		switch fieldType.Kind() {
		case reflect.String:
			sqlType = "TEXT"
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			sqlType = "INTEGER"
		case reflect.Float32, reflect.Float64:
			sqlType = "REAL"
		case reflect.Bool:
			sqlType = "INTEGER" // SQLite 用 0/1 表示布爾值
		case reflect.Struct:
			// 處理 time.Time 類型
			if fieldType.String() == "time.Time" {
				sqlType = "TEXT"
			} else {
				sqlType = "TEXT" // 其他結(jié)構(gòu)體序列化為 JSON 存儲
			}
		case reflect.Slice, reflect.Array, reflect.Map:
			// 數(shù)組/切片/映射序列化為 JSON 存儲
			sqlType = "TEXT"
		default:
			// 默認(rèn)使用 TEXT 類型
			sqlType = "TEXT"
		}

		// 構(gòu)建列定義
		columnDef := fmt.Sprintf("%s %s", columnName, sqlType)

		// 檢查是否是主鍵
		// isPrimaryKey := false
		if primaryKey != "" {
			// 使用指定的主鍵
			if columnName == primaryKey {
				columnDef += " PRIMARY KEY"
				// isPrimaryKey = true
				hasPrimaryKey = true
			}
		} else {
			// 自動判斷:如果字段名為 "id" 且沒有顯式指定主鍵
			if columnName == "id" && !hasPrimaryKey {
				columnDef += " PRIMARY KEY AUTOINCREMENT"
				// isPrimaryKey = true
				hasPrimaryKey = true
			}
		}

		// 檢查 NOT NULL 約束
		notNullTag := field.Tag.Get("dbNotNull")
		if notNullTag == "true" || notNullTag == "1" {
			columnDef += " NOT NULL"
		}

		// 檢查 UNIQUE 約束
		uniqueTag := field.Tag.Get("dbUnique")
		if uniqueTag == "true" || uniqueTag == "1" {
			columnDef += " UNIQUE"
		}

		// 添加 DEFAULT 值
		defaultTag := field.Tag.Get("dbDefault")
		if defaultTag != "" {
			columnDef += " DEFAULT " + defaultTag
		}

		columns = append(columns, columnDef)
	}

	if len(columns) == 0 {
		return fmt.Errorf("沒有找到有效的字段")
	}

	// 建表語句
	createTableSQL := fmt.Sprintf(`
		CREATE TABLE IF NOT EXISTS %s (
			%s
		)
	`, tableName, strings.Join(columns, ",\n\t\t"))

	// 執(zhí)行
	_, err := db.Exec(createTableSQL)
	if err != nil {
		return fmt.Errorf("創(chuàng)建表 %s 失敗: %v", tableName, err)
	}

	// fmt.Printf("debug 創(chuàng)建表語句:[%v]\n", createTableSQL)

	// 創(chuàng)建索引
	for _, field := range indices {
		if field != "" {
			indexSQL := fmt.Sprintf("CREATE INDEX IF NOT EXISTS idx_%s_%s ON %s(%s)",
				tableName, field, tableName, field)
			_, err = db.Exec(indexSQL)
			if err != nil {
				return fmt.Errorf("創(chuàng)建索引 %s 失敗: %v", field, err)
			}
		}
	}

	return nil
}

// 自動從結(jié)構(gòu)體生成SELECT字段列表
func genSelectItem(model interface{}, tableName string, where1 ...string) string {
	t := reflect.TypeOf(model)
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}

	var fields []string
	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		dbTag := field.Tag.Get("db")
		if dbTag != "" && dbTag != "-" {
			fields = append(fields, dbTag)
		}
	}

	where := ""
	if len(where1) > 0 {
		where = where1[0]
	}
	return fmt.Sprintf("SELECT %s FROM %s %s", strings.Join(fields, ", "), tableName, where)
}

///////////////////////////

func QueryOne[T any](db *sqlx.DB, tableName string, model T, where string, args ...interface{}) (*T, error) {
	sqlstr := genSelectItem(model, tableName, where)

	var result T
	err := db.Get(&result, sqlstr, args...)
	if err != nil {
		// if err == sql.ErrNoRows {
		// 	return nil, err // 沒有找到記錄,返回 nil
		// }
		return nil, fmt.Errorf("表 %s: %v", tableName, err)
	}

	return &result, nil
}

func QueryTable[T any](db *sqlx.DB, tableName string, model T, where string) ([]T, string, error) {
	// start := time.Now()
	// defer func() {
	// 	stats := db.Stats()
	// 	fmt.Printf("查詢耗時: %v, 等待連接數(shù)量: %d\n",
	// 		time.Since(start), stats.WaitCount)
	// }()

	mysqlstr := fmt.Sprintf("SELECT * FROM %v %v", tableName, where)

	sqlstr := genSelectItem(model, tableName, where)

	var results []T
	err := db.Select(&results, sqlstr)
	if err != nil {
		return nil, mysqlstr, fmt.Errorf("表 %s: %v", tableName, err)
	}

	return results, mysqlstr, nil
}

///////////////////

// BatchInsert 通用批量插入函數(shù)
func InsertTable[T any](db *sqlx.DB, tableName string, model []T, skipid ...string) (int64, string, error) {
	if len(model) == 0 {
		return 0, "", nil
	}

	// 獲取第一個記錄的結(jié)構(gòu)信息
	t := reflect.TypeOf(model[0])
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}

	// 可指定過濾的字段名,有的庫可能會使用自增的id,因此要過濾
	getskip := func(id string) bool {
		for i := range skipid {
			if skipid[i] == id {
				return true
			}
		}
		return false
	}

	// 收集所有 db tag(排除 id 字段)
	var fieldNames []string
	var dbTags []string

	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		dbTag := field.Tag.Get("db")

		if dbTag != "" && dbTag != "-" && !getskip(dbTag) {
			fieldNames = append(fieldNames, field.Name)
			dbTags = append(dbTags, dbTag)
		}
	}

	// 構(gòu)建帶命名參數(shù)的 SQL
	var namedParams []string
	for _, tag := range dbTags {
		namedParams = append(namedParams, ":"+tag)
	}

	query := fmt.Sprintf(`
        INSERT INTO %s (%s)
        VALUES (%s)
    `, tableName,
		strings.Join(dbTags, ", "),
		strings.Join(namedParams, ", "))

	// 執(zhí)行批量插入
	result, err := db.NamedExec(query, model)
	if err != nil {
		return 0, query, fmt.Errorf("表 %s: %v", tableName, err)
	}

	// fmt.Printf("debug insert: [%v]\n", query)

	rows, err := result.RowsAffected()
	if err != nil {
		return int64(len(model)), query, nil // 有些數(shù)據(jù)庫可能不支持
	}

	return rows, query, nil
}

// ////////////////
// QueryCount 查詢記錄數(shù)量
func QueryCount(db *sqlx.DB, tableName, where string, args ...interface{}) (int64, error) {
	sqlstr := fmt.Sprintf("SELECT COUNT(*) FROM %s", tableName)
	if where != "" {
		sqlstr += " WHERE " + where
	}

	var count int64
	err := db.Get(&count, sqlstr, args...)
	if err != nil {
		return 0, fmt.Errorf("表 %s: %v", tableName, err)
	}

	return count, nil
}

測試

建表打印信息:

debug 創(chuàng)建表語句:[
                CREATE TABLE IF NOT EXISTS result_data (
                        id TEXT PRIMARY KEY,
                num INTEGER,
                etype INTEGER,
                timestamp TEXT,
                mCode TEXT,
                mName TEXT,
                age TEXT,
                addr TEXT,
                mac TEXT,
                remark TEXT
                )
        ]

插入表打印信息:

debug insert: [
        INSERT INTO result_data (id, num, etype, timestamp, mCode, mName, age, addr, mac, remark)
        VALUES (:id, :num, :etype, :timestamp, :mCode, :mName, :age, :addr, :mac, :remark)
    ]

數(shù)據(jù)表內(nèi)容:

查表打印信息:

[2025-12-30 20:29:23 866] [INFO] query result:  id_8 2025-12-30T20:29:23
[2025-12-30 20:29:23 867] [INFO] query results:
[2025-12-30 20:29:23 868] [INFO] id_0 2025-12-30T20:29:23
[2025-12-30 20:29:23 868] [INFO] id_1 2025-12-30T20:29:23
[2025-12-30 20:29:23 868] [INFO] id_2 2025-12-30T20:29:23
[2025-12-30 20:29:23 869] [INFO] id_3 2025-12-30T20:29:23
[2025-12-30 20:29:23 869] [INFO] id_4 2025-12-30T20:29:23
[2025-12-30 20:29:23 869] [INFO] id_5 2025-12-30T20:29:23
[2025-12-30 20:29:23 870] [INFO] id_6 2025-12-30T20:29:23
[2025-12-30 20:29:23 871] [INFO] id_7 2025-12-30T20:29:23
[2025-12-30 20:29:23 871] [INFO] id_8 2025-12-30T20:29:23

有插入數(shù)據(jù)的寫表打印信息:

[2025-12-30 20:30:16 233] [INFO] insert sqlite failed:  表 result_data: constraint failed: UNIQUE constraint failed: result_data.id (1555)
[2025-12-30 20:30:16 234] [INFO] query result:  id_8 2025-12-30T20:29:23
[2025-12-30 20:30:16 234] [INFO] query results:
[2025-12-30 20:30:16 235] [INFO] id_0 2025-12-30T20:29:23
[2025-12-30 20:30:16 236] [INFO] id_1 2025-12-30T20:29:23
[2025-12-30 20:30:16 236] [INFO] id_2 2025-12-30T20:29:23
[2025-12-30 20:30:16 236] [INFO] id_3 2025-12-30T20:29:23
[2025-12-30 20:30:16 237] [INFO] id_4 2025-12-30T20:29:23
[2025-12-30 20:30:16 237] [INFO] id_5 2025-12-30T20:29:23
[2025-12-30 20:30:16 237] [INFO] id_6 2025-12-30T20:29:23
[2025-12-30 20:30:16 238] [INFO] id_7 2025-12-30T20:29:23
[2025-12-30 20:30:16 238] [INFO] id_8 2025-12-30T20:29:23

小結(jié)

本文通過示例工程展示了sqlx操作sqlite數(shù)據(jù)庫的方法,理論上只要數(shù)據(jù)庫驅(qū)動合適,sqlx可以對任意數(shù)據(jù)庫進(jìn)行操作,在代碼統(tǒng)一了方法,便于維護(hù)。

以上就是Golang使用sqlx操作sqlite3數(shù)據(jù)庫的完整指南的詳細(xì)內(nèi)容,更多關(guān)于Golang操作sqlite3的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go語言學(xué)習(xí)之鏈表的使用詳解

    Go語言學(xué)習(xí)之鏈表的使用詳解

    鏈表是一種物理存儲單元上非連續(xù)、非順序的存儲結(jié)構(gòu),數(shù)據(jù)元素的邏輯順序是通過鏈表中的指針鏈接次序?qū)崿F(xiàn)的。本文將詳細(xì)為大家介紹Go語言中鏈表的使用,感興趣的可以了解一下
    2022-04-04
  • golang中的空接口使用詳解

    golang中的空接口使用詳解

    這篇文章主要介紹了golang中的空接口使用,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • Go中nil比較的隱藏陷阱

    Go中nil比較的隱藏陷阱

    Go語言中,nil值比較因類型和上下文而異,相同類型nil相等,不同類型比較報錯,下面我們就來介紹一下Go中nil比較的隱藏陷阱,感興趣的可以了解一下
    2025-09-09
  • 實現(xiàn)像php一樣方便的go ORM數(shù)據(jù)庫操作示例詳解

    實現(xiàn)像php一樣方便的go ORM數(shù)據(jù)庫操作示例詳解

    這篇文章主要為大家介紹了實現(xiàn)像php一樣方便的go ORM數(shù)據(jù)庫操作示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • Go底層channel實現(xiàn)原理及示例詳解

    Go底層channel實現(xiàn)原理及示例詳解

    這篇文章主要介紹了Go底層channel實現(xiàn)原理及示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Go語言設(shè)計模式之實現(xiàn)觀察者模式解決代碼臃腫

    Go語言設(shè)計模式之實現(xiàn)觀察者模式解決代碼臃腫

    今天學(xué)習(xí)一下用?Go?實現(xiàn)觀察者模式,觀察者模式主要是用來實現(xiàn)事件驅(qū)動編程。事件驅(qū)動編程的應(yīng)用還是挺廣的,除了我們都知道的能夠用來解耦:用戶修改密碼后,給用戶發(fā)短信進(jìn)行風(fēng)險提示之類的典型場景,在微服務(wù)架構(gòu)實現(xiàn)最終一致性、實現(xiàn)事件源A?+?ES
    2022-08-08
  • Go語言的接口詳解

    Go語言的接口詳解

    這篇文章主要介紹了go語言的接口,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧,希望能夠給你帶來幫助
    2021-10-10
  • Go語言strconv包實現(xiàn)字符串和數(shù)值類型的相互轉(zhuǎn)換

    Go語言strconv包實現(xiàn)字符串和數(shù)值類型的相互轉(zhuǎn)換

    這篇文章主要介紹了Go語言strconv包實現(xiàn)字符串和數(shù)值類型的相互轉(zhuǎn)換,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • Golang連接并操作PostgreSQL數(shù)據(jù)庫基本操作

    Golang連接并操作PostgreSQL數(shù)據(jù)庫基本操作

    PostgreSQL是常見的免費的大型關(guān)系型數(shù)據(jù)庫,具有豐富的數(shù)據(jù)類型,也是軟件項目常用的數(shù)據(jù)庫之一,下面這篇文章主要給大家介紹了關(guān)于Golang連接并操作PostgreSQL數(shù)據(jù)庫基本操作的相關(guān)資料,需要的朋友可以參考下
    2022-09-09
  • 源碼剖析Golang如何fork一個進(jìn)程

    源碼剖析Golang如何fork一個進(jìn)程

    創(chuàng)建一個新進(jìn)程分為兩個步驟,一個是fork系統(tǒng)調(diào)用,一個是execve?系統(tǒng)調(diào)用,本文將從源碼的角度帶大家剖析一下Golang是如何fork一個進(jìn)程的
    2023-06-06

最新評論

时尚| 宿州市| 长兴县| 英吉沙县| 莱芜市| 安仁县| 宣汉县| 若尔盖县| 攀枝花市| 堆龙德庆县| 封开县| 万宁市| 云阳县| 隆昌县| 万安县| 稷山县| 堆龙德庆县| 湄潭县| 界首市| 温州市| 甘谷县| 夏津县| 肃北| 沙坪坝区| 齐齐哈尔市| 新晃| 新建县| 舟曲县| 上杭县| 阳原县| 巴塘县| 安义县| 湄潭县| 汝阳县| 红河县| 沁源县| 阿坝县| 丹凤县| 鄂托克旗| 桑植县| 安龙县|