首先我们要准备一个写golang的IDE,我用的是goland,还可以用vscode。
然后我们要知道golang的基本使用。
其次我们还要知道连接MySQL的基本步骤,如果有jdbc的封装经历就更好啦。
那就开始吧!
go get github.com/go-sql-driver/mysql_ "github.com/go-sql-driver/mysql"driver.go
func init() {
sql.Register("mysql", &MySQLDriver{})
}
我们导入mysql这个包的作用主要是为了执行这个init方法,注册mysql驱动。
连接mysqlfunc Connect() (*sql.DB, error) {
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8", username, password, url, dbName))
if err != nil {
return nil, err
}
return db, err
}
fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8", username, password, url, dbName)root:123456@tcp(127.0.0.1:3306)/test?charset=utf8
增删改查
增
func Insert(sql string, params ...interface{}) {
// 注意:这里必须是params... 不然会转成数组类型了
res, err := DB.Exec(sql, params...)
// 打印上一次插入自增的id
if res != nil {
fmt.Println(res.LastInsertId())
} else {
fmt.Printf("插入失败:%v\n", err)
}
}
前面是sql语句,后面是要加的参数,调用方法是这样的:
var user = User{
Username: "xxx",
Password: "xxx",
}
var sql = "insert into user (username, password) values (?, ?)"
Insert(sql, user.Username, user.Password)
删
func Delete(sql string, params ...interface{}) {
res, err := DB.Exec(sql, params...)
if err != nil {
fmt.Printf("删除失败:%v\n", err)
} else {
fmt.Println(res.RowsAffected())
}
}
调用方法与增加类似
var sql = "delete from user where id = ?"
// 删除id为1的用户
Delete(sql, 1)
改
func Update(sql string, params ...interface{}) {
res, err := DB.Exec(sql, params...)
if err != nil {
fmt.Printf("更新失败:%v\n", err)
} else {
fmt.Println(res.RowsAffected())
}
}
更新的调用方法也与之前一样的
var sql = "update user set username = ? where id = ?"
// 更新id为1的用户的用户名为张三
Update(sql, "张三", 1)
查
查询这里我是用反射封装了一个比较通用的查询,最后会返回一个list表示结果集,结果的类型应该是一个结构体,结构体的具体类型由用户传入的参数决定。
func Query(sqlString string, i interface{}) (res *list.List) {
rows, _ := DB.Query(sqlString)
res = list.New()
t := reflect.TypeOf(i)
// 获取表的所有列
cols, _ := rows.Columns()
// 这里需要琢磨一下
values := make([]sql.RawBytes, len(cols))
scanArgs := make([]interface{}, len(values))
for i := 0; i < len(values); i++ {
scanArgs[i] = &values[i]
}
for rows.Next() {
_ = rows.Scan(scanArgs...)
obj := reflect.New(t).Elem()
for i, v := range values {
// FiledByName 是根据字段名获取该字段的值...
value := obj.FieldByName(StringToCamel(cols[i]))
if !value.IsValid() {
fmt.Printf("字段名为 %s 的字段与结构体不匹配\n", cols[i])
continue
} else {
switch value.Kind() {
case reflect.Bool:
// TODO 转换Bool类型
case reflect.String:
value.SetString(string(v))
case reflect.Int:
temp, _ := strconv.Atoi(string(v))
value.SetInt(int64(temp))
}
}
}
res.PushBack(obj)
}
return
}
调用方法如下
type User struct {
Username string
Password string
}
var sql = "select * from user"
// 查询所有的用户,结果封装在res中
res := Query(sql, User{})
// 遍历res,打印结果
for i := res.Front(); i != nil; i = i.Next() {
fmt.Println(i.Value)
}
要注意的是如何将数据从rows中读取出来,还有就是反射,是一个Type和一个Value,是对应的,Type是类型,Value是具体的值,比如User的Username字段,它的Type是string,而Value是Username的具体的值,这个需要琢磨一下。