Golang结构体数据循环问题解析
Golang结构体数据循环问题解析
在我的代码中,我在 init 函数中执行以下代码块:
package main
import (
"syscall/js"
)
type object map[string]interface{}
var Window = js.Global()
type DataBase struct {
Data, Transactions, ObjectStore, Request js.Value
Upgrade js.Func
}
var DB DataBase // 所有结构体字段都初始化为它们的零值
func init() {
DB.init("dataSet", "table")
}
其中 DB.init 函数是:
package main
import (
"fmt"
"syscall/js"
)
func (db *DataBase) init(dataSet, table string) {
var Ok, Err js.Func
db.Request = Window.Get("indexedDB").Call("open", dataSet, 1)
db.Upgrade = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
defer db.Upgrade.Release()
db.Data = this.Get("result")
Store := db.Data.Call("createObjectStore", table, map[string]interface{}{"keyPath": "id"})
Store.Call("add", map[string]interface{}{"id": "00-03", "name": "Karam", "age": 19, "email": "kenny@planet.org"})
Window.Call("alert", "第一条记录已发布。")
return nil
})
Ok = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
db.Data = this.Get("result")
stores := []string{table}
objectStore := make([]interface{}, len(stores))
for i, v := range stores {
objectStore[i] = v
}
db.Transactions = db.Data.Call("transaction", objectStore, "readwrite").Call("objectStore", table)
db.ObjectStore = db.Data.Call("transaction", objectStore).Call("objectStore", table)
Window.Call("alert", "数据库已准备就绪!")
return nil
})
Err = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
Window.Call("alert", "抱歉,无法初始化数据库")
return nil
})
db.Request.Set("onupgradeneeded", db.Upgrade)
db.Request.Set("onsuccess", Ok)
db.Request.Set("onerror", Err)
}
以上代码使用了 indexedDB API,其中 db.Upgrade 仅在应用程序首次运行时执行一次(或者如果数据库已被删除,或者分配了新的版本号)。
然后,每次应用程序运行时(在升级之后),Ok 函数都会作为第一件事运行。
根据上面的代码,我假设只要应用程序在运行,变量 db.Transactions 就应该存在并附加到 DB 上,并且我应该能够通过附加到结构体的任何方法来调用它。
但是,当我在后续阶段调用 Add 函数时,即:
func (db *DataBase) Add(table string, usr map[string]interface{}) {
fmt.Println(usr)
var Ok, Err js.Func
fmt.Println(table)
stores := []string{table} // 为了解决意外的字面量 'employee',期望方法或接口名称
objectStore := make([]interface{}, len(stores))
for i, v := range stores {
objectStore[i] = v
}
// db.Transactions = db.Data.Call("transaction", objectStore, "readwrite").Call("objectStore", table)
request := db.Transactions.Call("add", usr)
Ok = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
defer Ok.Release()
Window.Call("alert", "用户已添加。")
return nil
})
request.Set("onsuccess", Ok)
Err = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
defer Err.Release()
Window.Call("alert", "抱歉,无法添加用户//。")
return nil
})
request.Set("onerror", Err)
}
我得到一个关于 db.Transactions 的错误:
panic: JavaScript error: Failed to execute 'add' on 'IDBObjectStore': The transaction has finished.
但是,如果我在 Add 函数的代码中重新定义它,即取消注释这行:
// db.Transactions = db.Data.Call("transaction", objectStore, "readwrite").Call("objectStore", table)
那么一切都会顺利运行!
有什么想法吗?
更多关于Golang结构体数据循环问题解析的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于Golang结构体数据循环问题解析的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
问题出在IndexedDB事务的生命周期管理上。在Go WebAssembly中,IndexedDB事务是自动提交的,一旦回调函数执行完毕,事务就会自动结束。
在你的代码中,init函数里的Ok回调创建了一个事务,但这个事务在回调执行完成后就自动结束了。所以后续调用Add方法时,db.Transactions引用的是一个已经结束的事务。
正确的做法是每次需要操作数据库时都创建新的事务。以下是修改后的Add函数:
func (db *DataBase) Add(table string, usr map[string]interface{}) {
fmt.Println(usr)
var Ok, Err js.Func
// 每次操作都需要创建新的事务
stores := []string{table}
objectStore := make([]interface{}, len(stores))
for i, v := range stores {
objectStore[i] = v
}
// 创建新的事务
transaction := db.Data.Call("transaction", objectStore, "readwrite")
objectStoreHandle := transaction.Call("objectStore", table)
request := objectStoreHandle.Call("add", usr)
Ok = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
defer Ok.Release()
Window.Call("alert", "用户已添加。")
return nil
})
request.Set("onsuccess", Ok)
Err = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
defer Err.Release()
Window.Call("alert", "抱歉,无法添加用户。")
return nil
})
request.Set("onerror", Err)
}
同样,如果你需要其他数据库操作(如查询、更新、删除),也应该遵循相同的模式:
func (db *DataBase) Get(table string, key string) {
stores := []string{table}
objectStore := make([]interface{}, len(stores))
for i, v := range stores {
objectStore[i] = v
}
transaction := db.Data.Call("transaction", objectStore, "readonly")
objectStoreHandle := transaction.Call("objectStore", table)
request := objectStoreHandle.Call("get", key)
request.Set("onsuccess", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
result := args[0].Get("target").Get("result")
fmt.Println("查询结果:", result)
return nil
}))
}
对于init函数中的Ok回调,可以只保留数据库连接,而不创建长期事务:
Ok = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
db.Data = this.Get("result")
Window.Call("alert", "数据库已准备就绪!")
return nil
})
这样修改后,每次数据库操作都会使用独立的事务,避免了事务已结束的错误。

