我使用的数据库是一个全局变量,初始化读取文件sql-repo.db
:
const dbFile = "sql-repo.db"
var globalDB *LocalDB
type LocalDB struct {
Path string
handle *sql.DB
}
func InitSqlDB(dbDir string) error {
if globalDB != nil {
return nil
}
db := LocalDB{Path: filepath.Join(dbDir, dbFile)}
var err error
db.handle, err = sql.Open("sqlite3", db.Path)
if err != nil {
return err
}
globalDB = &db
return nil
}
不时地,我会有这个数据库的更新版本,我可以下载并存储在dbDir
中。
我的想法:
- 使用
ATTACH DATABASE sql-repo.db AS dbMain
附加第一个数据库的副本,并在默认情况下使用它
当我有了新的.db
文件时,我也会附加它ATTACH DATABASE sql-repo-new.db AS dbNew
然后分离dbMain
并将dbNew
重命名为dbMain
- 只需更改我的
globalDB
指向的地址:
const newDBFile = "sql-repo-new.db"
func PullNewDB(dbDir string) error {
db := LocalDB{Path: filepath.Join(dbDir, newDBFile)}
var err error
db.handle, err = sql.Open("sqlite3", db.Path)
if err != nil {
return err
}
globalDB = &db
return nil
}
如果我代码中的客户端连接到数据库并正在查询数据库,我如何或应该如何用新版本/文件更新globalDB
,以避免任何干扰?
我应该将sync.RWMutex
附加到我的LocalDB
结构,然后在更新时锁定/解锁它吗
或者我应该使用一个通道来要求每个客户端停止查询数据库?
感谢您的帮助/建议!
或者您可以启动一个单独的go例程或进程,将旧数据库与新文件同步。插入或更新从新到旧的所有行,然后删除缺失的行。如果这一切都在一个事务中完成,那么所有查询都将读取所有旧数据或新数据,而不会阻塞。
另一个好处是分离了关注点,您的应用程序代码不会与更新逻辑聚集在一起,在这种情况下,新文件已损坏,更新事务出错,不会造成任何伤害。