MariaDB并行执行含DEFAULT()的预查询触发1615错误求助
问题原因分析
这个错误是MariaDB在多连接并行场景下,处理关联了Sequence的表的预准备语句时的元数据缓存竞争问题:
- 当查询使用
DEFAULT(column)函数时,预准备语句会依赖表的元数据(列默认值定义) - 关联了Sequence的表,在多连接并行访问时,元数据可能被标记为"失效"(即使表结构没有实际变更)
- 此时预准备语句的依赖元数据发生变化,触发MariaDB抛出
1615 (HY000): Prepared statement needs to be re-prepared错误 - 调整
table_definition_cache无效,说明问题并非缓存容量不足,而是元数据一致性的并发处理逻辑存在缺陷
解决/规避方案
临时规避方案(无需升级数据库)
- 替换
DEFAULT()函数的查询方式:改为从INFORMATION_SCHEMA.COLUMNS直接查询列默认值,示例SQL:SELECT column_default FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() AND table_name = 'table1' AND column_name = 'name' - 驱动层面添加自动重试逻辑:捕获
1615错误后,重新准备语句并执行:- Golang示例修改:
func request(request string, db *sql.DB) { retryCount := 3 var stmt *sql.Stmt var err error var rows *sql.Rows for i := 0; i < retryCount; i++ { stmt, err = db.Prepare(request) if err != nil { if i == retryCount-1 { panic(err.Error()) } time.Sleep(10 * time.Millisecond) continue } rows, err = stmt.Query() if err != nil { if !strings.Contains(err.Error(), "1615") || i == retryCount-1 { panic(err.Error()) } stmt.Close() time.Sleep(10 * time.Millisecond) continue } break } if rows != nil { rows.Close() } if stmt != nil { stmt.Close() } } - PHP mysqli示例:捕获
mysqli_sql_exception,判断错误码为1615时重新执行准备和查询操作
- Golang示例修改:
- 临时解除列与Sequence的关联:如果业务允许,暂时取消列和Sequence的绑定,待问题修复后再重新关联
- 限制单连接执行:仅适合测试场景,生产环境不推荐
长期解决方案
- 升级MariaDB版本:查询MariaDB官方bug列表,确认该问题是否已在后续版本(如11.5+、10.6.x补丁版)修复,升级到对应稳定版
- 提交bug报告:如果当前使用的版本未修复该问题,向MariaDB官方提交包含复现步骤的bug报告,推动问题修复
复现代码与报错
Golang复现代码
package main import ( "database/sql" _ "github.com/go-sql-driver/mysql" "time" ) const myrequest = `SELECT DEFAULT(name) FROM table1` func createDB() *sql.DB { db, err := sql.Open("mysql", "dev:dev@tcp(localhost:3306)/dev") if err != nil { panic(err.Error()) } return db } func request(request string, db *sql.DB) { stmt, err := db.Prepare(request) if err != nil { panic(err.Error()) } _, err = stmt.Query() if err != nil { panic(err.Error()) } } func main() { db := createDB() for i := 0; i < 100; i++ { go func() { request(myrequest, db) }() } time.Sleep(1 * time.Second) }
报错输出
panic: Error 1615 (HY000): Prepared statement needs to be re-prepared goroutine 76 [running]: main.request({0x640f56?, 0x0?}, 0x0?) /home/bperrard/Documents/booking/testmariadb/main.go:336 +0x7c main.main.func1() /home/bperrard/Documents/booking/testmariadb/main.go:344 +0x25 created by main.main in goroutine 1 /home/bperrard/Documents/booking/testmariadb/main.go:343 +0x25
内容的提问来源于stack exchange,提问作者bpeexc
相关产品推荐
相关产品推荐

