云数据库 Redis
  • 产品发布记录
  • 新手引导
  • 产品简介

  • 购买指南

  • 快速入门

  • 操作指南

  • 性能白皮书
  • API文档

  • 最佳实践

    • 消息发布订阅
    • 管道传输
    • 事务处理
      • 场景介绍
      • 代码示例
  • 常见问题

  • 故障处理

  • 服务条款
  • 相关概念
  • 联系我们
  • 云数据库Redis
  • 最佳实践
云数据库 Redis

云数据库Redis是首云提供的兼容开源Redis协议标准、基于键值对形式存储的内存数据库服务,具有高可用、高可靠、弹性扩展等特点。支持主从和集群两种架构,可实现亚毫秒级响应时间,每秒处理数十万个请求,可满足高吞吐、低延迟及弹性变配等业务需求。

  • 产品简介
    • 产品概述

    • 产品优势

    • 应用场景

    • 产品系列

    • 命令支持

    • 地域与可用区

  • 购买指南
    • 计费概述

    • 购买方式

    • 欠费说明

    • 调整实例规格费用说明

  • 快速入门
    • 创建Redis实例

    • 设置白名单

    • 连接Redis实例

  • 操作指南
    • 使用限制

    • 操作总览

    • 管理实例

    • 连接实例

    • 网络与安全

    • 备份与恢复

    • 数据迁移

    • 监控告警

    • 账号与密码

    • 参数配置

    • 禁用命令

    • 标签管理

  • API文档
    • 认证方式

    • API概览

    • 实例相关接口

    • 备份相关接口

    • 错误码

  • 最佳实践
    • 消息发布订阅

    • 管道传输

    • 事务处理

  • 常见问题
    • 购买计费

    • 连接登录

    • 使用数据库

    • 监控报警

    • 持久化

    • 缓存策略

  • 故障处理
    • Redis无法连接

    • 使用Csredis客户端时出现Unexpected end of stream异常

    • 使用redis-py客户端时连接集群时报错

    • 使用Jedis客户端时出现Unexpected end of stream异常

    • 使用Jedis客户端时出现OOM异常

    • 如何处理大key问题

事务处理

最后更新时间:2022-01-13 生成PDF文件 | 前往GitHub编辑

# 场景介绍

云数据库Redis支持事务(transaction)机制。Redis事务是一组命令的集合,事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。事务属于原子操作,即事务中的命令要么全部被执行,要么全部都不执行。

Redis事务命令包括:MULTI,EXEC,DISCARD,WATCH,UNWATCH。

注意:

Redis中定义的事务,并不是关系数据库中严格意义上的事务。当Redis事务中的某个操作执行失败,或者用DISCARD取消事务时候,Redis不会执行事务回滚。

# 代码示例

  • 两个client操作相同的key
import java.util.List;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
public class RedisTranscationTest {
    static final String host = "10.XX.XX.13";
    static final int port = 9736;
    static final String password = "password";
    //**注意这两个key的内容是相同的
    static String client1_key = "Redis-Transcation-1";
    static String client2_key = "Redis-Transcation-1";
    public static void main(String[] args) {
        Jedis jedis = new Jedis(host, port);
        // Redis的实例密码
        String authString = jedis.auth(password);//password
        if (!authString.equals("OK")) {
            System.err.println("认证失败: " + authString);
            jedis.close();
            return;
        }
        jedis.set(client1_key, "0");
        // 启动另一个thread,模拟另外的client
        new RedisTranscationTest().new OtherRedisClient().start();
        Thread.sleep(500);
        Transaction tx = jedis.multi();//开始事务
        // 以下操作会集中提交服务器端处理,作为“原子操作”
        tx.incr(client1_key);
        tx.incr(client1_key);
        Thread.sleep(400);//此处Thread的暂停对事务中前后连续的操作并无影响,其他Thread的操作也无法执行
        tx.incr(client1_key);
        Thread.sleep(300);//此处Thread的暂停对事务中前后连续的操作并无影响,其他Thread的操作也无法执行
        tx.incr(client1_key);
        Thread.sleep(200);//此处Thread的暂停对事务中前后连续的操作并无影响,其他Thread的操作也无法执行
        tx.incr(client1_key);
        List<Object> result = tx.exec();//提交执行
        // 解析并打印出结果
        for(Object rt : result){
            System.out.println("Client 1 > 事务中> "+rt.toString());
        }
        jedis.close();
    }
    class OtherRedisClient extends Thread{
        @Override
        public void run() {
            Jedis jedis = new Jedis(host, port);
            // Redis的实例密码
            String authString = jedis.auth(password);// password
            if (!authString.equals("OK")) {
                System.err.println("AUTH Failed: " + authString);
                jedis.close();
                return;
            }
            jedis.set(client2_key, "100");
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Client 2 > "+jedis.incr(client2_key));
            }
            jedis.close();
        }
    }
}
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

在输入了正确的云数据库Redis版实例访问地址和密码之后,运行以上Java程序,输出结果如下:

Client 2 > 101
Client 2 > 102
Client 2 > 103
Client 2 > 104
Client 1 > 事务中> 105
Client 1 > 事务中> 106
Client 1 > 事务中> 107
Client 1 > 事务中> 108
Client 1 > 事务中> 109
Client 2 > 110
Client 2 > 111
Client 2 > 112
Client 2 > 113
Client 2 > 114
Client 2 > 115
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

您可以看到不同线程中的两个client在操作同一个key,但是当client1利用事务机制来操作这个key时,client2被阻塞不得不等待client1事务中的操作完全执行完毕。

  • 两个client操作不同的key

对以上的代码稍作改动,使得两个client操作不同key,其余部分保持不变。

import java.util.List;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
public class RedisTranscationTest {
    static final String host = "10.XX.XX.13";
    static final int port = 9736;
    static final String password = "password";
    //**注意这两个key的内容是不同的
    static String client1_key = "Redis-Transcation-1";
    static String client2_key = "Redis-Transcation-2";
    public static void main(String[] args) {
        Jedis jedis = new Jedis(host, port);
        // Redis的实例密码
        String authString = jedis.auth(password);//password
        if (!authString.equals("OK")) {
            System.err.println("认证失败: " + authString);
            jedis.close();
            return;
        }
        jedis.set(client1_key, "0");
        // 启动另一个thread,模拟另外的client
        new RedisTranscationTest().new OtherRedisClient().start();
        Thread.sleep(500);
        Transaction tx = jedis.multi();//开始事务
        // 以下操作会集中提交服务器端处理,作为“原子操作”
        tx.incr(client1_key);
        tx.incr(client1_key);
        Thread.sleep(400);//此处Thread的暂停对事务中前后连续的操作并无影响,其他Thread的操作也无法执行
        tx.incr(client1_key);
        Thread.sleep(300);//此处Thread的暂停对事务中前后连续的操作并无影响,其他Thread的操作也无法执行
        tx.incr(client1_key);
        Thread.sleep(200);//此处Thread的暂停对事务中前后连续的操作并无影响,其他Thread的操作也无法执行
        tx.incr(client1_key);
        List<Object> result = tx.exec();//提交执行
        // 解析并打印出结果
        for(Object rt : result){
            System.out.println("Client 1 > 事务中> "+rt.toString());
        }
        jedis.close();
    }
    class OtherRedisClient extends Thread{
        @Override
        public void run() {
            Jedis jedis = new Jedis(host, port);
            // Redis的实例密码
            String authString = jedis.auth(password);// password
            if (!authString.equals("OK")) {
                System.err.println("AUTH Failed: " + authString);
                jedis.close();
                return;
            }
            jedis.set(client2_key, "100");
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Client 2 > "+jedis.incr(client2_key));
            }
            jedis.close();
        }
    }
}
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

运行修改后的此Java程序,输出结果如下:

Client 2 > 101
Client 2 > 102
Client 2 > 103
Client 2 > 104
Client 1 > 事务中> 1
Client 1 > 事务中> 2
Client 1 > 事务中> 3
Client 1 > 事务中> 4
Client 1 > 事务中> 5
Client 2 > 105
Client 2 > 106
Client 2 > 107
Client 2 > 108
Client 2 > 109
Client 2 > 110
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

您从中可以看到client1和 client2在两个不同的Thread中,client1所提交的事务操作都是集中顺序执行的,在此期间尽管client2是对另外一个key进行操作,它的命令操作也都被阻塞等待,直至client1事务中的全部操作执行完毕。

管道传输
购买计费

← 管道传输 购买计费→

最近更新
01
_index
08-18
02
将备份数据迁移至首云Redis
07-11
03
监控概览
04-08
更多文章>

版权所有 ©2005 - 2024 Capitalonline Data Service Co., Ltd 备案序号:京ICP备06033943号 京公网安备:11010502020343号

北京首都在线科技股份有限公司(总部) 经营许可证:B1.B2-20140358 上海红之盟网络科技有限公司(首都在线全资子公司) 经营许可证:B1-20194861