Go如何使用数据库、缓存

database/sql 接口

Go官方没有提供数据库驱动,而是为开发数据库驱动定义了一些标准接口database/sql,开发者可以根据定义的接口来开发相应的数据库驱动,这样做有一个好处,只要是按照标准接口开发的代码, 以后需要迁移数据库时,不需要任何修改。

MySQL

常用的有如下几种:

这里使用go-sql-driver/mysql驱动进行演示,原因是该库使用人数最多,且支持database/sql接口。

示例:

package main

import (
	_ "github.com/go-sql-driver/mysql"
	"database/sql"
	"fmt"
)

type User struct {
	Id int
	Name string
	Gender int
	Age int
}

func checkErr(err error) {
	if err != nil {
		panic(err)
	}
}

func main() {
	db, err := sql.Open("mysql", "root:@(127.0.0.1:3306)/test?charset=utf8")
	checkErr(err)

	//查询
	rows, err := db.Query("SELECT id,name,gender,age from user limit 2")
	checkErr(err)

	var users []User
	for rows.Next() {
		var u User
		rows.Scan(&u.Id, &u.Name, &u.Gender, &u.Age)
		users = append(users, u)
	}

	//fmt.Print(users)
	for _,u := range users{
		fmt.Printf("id:%d, name:%s, gender:%d, age:%d\n", u.Id, u.Name, u.Gender, u.Age)
	}
}

输出:

id:1, name:allen, gender:1, age:20
id:2, name:alice, gender:2, age:18

新增:

stmt, err := db.Prepare("INSERT INTO user (name,age) VALUES (?, ?)")
checkErr(err)
res, err := stmt.Exec("golang", 10)
checkErr(err)
fmt.Println(res.LastInsertId())

输出:

26 <nil>

注:res.LastInsertId()返回的新增id和error。

更新:

stmt, err := db.Prepare("update user set age = ? where id = ?")
checkErr(err)
res, err := stmt.Exec(8, 26)
checkErr(err)
fmt.Println(res.RowsAffected())

输出:

1 <nil>

注:res.RowsAffected()返回的影响函数和error。

删除:

stmt, err := db.Prepare("DELETE FROM user where id = ?")
checkErr(err)
res, err := stmt.Exec( 26)
checkErr(err)
fmt.Println(res.RowsAffected())

//或者
//res, err := db.Exec("DELETE FROM user where id = 26")
//checkErr(err)
//fmt.Println(res.RowsAffected())

可以简单封装一下:

func NewMysqlClient() (*sql.DB, error) {
	address := "127.0.0.1:3306"
	user := "root"
	password := ""
	database := "test"
	dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4", user, password, address, database)
	db, err := sql.Open("mysql", dsn)
	return db, errors.Wrap(err, "can not connect db.")
}

PostgreSQL

常见驱动库:

这里使用lib/pq进行演示,因为该库使用的人数最多。

import (
	"database/sql"

	_ "github.com/lib/pq"
)

//获取客户端
func NewPostgreSQLClient() (*sql.DB, error) {
	address := "127.0.0.1"
	user := "pqgotest"
	password := ""
	database := "pqgotest"
	dsn := fmt.Sprintf("%s://%s:%s@%s/%s?sslmode=verify-full", user, password, address, database)
	db, err := sql.Open("postgres", dsn)
	return db, errors.Wrap(err, "can not connect db.")
}

func main() {
	db, err := NewPostgreSQLClient()
	if err != nil {
		log.Fatal(err)
	}

	age := 21
	rows, err := db.Query("SELECT name FROM users WHERE age = $1", age)
	//…
}

SQLite

驱动库:https://github.com/mattn/go-sqlite3

该驱动采用database/sql接口,所以使用起来和操作MySQL是一样的。

增删改查示例:

package main

import (
	"database/sql"
	"fmt"

	_ "github.com/mattn/go-sqlite3"
)

//CREATE TABLE `userinfo` (
//	`uid` INTEGER PRIMARY KEY AUTOINCREMENT,
//	`username` VARCHAR(64) NULL,
//	`departname` VARCHAR(64) NULL,
//	`created` DATE NULL
//);

func checkErr(err error) {
	if err != nil {
		panic(err)
	}
}

type UserInfo struct {
	uid        int
	username   string
	departname string
	created    string
}

func main() {
	db, err := sql.Open("sqlite3", "./test_sqlite.db")
	checkErr(err)

	//增加
	stmt, err := db.Prepare("insert into userinfo(username,departname,created) values(?, ?, ?)")
	checkErr(err)

	res, err := stmt.Exec("yjc", "test", "2018-08-12")
	checkErr(err)

	id, err := res.LastInsertId()
	checkErr(err)

	fmt.Println(id)

	//更新
	stmt, err = db.Prepare("update userinfo set username = ? where uid = ?")
	checkErr(err)

	res, err = stmt.Exec("golang", 1)
	checkErr(err)

	affect, err := res.RowsAffected()
	checkErr(err)
	fmt.Println(affect)

	//查询
	rows, err := db.Query("select * from userinfo")
	checkErr(err)

	var user UserInfo
	var users []UserInfo
	for rows.Next() {
		rows.Scan(&user.uid, &user.username, &user.departname, &user.created)
		users = append(users, user)
	}

	fmt.Println(users)

	//删除
	stmt, err = db.Prepare("delete from userinfo where uid = ?")
	checkErr(err)

	res, err = stmt.Exec(2)
	checkErr(err)

	affect, err = res.RowsAffected()
	checkErr(err)
	fmt.Println(affect)

}

可以简单封装一下:

func NewSqliteClient() (*sql.DB, error) {
	dbname := "./test_sqlite.db"
	db, err := sql.Open("sqlite3", dbname)
	return db, errors.Wrap(err, "can not connect db.")
}

redis

Go目前支持redis的驱动有如下

前面两个Star数是最多的,生产环境推荐从前面两个选择。使用上go-redis/redis简单些。

go-redis/redis示例

//获取客户端
func NewRedisClient() *redis.Client {
	client := redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password set
		DB:       0,  // use default DB
	})

	//pong, err := client.Ping().Result()
	//fmt.Println(pong, err)
	// Output: PONG <nil>
	return client
}

//test
func ExampleClient() {
    client := NewRedisClient()
    defer client.Close()
    
	err := client.Set("key", "value", 0).Err()
	if err != nil {
		panic(err)
	}

	val, err := client.Get("key").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println("key", val)

	val2, err := client.Get("key2").Result()
	if err == redis.Nil {
		fmt.Println("key2 does not exist")
	} else if err != nil {
		panic(err)
	} else {
		fmt.Println("key2", val2)
	}
	// Output: key value
	// key2 does not exist
}

mongoDB

目前Go支持mongoDB最好的驱动就是mgo,地址:http://labix.org/mgo

2019-08-18 更新:很长一段时间,MongoDB 的 Go 语言驱动一直使用的 mgo 这个,但由于作者工作中不再使用 MongoDB,出于精力等方面的考虑,该项目不再维护。而且我们有了官方出品的驱动,自然应该使用它了。地址:https://github.com/mongodb/mongo-go-driver。

安装mgo:

go get gopkg.in/mgo.v2

示例:

package main

import (
    "fmt"
	"log"
    "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
)

type Person struct {
    Name string
    Phone string
}

func main() {
    session, err := mgo.Dial("server1.example.com,server2.example.com")
    if err != nil {
            panic(err)
    }
    defer session.Close()

    // Optional. Switch the session to a monotonic behavior.
    session.SetMode(mgo.Monotonic, true)

    c := session.DB("test").C("people")
    err = c.Insert(&Person{"Ale", "+55 53 8116 9639"},
               &Person{"Cla", "+55 53 8402 8510"})
    if err != nil {
            log.Fatal(err)
    }

    result := Person{}
    err = c.Find(bson.M{"name": "Ale"}).One(&result)
    if err != nil {
            log.Fatal(err)
    }

    fmt.Println("Phone:", result.Phone)
}

Elasticsearch

常用驱动:

posted @ 2019-08-03 15:54  飞鸿影  阅读(876)  评论(0编辑  收藏