必须为每个驱动单独调用gorm.open(),不可复用同一实例连接不同数据库;需声明独立变量(如mysqldb、sqlitedb),显式导入对应驱动,使用适配方言的dsn和模型定义,并分别配置连接池与迁移。

gorm.Open() 必须为每个驱动单独调用
不能只写一次 gorm.Open() 就想同时跑 MySQL 和 SQLite —— GORM 的 *gorm.DB 实例是绑定到具体驱动和方言的。你传 mysql.Open(dsn),它就只会理解 MySQL 语法;传 sqlite.Open(dsn),它才按 SQLite 规则解析表名、类型、默认值等。
常见错误是:在 init 函数里反复调用 gorm.Open() 赋值给同一个全局变量 db,结果后一次覆盖前一次,SQLite 查询实际发到了 MySQL 上,报错像 no such table 或 near "AUTOINCREMENT" 这种方言不匹配提示。
- 正确做法是声明两个独立变量:
var mysqlDB *gorm.DB、var sqliteDB *gorm.DB - 各自调用
gorm.Open(mysql.Open(dsn), ...)和gorm.Open(sqlite.Open(dsn), ...) - 务必显式导入驱动:
import _ "gorm.io/driver/mysql"和import _ "gorm.io/driver/sqlite"(下划线不能漏)
DSN 格式与关键参数差异极大
MySQL 和 SQLite 的 DSN 完全不是一回事:MySQL 是网络地址+认证信息,SQLite 是本地文件路径。填错格式会导致初始化静默失败或运行时报模糊错误(比如 file is not a database 或连接超时)。
- MySQL DSN 示例:
"root:pass@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local",必须含parseTime=True和loc=Local,否则 time.Time 字段解析异常 - SQLite DSN 示例:
"test.db?_foreign_keys=1&_busy_timeout=5000",注意:- 路径是相对或绝对文件路径,不是 host:port
-
_foreign_keys=1才能启用外键约束 -
_busy_timeout避免写冲突时直接报database is locked
模型定义需适配两套方言
同一个结构体字段,在 MySQL 里用 AUTO_INCREMENT,SQLite 里得用 INTEGER PRIMARY KEY;MySQL 支持 TIMESTAMP DEFAULT CURRENT_TIMESTAMP,SQLite 只认 DEFAULT CURRENT_TIMESTAMP(无类型前缀)。GORM 的 gorm.Model 或 gorm.ColumnType 不会自动转换这些。
- 别直接复用同一份
type User struct跨库操作——哪怕字段名一致,db.Create(&u)在 SQLite 上可能因主键策略失败 - 推荐按库拆分模型:如
MySQLUser和SQLiteUser,用 tag 分别控制:gorm:"primaryKey;autoIncrement"vsgorm:"primaryKey;autoIncrement:false" - 迁移也得分开做:
mysqlDB.AutoMigrate(&MySQLUser{})和sqliteDB.AutoMigrate(&SQLiteUser{})
事务与查询逻辑无法共享
mysqlDB.Transaction() 和 sqliteDB.Transaction() 彼此完全隔离。你在 MySQL 事务里调 sqliteDB.Create(),后者根本不在事务上下文中,提交或回滚都影响不到它。
- 不要试图用一个函数封装“跨库写入”,这不是 ORM 层能解决的问题
- 如果业务真要双写(比如开发环境 SQLite + 生产环境 MySQL),得靠上层协调:先写 SQLite 成功,再同步写 MySQL;失败则走补偿逻辑,而不是依赖事务原子性
-
db.Table("users").Where(...).Find()这类链式调用也得明确指定是哪个 DB 实例——混用会导致字段类型映射错乱,比如 SQLite 的TEXT被当 MySQL 的VARCHAR处理,长度截断或比较失效
最易被忽略的一点:SQLite 的连接池行为和 MySQL 不同。它本质是文件锁,MaxOpenConns 设太高反而容易触发 database is locked;而 MySQL 的连接池参数(如 ConnMaxLifetime)对 SQLite 完全无效。必须为每个驱动单独配置,不能共用一套连接池设置。











