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

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

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

問(wèn)題提出

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

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

實(shí)踐

設(shè)計(jì)說(shuō)明

本文使用前面文章生成的結(jié)構(gòu)體作為演示數(shù)據(jù)表字段。為簡(jiǎn)單起見,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"

引入第三方庫(kù)

庫(kù)如下:

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

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

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

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

代碼如下,代碼會(huì)自動(dòng)創(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 推薦單個(gè)連接
	w.db.SetMaxIdleConns(1)
	w.db.SetConnMaxLifetime(time.Hour)

	err = w.initTables()
	if err != nil {
		klog.Println("創(chuàng)建內(nèi)部數(shù)據(jù)庫(kù)失敗: ", 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
}

建表

在初始化的同時(shí)創(chuàng)建了數(shù)據(jù)表??梢哉{(diào)用initTableSimple,也可以調(diào)用CreateTableFromStruct。其中initTableSimple為直接指定字段創(chuàng)建表,實(shí)現(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)一些,實(shí)現(xiàn)如下:

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

	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 為空或?yàn)?"-",跳過(guò)該字段
			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 存儲(chǔ)
			}
		case reflect.Slice, reflect.Array, reflect.Map:
			// 數(shù)組/切片/映射序列化為 JSON 存儲(chǔ)
			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 {
			// 自動(dòng)判斷:如果字段名為 "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("沒有找到有效的字段")
	}

	// 建表語(yǔ)句
	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)建表語(yǔ)句:[%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
	}

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

	// 可指定過(guò)濾的字段名,有的庫(kù)可能會(huì)使用自增的id,因此要過(guò)濾
	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ù)庫(kù)可能不支持
	}

	return rows, query, nil
}

查表

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

比如:

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

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

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

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

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

這2個(gè)函數(shù)實(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ù)庫(kù)連接為空")
	}

	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 為空或?yàn)?"-",跳過(guò)該字段
			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 存儲(chǔ)
			}
		case reflect.Slice, reflect.Array, reflect.Map:
			// 數(shù)組/切片/映射序列化為 JSON 存儲(chǔ)
			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 {
			// 自動(dòng)判斷:如果字段名為 "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("沒有找到有效的字段")
	}

	// 建表語(yǔ)句
	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)建表語(yǔ)句:[%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
}

// 自動(dòng)從結(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("查詢耗時(shí): %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
	}

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

	// 可指定過(guò)濾的字段名,有的庫(kù)可能會(huì)使用自增的id,因此要過(guò)濾
	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ù)庫(kù)可能不支持
	}

	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
}

測(cè)試

建表打印信息:

debug 創(chuàng)建表語(yǔ)句:[
                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é)

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

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

相關(guān)文章

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

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

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

    golang中的空接口使用詳解

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

    Go中nil比較的隱藏陷阱

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

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

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

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

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

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

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

    Go語(yǔ)言的接口詳解

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

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

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

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

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

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

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

最新評(píng)論

广宁县| 临桂县| 勃利县| 浮山县| 沙河市| 东至县| 策勒县| 勃利县| 会宁县| 南丹县| 社会| 开封市| 沅江市| 福泉市| 微山县| 锡林郭勒盟| 凤城市| 嘉善县| 滕州市| 盖州市| 常熟市| 鄂尔多斯市| 沧源| 大同市| 邢台市| 红河县| 晴隆县| 宝鸡市| 全椒县| 墨玉县| 镇平县| 响水县| 通江县| 武陟县| 西青区| 新建县| 陕西省| 二手房| 三明市| 锦屏县| 迁西县|