golang操作Redis&Mysql&RabbitMQ的方法介绍
golang操作Redis&Mysql&RabbitMQ:
Reids
安装导入
1 2 | go get github.com/garyburd/redigo/redis import "github.com/garyburd/redigo/redis" |
使用
连接
1 2 3 4 5 6 7 8 9 10 | import "github.com/garyburd/redigo/redis"
func main() { c, err := redis.Dial("tcp", "localhost:6379") if err != nil { fmt.Println("conn redis failed, err:", err) return } defer c.Close() } |
set & get
1 2 3 4 5 6 7 8 9 10 11 12 | _, err = c.Do("Set", "name", "nick") if err != nil { fmt.Println(err) return }
r, err := redis.String(c.Do("Get", "name")) if err != nil { fmt.Println(err) return } fmt.Println(r) |
mset & mget
批量设置
1 2 3 4 5 6 7 8 9 10 11 12 | _, err = c.Do("MSet", "name", "nick", "age", "18") if err != nil { fmt.Println("MSet error: ", err) return }
r2, err := redis.Strings(c.Do("MGet", "name", "age")) if err != nil { fmt.Println("MGet error: ", err) return } fmt.Println(r2) |
hset & hget
hash操作
1 2 3 4 5 6 7 8 9 10 11 12 | _, err = c.Do("HSet", "names", "nick", "suoning") if err != nil { fmt.Println("hset error: ", err) return }
r, err = redis.String(c.Do("HGet", "names", "nick")) if err != nil { fmt.Println("hget error: ", err) return } fmt.Println(r) |
expire
设置过期时间
1 2 3 4 5 | _, err = c.Do("expire", "names", 5) if err != nil { fmt.Println("expire error: ", err) return } |
lpush & lpop & llen
队列
立即学习“go语言免费学习笔记(深入)”;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | // 队列 _, err = c.Do("lpush", "Queue", "nick", "dawn", 9) if err != nil { fmt.Println("lpush error: ", err) return } for { r, err = redis.String(c.Do("lpop", "Queue")) if err != nil { fmt.Println("lpop error: ", err) break } fmt.Println(r) } r3, err := redis.Int(c.Do("llen", "Queue")) if err != nil { fmt.Println("llen error: ", err) return } |
连接池
各参数的解释如下:
MaxIdle:最大的空闲连接数,表示即使没有redis连接时依然可以保持N个空闲的连接,而不被清除,随时处于待命状态。
MaxActive:最大的激活连接数,表示同时最多有N个连接
IdleTimeout:最大的空闲连接等待时间,超过此时间后,空闲连接将被关闭
1 2 3 4 5 6 7 8 | pool := &redis.Pool{ MaxIdle: 16, MaxActive: 1024, IdleTimeout: 300, Dial: func() (redis.Conn, error) { return redis.Dial("tcp", "localhost:6379") }, } |
连接池例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | package main
import ( "fmt"
"github.com/garyburd/redigo/redis" )
var pool *redis.Pool
func init() { pool = &redis.Pool{ MaxIdle: 16, MaxActive: 1024, IdleTimeout: 300, Dial: func() (redis.Conn, error) { return redis.Dial("tcp", "localhost:6379") }, } }
func main() { c := pool.Get() defer c.Close()
_, err := c.Do("Set", "name", "nick") if err != nil { fmt.Println(err) return }
r, err := redis.String(c.Do("Get", "name")) if err != nil { fmt.Println(err) return } fmt.Println(r) } |
管道操作
请求/响应服务可以实现持续处理新请求,客户端可以发送多个命令到服务器而无需等待响应,最后在一次读取多个响应。
使用Send(),Flush(),Receive()方法支持管道化操作
Send向连接的输出缓冲中写入命令。
Flush将连接的输出缓冲清空并写入服务器端。
Recevie按照FIFO顺序依次读取服务器的响应。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | func main() { c, err := redis.Dial("tcp", "localhost:6379") if err != nil { fmt.Println("conn redis failed, err:", err) return } defer c.Close()
c.Send("SET", "name1", "sss1") c.Send("SET", "name2", "sss2")
c.Flush()
v, err := c.Receive() fmt.Printf("v:%v,err:%v\n", v, err) v, err = c.Receive() fmt.Printf("v:%v,err:%v\n", v, err)
v, err = c.Receive() // 夯住,一直等待 fmt.Printf("v:%v,err:%v\n", v, err) } |
Mysql
安装导入
1 2 3 4 5 6 7 | go get "github.com/go-sql-driver/mysql" go get "github.com/jmoiron/sqlx"
import ( _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" ) |
连接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import ( _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" )
var Db *sqlx.DB
func init() {
database, err := sqlx.Open("mysql", "root:@tcp(127.0.0.1:3306)/test") if err != nil { fmt.Println("open mysql failed,", err) return }
Db = database } |
建表
1 2 3 4 5 6 | CREATE TABLE `person` ( `user_id` int(128) DEFAULT NULL, `username` varchar(255) DEFAULT NULL, `sex` varchar(16) DEFAULT NULL, `email` varchar(128) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
(insert)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | package main
import ( "fmt"
_ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" )
type Person struct { UserId int `db:"user_id"` Username string `db:"username"` Sex string `db:"sex"` Email string `db:"email"` }
var Db *sqlx.DB
func init() { database, err := sqlx.Open("mysql", "root:@tcp(127.0.0.1:3306)/test") if err != nil { fmt.Println("open mysql failed,", err) return } Db = database }
func main() { r, err := Db.Exec("insert into person(username, sex, email)values(?, ?, ?)", "suoning", "man", "suoning@net263.com") if err != nil { fmt.Println("exec failed, ", err) return } id, err := r.LastInsertId() if err != nil { fmt.Println("exec failed, ", err) return }
fmt.Println("insert succ:", id) } |
(update)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | package main
import ( "fmt"
_ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" )
type Person struct { UserId int `db:"user_id"` Username string `db:"username"` Sex string `db:"sex"` Email string `db:"email"` }
var Db *sqlx.DB
func init() {
database, err := sqlx.Open("mysql", "root:@tcp(127.0.0.1:3306)/test") if err != nil { fmt.Println("open mysql failed,", err) return }
Db = database }
func main() {
_, err := Db.Exec("update person set user_id=? where username=jQuery33106851783089684351_1744753637067", 20170808, "suoning") if err != nil { fmt.Println("exec failed, ", err) return }
} |
(select)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | package main
import ( "fmt"
_ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" )
type Person struct { UserId int `db:"user_id"` Username string `db:"username"` Sex string `db:"sex"` Email string `db:"email"` }
type Place struct { Country string `db:"country"` City string `db:"city"` TelCode int `db:"telcode"` }
var Db *sqlx.DB
func init() {
database, err := sqlx.Open("mysql", "root:@tcp(127.0.0.1:3306)/test") if err != nil { fmt.Println("open mysql failed,", err) return }
Db = database }
func main() {
var person []Person err := Db.Select(&person, "select user_id, username, sex, email from person where user_id=?", 1) if err != nil { fmt.Println("exec failed, ", err) return } fmt.Println("select succ:", person)
people := []Person{} Db.Select(&people, "SELECT * FROM person ORDER BY user_id ASC") fmt.Println(people) jason, john := people[0], people[1] fmt.Printf("%#v\n%#v", jason, john) } |
(delete)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | package main
import ( "fmt"
_ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" )
type Person struct { UserId int `db:"user_id"` Username string `db:"username"` Sex string `db:"sex"` Email string `db:"email"` }
var Db *sqlx.DB
func init() {
database, err := sqlx.Open("mysql", "root:@tcp(127.0.0.1:3306)/test") if err != nil { fmt.Println("open mysql failed,", err) return }
Db = database }
func main() {
_, err := Db.Exec("delete from person where username=? limit 1", "suoning") if err != nil { fmt.Println("exec failed, ", err) return }
fmt.Println("delete succ") } |
事务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | package main
import ( "github.com/astaxie/beego/logs" _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" )
var Db *sqlx.DB
func init() { database, err := sqlx.Open("mysql", "root:@tcp(127.0.0.1:3306)/test") if err != nil { logs.Error("open mysql failed,", err) return } Db = database }
func main() { conn, err := Db.Begin() if err != nil { logs.Warn("DB.Begin failed, err:%v", err) return }
defer func() { if err != nil { conn.Rollback() return } conn.Commit() }()
// do something } |
RabbitMQ
安装
1 | go get "github.com/streadway/amqp" |
普通模式
生产者:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | package main
import ( "fmt" "log" "os" "strings"
"github.com/streadway/amqp" "time")/*默认点对点模式*/func failOnError(err error, msg string) { if err != nil { log.Fatalf("%s: %s", msg, err) panic(fmt.Sprintf("%s: %s", msg, err)) } }
func main() { // 连接 conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/") failOnError(err, "Failed to connect to RabbitMQ") defer conn.Close() // 打开一个并发服务器通道来处理消息 ch, err := conn.Channel() failOnError(err, "Failed to open a channel") defer ch.Close() // 申明一个队列 q, err := ch.QueueDeclare( "task_queue", // name true, // durable 持久性的,如果事前已经声明了该队列,不能重复声明 false, // delete when unused false, // exclusive 如果是真,连接一断开,队列删除 false, // no-wait nil, // arguments ) failOnError(err, "Failed to declare a queue")
body := bodyFrom(os.Args) // 发布 err = ch.Publish( "", // exchange 默认模式,exchange为空 q.Name, // routing key 默认模式路由到同名队列,即是task_queue false, // mandatory false, amqp.Publishing{ // 持久性的发布,因为队列被声明为持久的,发布消息必须加上这个(可能不用),但消息还是可能会丢,如消息到缓存但MQ挂了来不及持久化。 DeliveryMode: amqp.Persistent, ContentType: "text/plain", Body: []byte(body), }) failOnError(err, "Failed to publish a message") log.Printf(" [x] Sent %s", body) }
func bodyFrom(args []string) string { var s string if (len(args) < 2) || os.Args[1] == "" { s = fmt.Sprintf("%s-%v","hello", time.Now()) } else { s = strings.Join(args[1:], " ") } return s } |
消费者:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | package main
import ( "bytes" "fmt" "github.com/streadway/amqp" "log" "time" )
/* 默认点对点模式 工作方,多个,拿发布方的消息 */
func failOnError(err error, msg string) { if err != nil { log.Fatalf("%s: %s", msg, err) panic(fmt.Sprintf("%s: %s", msg, err)) } }
func main() { conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/") failOnError(err, "Failed to connect to RabbitMQ") defer conn.Close()
ch, err := conn.Channel() failOnError(err, "Failed to open a channel") defer ch.Close()
// 指定队列! q, err := ch.QueueDeclare( "task_queue", // name true, // durable false, // delete when unused false, // exclusive false, // no-wait nil, // arguments ) failOnError(err, "Failed to declare a queue")
// Fair dispatch 预取,每个工作方每次拿一个消息,确认后才拿下一次,缓解压力 err = ch.Qos( 1, // prefetch count 0, // prefetch size false, // global ) failOnError(err, "Failed to set QoS")
// 消费根据队列名 msgs, err := ch.Consume( q.Name, // queue "", // consumer false, // auto-ack 设置为真自动确认消息 false, // exclusive false, // no-local false, // no-wait nil, // args ) failOnError(err, "Failed to register a consumer")
forever := make(chan bool)
go func() { for d := range msgs { log.Printf("Received a message: %s", d.Body) dot_count := bytes.Count(d.Body, []byte(".")) t := time.Duration(dot_count) time.Sleep(t * time.Second) log.Printf("Done")
// 确认消息被收到!!如果为真的,那么同在一个channel,在该消息之前未确认的消息都会确认,适合批量处理 // 真时场景:每十条消息确认一次,类似 d.Ack(false) } }()
log.Printf(" [*] Waiting for messages. To exit press CTRL+C") <-forever } |
订阅模式
订阅 生产者:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | package main
import ( "fmt" "github.com/streadway/amqp" "log" "os" "strings" "time" )
/* 广播模式 发布方 */
func failOnError(err error, msg string) { if err != nil { log.Fatalf("%s: %s", msg, err) panic(fmt.Sprintf("%s: %s", msg, err)) } }
func main() { conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/") failOnError(err, "Failed to connect to RabbitMQ") defer conn.Close()
ch, err := conn.Channel() failOnError(err, "Failed to open a channel") defer ch.Close()
// 默认模式有默认交换机,广播自己定义一个交换机,交换机可与队列进行绑定 err = ch.ExchangeDeclare( "logs", // name "fanout", // type 广播模式 true, // durable false, // auto-deleted false, // internal false, // no-wait nil, // arguments ) failOnError(err, "Failed to declare an exchange")
body := bodyFrom(os.Args)
// 发布 err = ch.Publish( "logs", // exchange 消息发送到交换机,这个时候没队列绑定交换机,消息会丢弃 "", // routing key 广播模式不需要这个,它会把所有消息路由到绑定的所有队列 false, // mandatory false, // immediate amqp.Publishing{ ContentType: "text/plain", Body: []byte(body), }) failOnError(err, "Failed to publish a message")
log.Printf(" [x] Sent %s", body) }
func bodyFrom(args []string) string { var s string if (len(args) < 2) || os.Args[1] == "" { s = fmt.Sprintf("%s-%v","hello", time.Now()) } else { s = strings.Join(args[1:], " ") } return s } |
订阅 消费者:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | package main
import ( "fmt" "github.com/streadway/amqp" "log" )
/* 广播模式 订阅方 */
func failOnError(err error, msg string) { if err != nil { log.Fatalf("%s: %s", msg, err) panic(fmt.Sprintf("%s: %s", msg, err)) } }
func main() { conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/") failOnError(err, "Failed to connect to RabbitMQ") defer conn.Close()
ch, err := conn.Channel() failOnError(err, "Failed to open a channel") defer ch.Close()
// 同样要申明交换机 err = ch.ExchangeDeclare( "logs", // name "fanout", // type true, // durable false, // auto-deleted false, // internal false, // no-wait nil, // arguments ) failOnError(err, "Failed to declare an exchange")
// 新建队列,这个队列没名字,随机生成一个名字 q, err := ch.QueueDeclare( "", // name false, // durable false, // delete when usused true, // exclusive 表示连接一断开,这个队列自动删除 false, // no-wait nil, // arguments ) failOnError(err, "Failed to declare a queue")
// 队列和交换机绑定,即是队列订阅了发到这个交换机的消息 err = ch.QueueBind( q.Name, // queue name 队列的名字 "", // routing key 广播模式不需要这个 "logs", // exchange 交换机名字 false, nil) failOnError(err, "Failed to bind a queue")
// 开始消费消息,可开多个订阅方,因为队列是临时生成的,所有每个订阅方都能收到同样的消息 msgs, err := ch.Consume( q.Name, // queue 队列名字 "", // consumer true, // auto-ack 自动确认 false, // exclusive false, // no-local false, // no-wait nil, // args ) failOnError(err, "Failed to register a consumer")
forever := make(chan bool)
go func() { for d := range msgs { log.Printf(" [x] %s", d.Body) } }()
log.Printf(" [*] Waiting for logs. To exit press CTRL+C") <-forever } |
RPC模式
RPC 应答方:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | package main
import ( "fmt" "log" "strconv"
"github.com/streadway/amqp" )
/* RPC模式 应答方 */
func failOnError(err error, msg string) { if err != nil { log.Fatalf("%s: %s", msg, err) panic(fmt.Sprintf("%s: %s", msg, err)) } }
func fib(n int) int { if n == 0 { return 0 } else if n == 1 { return 1 } else { return fib(n-1) + fib(n-2) } }
func main() {
conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/") failOnError(err, "Failed to connect to RabbitMQ") defer conn.Close()
ch, err := conn.Channel() failOnError(err, "Failed to open a channel") defer ch.Close()
q, err := ch.QueueDeclare( "rpc_queue", // name false, // durable false, // delete when usused false, // exclusive false, // no-wait nil, // arguments ) failOnError(err, "Failed to declare a queue")
// 公平分发 没有这个则round-robbin err = ch.Qos( 1, // prefetch count 0, // prefetch size false, // global ) failOnError(err, "Failed to set QoS")
// 消费,等待请求 msgs, err := ch.Consume( q.Name, // queue "", // consumer false, // auto-ack false, // exclusive false, // no-local false, // no-wait nil, // args ) failOnError(err, "Failed to register a consumer")
forever := make(chan bool)
go func() { //请求来了 for d := range msgs { n, err := strconv.Atoi(string(d.Body)) failOnError(err, "Failed to convert body to integer")
log.Printf(" [.] fib(%d)", n)
// 计算 response := fib(n)
// 回答 err = ch.Publish( "", // exchange d.ReplyTo, // routing key false, // mandatory false, // immediate amqp.Publishing{ ContentType: "text/plain", CorrelationId: d.CorrelationId, //序列号 Body: []byte(strconv.Itoa(response)), }) failOnError(err, "Failed to publish a message")
// 确认回答完毕 d.Ack(false) } }()
log.Printf(" [*] Awaiting RPC requests") <-forever } |
RPC 请求方:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | package main
import ( "fmt" "log" "math/rand" "os" "strconv" "strings" "time"
"github.com/streadway/amqp" )
/* RPC模式 请求方 */
func failOnError(err error, msg string) { if err != nil { log.Fatalf("%s: %s", msg, err) panic(fmt.Sprintf("%s: %s", msg, err)) } }
func randomString(l int) string { bytes := make([]byte, l) for i := 0; i < l; i++ { bytes[i] = byte(randInt(65, 90)) } return string(bytes) }
func randInt(min int, max int) int { return min + rand.Intn(max-min) }
func fibonacciRPC(n int) (res int, err error) {
conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/") failOnError(err, "Failed to connect to RabbitMQ") defer conn.Close()
ch, err := conn.Channel() failOnError(err, "Failed to open a channel") defer ch.Close()
// 队列声明 q, err := ch.QueueDeclare( "", // name false, // durable false, // delete when usused true, // exclusive 为真即连接断开就删除 false, // noWait nil, // arguments ) failOnError(err, "Failed to declare a queue")
msgs, err := ch.Consume( q.Name, // queue "", // consumer true, // auto-ack false, // exclusive 这个为真,服务器会认为这是该队列唯一的消费者 false, // no-local false, // no-wait nil, // args ) failOnError(err, "Failed to register a consumer")
corrId := randomString(32)
err = ch.Publish( "", // exchange "rpc_queue", // routing key false, // mandatory false, // immediate amqp.Publishing{ ContentType: "text/plain", CorrelationId: corrId, ReplyTo: q.Name, Body: []byte(strconv.Itoa(n)), }) failOnError(err, "Failed to publish a message")
for d := range msgs { if corrId == d.CorrelationId { res, err = strconv.Atoi(string(d.Body)) failOnError(err, "Failed to convert body to integer") break } }
return }
func main() { rand.Seed(time.Now().UTC().UnixNano())
n := bodyFrom(os.Args)
log.Printf(" [x] Requesting fib(%d)", n) res, err := fibonacciRPC(n) failOnError(err, "Failed to handle RPC request")
log.Printf(" [.] Got %d", res) }
func bodyFrom(args []string) int { var s string if (len(args) < 2) || os.Args[1] == "" { s = "30" } else { s = strings.Join(args[1:], " ") } n, err := strconv.Atoi(s) failOnError(err, "Failed to convert arg to integer") return n } |
推荐:golang
关注公众号:拾黑(shiheibook)了解更多
友情链接:
下软件就上简单下载站:https://www.jdsec.com/
四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/