zoukankan      html  css  js  c++  java
  • 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
    ", 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

    常用驱动:

  • 相关阅读:
    Retrofit/Okhttp API接口加固技术实践(上)
    浅析C#中的结构体和类
    iOS中 支付宝钱包具体解释/第三方支付 韩俊强的博客
    Java并发之volatile二
    dynamic initializer和全局变量
    二叉树转换成森林&amp;森林变成二叉树
    这才是真正的裸眼3D!超级震撼!!
    每一个开发人员都应该有一款自己的App
    Hibernate HQL的使用
    我的Android进阶之旅------&gt;Android 关于arm64-v8a、armeabi-v7a、armeabi、x86下的so文件兼容问题
  • 原文地址:https://www.cnblogs.com/52fhy/p/11295095.html
Copyright © 2011-2022 走看看