我正在编写一个golang Web应用程序。 Web应用程序访问文件系统(读取和写入)和sqlite3数据库文件。
问题1:如何在Go中同步文件系统访问?
type DataObject struct {
data []byte
}
func (*d DataObject) Write() {
//
// Synchronization ?
//
ioutil.WriteFile("file.name", d.data, 0644)
//
// Stop synchronization ?
//
}
问题2:我是否需要同步sqlite3数据库文件?
type SqlObject struct {
sqldata string
}
func (*s SqlObject) Store() error {
//
// Open the file, do I need some sort of synchronization?
//
con, err := sqlite.Open("database/datafile.db")
if err != nil {
return err
}
defer con.Close()
err = con.Exec("INSERT INTO data(sqldata) values(?)", s.sqldata)
if err != nil {
return err
}
return nil
}
我正在使用gosqlite3驱动程序(http://code.google.com/p/gosqlite/)。
答案 0 :(得分:7)
对于文件,它取决于您的应用程序。如果你只有一个goroutine写入文件,你不应该。如果不止一个,则取决于:
如果您在不同的进程(程序)之间进行协调,则可以使用flock(这可能不会很有趣)。
如果您正在协调程序中的多个goroutine,您可以使用mutexes,或者您可以看看是否可以重新组织程序,因此只需一个例程写入文件,其他例程通过频道发送更新。
对于SQLite,我认为最简单的方法是保持一个sqlite连接打开并使用来自各种goroutines的连接;虽然它确实支持多个进程同时打开它,如果你的系统执行许多可能更快的并发读取(它使用全局锁写入)。
答案 1 :(得分:4)
问题1
"sync"包提供了Lock和RWLock,用于以传统方式同步对资源的访问。虽然这没有什么不妥,但我喜欢玩成语,所以我可能会做this之类的事情:
package main
import "fmt"
func SyncFile(path string) chan<- func(string) {
ch := make(chan func(string))
go func() {
for process := range ch {
process(path)
}
}()
return ch
}
func main() {
data := SyncFile("data.name")
data <- func(path string) {
fmt.Println(path)
}
}
然后,如果您只通过此func通道访问该文件,则将同步访问。这是可靠的,但您可以找到更有效的东西。
问题2
gosqlite3驱动程序只是对libsqlite3的Go绑定,因此适用SQLite FAQ(看起来你已明白了)。如果您希望这两者彼此同步,那么只需将SQLite用法包装在文件访问同步代码中。
答案 2 :(得分:3)
1)您应该使用读/写互斥锁(在go std库中)。 代码看起来像:
import "sync" // http://golang.org/pkg/sync/
const (
filename = "file.name"
)
var globalFileLock sync.RWMutex
type DataObject struct {
data []byte
}
func (*d DataObject) Write() {
globalFileLock.Lock()
defer globalFileLock.Unlock()
ioutil.WriteFile(filename, d.data, 0644)
}
func (*d DataObject) Read() {
globalFileLock.RLock()
defer globalFileLock.RUnlock()
d.data = ioutil.ReadFile(filename)
}
2)由于您尚未从程序中发布“导入”部分,因此我不知道您使用的是哪个sqlite驱动程序。
如果您使用database / sql打开数据库连接,驱动程序会在goroutines之间提供并发控制。
答案 3 :(得分:-1)
我知道这是一个老问题,但由于我遇到了同样的“数据库锁定”问题,而且事务已经为我解决了,我想我会在这里提到它:
db, err := sql.Open("sqlite3", db_path)
if err != nil {
log.Printf("Cannot connect to database: %s\n", err )
}
defer db.Close()
tx, _ := db.Begin()
var value string
err = tx.QueryRow("SELECT X FROM Y").Scan(&value)
tx.Rollback() // or: tx.Commit()