使用更优雅的断言来代替 strings.Contains

封面

处理 MySQL Duplicate 错误是比较基础的内容,但目前网上的资料不是很全面,对入门同学有门槛。

日常 Go 开发过程中经常会操作数据库,使用 INSERT 操作时可能会遇到主键或者唯一索引发生冲突的情况,日志输出的内容如下所示。

Error 1062: Duplicate entry '%s' for key %d

正确处理方式

断言 Error 接口为 mysql.MySQLError 类型,随后判断 Number 字段值为 1062 即可进行特殊处理。

import (
	"database/sql"
	"os"

	"github.com/go-sql-driver/mysql"
	_ "github.com/go-sql-driver/mysql"
)

func main() {
	db, _ := sql.Open("mysql", os.Getenv("DSN"))
	
	_, err := db.Exec("INSERT INTO test_table(id) VALUES (1)")
	if err != nil {
		
		// make sure err is a mysql.MySQLError.
		if errMySQL, ok := err.(*mysql.MySQLError); ok {
			switch errMySQL.Number {
			case 1062:
				// TODO handle Error 1062: Duplicate entry '%s' for key %d
			}
		}
		
	}
}

原理

日志输出的内容是 Go 基本库 Error 接口的 Error 方法结果,如果我们使用的是 go-sql-driver 作为 Driver,那么 Error 接口的实现是 go-sql-driver 内的 MySQLError 结构体。

代码位置在 go-sql-driver/mysql/blob/master/errors.go#L58,源码如下所示。

// MySQLError is an error type which represents a single MySQL error
type MySQLError struct {
	Number  uint16
	Message string
}

func (me *MySQLError) Error() string {
	return fmt.Sprintf("Error %d: %s", me.Number, me.Message)
}

根据上述原理进行类推,我们可以根据全部 MySQL 错误代码进行处理。

参考资料

关于 MySQL 错误,您可以查阅 MySQL 官方文档 - Chapter 2 Server Error Message Reference