gorm_sqlite.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. package initialize
  2. import (
  3. "fmt"
  4. "os"
  5. "path/filepath"
  6. "github.com/glebarez/sqlite"
  7. "go.uber.org/zap"
  8. "gorm.io/gorm"
  9. "wails-app/internal/config"
  10. "wails-app/internal/global"
  11. "wails-app/internal/initialize/internal"
  12. )
  13. // GormSqlite 初始化Sqlite数据库
  14. func GormSqlite() *gorm.DB {
  15. s := global.GVA_CONFIG.Sqlite
  16. if s.Dbname == "" {
  17. return nil
  18. }
  19. // Resolve path: empty = %APPDATA%/smart-parking/
  20. if s.Path == "" {
  21. if appData := os.Getenv("APPDATA"); appData != "" {
  22. s.Path = appData
  23. } else {
  24. // Fallback: exe directory
  25. if exePath, err := os.Executable(); err == nil {
  26. s.Path = filepath.Dir(exePath)
  27. }
  28. }
  29. s.Path = filepath.Join(s.Path, "smart-parking")
  30. }
  31. // Ensure directory exists
  32. if err := os.MkdirAll(s.Path, 0755); err != nil {
  33. panic(fmt.Errorf("failed to create SQLite db directory %s: %w", s.Path, err))
  34. }
  35. dsn := filepath.Join(s.Path, s.Dbname+".db")
  36. fmt.Printf("SQLite database: %s\n", dsn)
  37. if global.GVA_LOG != nil {
  38. global.GVA_LOG.Info("SQLite 数据库路径", zap.String("dsn", dsn))
  39. }
  40. if db, err := gorm.Open(sqlite.Open(dsn), internal.Gorm.Config(s.Prefix, s.Singular)); err != nil {
  41. panic(err)
  42. } else {
  43. configureSQLite(db, s)
  44. return db
  45. }
  46. }
  47. // GormSqliteByConfig 初始化Sqlite数据库用过传入配置
  48. func GormSqliteByConfig(s config.Sqlite) *gorm.DB {
  49. if s.Dbname == "" {
  50. return nil
  51. }
  52. if db, err := gorm.Open(sqlite.Open(s.Dsn()), internal.Gorm.Config(s.Prefix, s.Singular)); err != nil {
  53. panic(err)
  54. } else {
  55. configureSQLite(db, s)
  56. return db
  57. }
  58. }
  59. // configureSQLite limits concurrent connections and enables SQLite settings
  60. // that avoid long writer starvation when device events and API requests share
  61. // the same database file.
  62. func configureSQLite(db *gorm.DB, s config.Sqlite) {
  63. sqlDB, err := db.DB()
  64. if err != nil {
  65. panic(err)
  66. }
  67. maxIdle := s.MaxIdleConns
  68. if maxIdle <= 0 {
  69. maxIdle = 1
  70. }
  71. maxOpen := s.MaxOpenConns
  72. if maxOpen <= 0 {
  73. maxOpen = 4
  74. }
  75. if maxOpen < maxIdle {
  76. maxOpen = maxIdle
  77. }
  78. sqlDB.SetMaxIdleConns(maxIdle)
  79. sqlDB.SetMaxOpenConns(maxOpen)
  80. // WAL allows readers to continue while a writer commits. busy_timeout
  81. // prevents transient lock contention from immediately failing a request.
  82. for _, pragma := range []string{
  83. "PRAGMA busy_timeout = 5000",
  84. "PRAGMA journal_mode = WAL",
  85. "PRAGMA synchronous = NORMAL",
  86. } {
  87. if err := sqlDB.Ping(); err != nil {
  88. if global.GVA_LOG != nil {
  89. global.GVA_LOG.Warn("SQLite 连接检查失败", zap.Error(err))
  90. }
  91. return
  92. }
  93. if _, err := sqlDB.Exec(pragma); err != nil && global.GVA_LOG != nil {
  94. global.GVA_LOG.Warn("SQLite PRAGMA 设置失败", zap.String("pragma", pragma), zap.Error(err))
  95. }
  96. }
  97. }