mirror of
https://github.com/Luzifer/cloudkeys-go.git
synced 2024-11-14 08:52:44 +00:00
105 lines
2.7 KiB
Go
105 lines
2.7 KiB
Go
|
package goredis
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
)
|
||
|
|
||
|
// Transaction doc: http://redis.io/topics/transactions
|
||
|
// MULTI, EXEC, DISCARD and WATCH are the foundation of transactions in Redis.
|
||
|
// A Redis script is transactional by definition,
|
||
|
// so everything you can do with a Redis transaction, you can also do with a script,
|
||
|
// and usually the script will be both simpler and faster.
|
||
|
type Transaction struct {
|
||
|
redis *Redis
|
||
|
conn *connection
|
||
|
}
|
||
|
|
||
|
// Transaction new a *transaction from *redis
|
||
|
func (r *Redis) Transaction() (*Transaction, error) {
|
||
|
c, err := r.pool.Get()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if err := c.SendCommand("MULTI"); err != nil {
|
||
|
r.pool.Put(c)
|
||
|
return nil, err
|
||
|
}
|
||
|
if _, err := c.RecvReply(); err != nil {
|
||
|
r.pool.Put(c)
|
||
|
return nil, err
|
||
|
}
|
||
|
return &Transaction{r, c}, nil
|
||
|
}
|
||
|
|
||
|
// Close closes the transaction, put the under connection back for reuse
|
||
|
func (t *Transaction) Close() {
|
||
|
t.redis.pool.Put(t.conn)
|
||
|
}
|
||
|
|
||
|
// Discard flushes all previously queued commands in a transaction
|
||
|
// and restores the connection state to normal.
|
||
|
// If WATCH was used, DISCARD unwatches all keys.
|
||
|
func (t *Transaction) Discard() error {
|
||
|
if err := t.conn.SendCommand("DISCARD"); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
_, err := t.conn.RecvReply()
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// Watch marks the given keys to be watched for conditional execution of a transaction.
|
||
|
func (t *Transaction) Watch(keys ...string) error {
|
||
|
args := packArgs("WATCH", keys)
|
||
|
if err := t.conn.SendCommand(args...); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
_, err := t.conn.RecvReply()
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// UnWatch flushes all the previously watched keys for a transaction.
|
||
|
// If you call EXEC or DISCARD, there's no need to manually call UNWATCH.
|
||
|
func (t *Transaction) UnWatch() error {
|
||
|
if err := t.conn.SendCommand("UNWATCH"); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
_, err := t.conn.RecvReply()
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// Exec executes all previously queued commands in a transaction
|
||
|
// and restores the connection state to normal.
|
||
|
// When using WATCH, EXEC will execute commands only if the watched keys were not modified,
|
||
|
// allowing for a check-and-set mechanism.
|
||
|
func (t *Transaction) Exec() ([]*Reply, error) {
|
||
|
if err := t.conn.SendCommand("EXEC"); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
rp, err := t.conn.RecvReply()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return rp.MultiValue()
|
||
|
}
|
||
|
|
||
|
// Command send raw redis command to redis server
|
||
|
// and redis will return QUEUED back
|
||
|
func (t *Transaction) Command(args ...interface{}) error {
|
||
|
args2 := packArgs(args...)
|
||
|
if err := t.conn.SendCommand(args2...); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
rp, err := t.conn.RecvReply()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
s, err := rp.StatusValue()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if s != "QUEUED" {
|
||
|
return errors.New(s)
|
||
|
}
|
||
|
return nil
|
||
|
}
|