如何在Golang中编写通用函数动态替换SQL参数
Golang 通用SQL参数替换实现
需求说明
数据库中存储着带@前缀参数占位符的SELECT语句,示例如下:
select * from dbo.student where dob > @date_of_birth and grade = @grade
从Kafka获取的参数JSON格式(已翻译为中文):
{ "message": [{ "sql_table": "student", "input_params": [{ "key": "@date_of_birth", "value": "2012-03-03" }, { "key": "@grade", "value": "5" } ] } ] }
需要实现一个通用函数,支持任意表、任意数量参数的占位符替换。
实现代码
1. 定义JSON解析结构体
先定义对应Kafka消息格式的结构体,方便解析参数:
type Param struct { Key string `json:"key"` Value string `json:"value"` } type KafkaMessageItem struct { SqlTable string `json:"sql_table"` InputParams []Param `json:"input_params"` } type KafkaMessage struct { Message []KafkaMessageItem `json:"message"` }
2. 通用参数替换函数
实现核心替换逻辑,同时处理字符串参数的单引号转义、数字参数的格式适配:
import ( "strings" ) // ReplaceSQLParams 接收原始SQL和参数列表,返回替换后的SQL语句 func ReplaceSQLParams(originalSQL string, params []Param) string { replacedSQL := originalSQL for _, p := range params { var valueStr string // 判断参数是否为数字,数字类型直接使用原值,字符串类型添加单引号并转义内部单引号 if isNumeric(p.Value) { valueStr = p.Value } else { escapedValue := strings.ReplaceAll(p.Value, "'", "''") valueStr = "'" + escapedValue + "'" } replacedSQL = strings.ReplaceAll(replacedSQL, p.Key, valueStr) } return replacedSQL } // isNumeric 判断字符串是否为纯数字 func isNumeric(s string) bool { for _, c := range s { if c < '0' || c > '9' { return false } } return true }
3. 使用示例
模拟从Kafka获取消息、解析并完成参数替换的完整流程:
import ( "encoding/json" "fmt" ) func main() { // 模拟从数据库读取的原始SQL originalSQL := "select * from dbo.student where dob > @date_of_birth and grade = @grade" // 模拟Kafka获取的JSON字符串 kafkaJSON := `{ "message": [{ "sql_table": "student", "input_params": [{ "key": "@date_of_birth", "value": "2012-03-03" }, { "key": "@grade", "value": "5" } ] } ] }` // 解析Kafka消息 var msg KafkaMessage err := json.Unmarshal([]byte(kafkaJSON), &msg) if err != nil { fmt.Printf("JSON解析失败: %v\n", err) return } // 处理消息(此处取第一个消息项,实际场景可根据需求遍历所有message元素) if len(msg.Message) == 0 { fmt.Println("无可用消息数据") return } item := msg.Message[0] // 执行参数替换 finalSQL := ReplaceSQLParams(originalSQL, item.InputParams) fmt.Println("替换后的SQL:", finalSQL) }
注意事项
- 上述实现仅做基础的格式处理和注入防护,生产环境优先推荐使用数据库驱动的参数化查询(如
database/sql包的Prepare+Query/Exec),从根源避免SQL注入风险。 - 若占位符格式不是
@前缀,只需调整替换逻辑中的占位符匹配规则即可,函数本身具备通用性。 - 多表场景下,可维护一个表名到原始SQL的映射关系,根据
sql_table字段匹配对应的SQL语句。
内容的提问来源于stack exchange,提问作者John Scott
相关产品推荐
相关产品推荐

