如何在不干扰客户端的情况下用新版本更新数据库(golang/sqlite3)



我使用的数据库是一个全局变量,初始化读取文件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例程或进程,将旧数据库与新文件同步。插入或更新从新到旧的所有行,然后删除缺失的行。如果这一切都在一个事务中完成,那么所有查询都将读取所有旧数据或新数据,而不会阻塞。

另一个好处是分离了关注点,您的应用程序代码不会与更新逻辑聚集在一起,在这种情况下,新文件已损坏,更新事务出错,不会造成任何伤害。

最新更新