Redis事务

  • 原子性:就是最小的单位
  • 一致性:好多命令,要么全部执行成功,要么全部执行失败
  • 隔离性:一个会话和另一个会话之间是互相隔离的
  • 持久性:执行了就执行了,数据保存在硬盘上

典型例子:银行转账,A给B转账100万,首先要A的账户减去100万,然后B的账户增加100万,如果中间断了那就出问题了。所以我们人为的将这件事进行原子化,做成一个最小单位。要么一起成功要么一起失败。

redis是一种简单的数据存储形式,redis的事务是不支持回滚的。

之前的sqlserver的事务,开了一个事务,去修改表的数据。然后有一个新的会话,或者新的连接,这个时候如果我们这儿连接去修改或者查询这个表时,可能会一直等待,直到事务操作完毕。

而redis则不然,如果同样的操作使用redis事务的话,会导致事务操作失败。redis在开启事务前监听了3个要修改key的版本号,如果在这个事务期间,其他的连接可以修改这3个key对应的值,但是会影响当前开启事务这个会话的操作,让事务提交不成功。

//事务模式
using (RedisClient client = new RedisClient("127.0.0.1", 6379, "12345", 10))
{
//删除当前数据库中的所有Key 默认删除的是db0
client.FlushDb();
//删除所有数据库中的key
//client.FlushAll(); client.Set("a", "1");
client.Set("b", "1");
client.Set("c", "1"); //获取当前这三个key的版本号 实现事务
client.Watch("a", "b", "c");
using (var trans = client.CreateTransaction())
{
trans.QueueCommand(p => p.Set("a", "3"));
trans.QueueCommand(p => p.Set("b", "3"));
trans.QueueCommand(p => p.Set("c", "3"));
//提交事务 如果在触发事务过程中,其他进程操作了当前的key,则事务提交失败,就是没有指令没有修改成功
var flag = trans.Commit();
// ID KEY
Console.WriteLine(flag);
}
//根据key取出值,返回string
Console.WriteLine(client.Get<string>("a") + ":" + client.Get<string>
("b") + ":" + client.Get<string>
("c"));
Console.ReadLine();
}

所以,在redis使用事务的情况下,必须使用watch进行监听一下对应的key值,凡是需要事务操作的key,都要包含在watch里面进行监听。

单线程理解误区:(看代码)

//单线程理解误区
using (RedisClient client1 = new RedisClient("127.0.0.1", 6379, "12345", 10))
{
//删除当前数据库中的所有Key 默认删除的是db0
client1.FlushDb();
//删除所有数据库中的key
//client.FlushAll(); client1.Del("number"); for (int i = 0; i < 10; i++)
{
Task.Run(() =>
{
using (RedisClient client = new RedisClient("127.0.0.1", 6379, "12345", 10))
{
if (client.Get("number") == null)
{
Console.WriteLine("number == null");
client.Set<string>("number", "100");
}
else
{
Console.WriteLine("number != null");
}
}
});
}
}
Console.ReadLine();

在我的电脑上最终打印结果:

number == null
number == null
number == null
number == null
number != null
number != null
number != null
number != null
number != null
number != null

这里面的语句(if (client.Get("number") == null))会出现4次执行成功,这会误导我们对单线程的理解。说明进入这个判断时,有4个同时进入了,这4个获取过程会排队到redis里面,redis会一个个的进行执行,那么这4个就都是成功的,所以会有4次成功执行,而这4次执行完之后,key就被赋值了,其他线程进入时,就会不为null。这里面的单线程指的是redis执行的过程,而不是程序中线程执行的过程。如果想要只进入一次,就需要对这个过程加锁。(我的理解是,因为我的CPU是2核4线程,所以会有4个线程同时进入)

//单线程理解误区
using (RedisClient client1 = new RedisClient("127.0.0.1", 6379, "12345", 10))
{
//删除当前数据库中的所有Key 默认删除的是db0
client1.FlushDb();
//删除所有数据库中的key
//client.FlushAll(); client1.Del("number"); for (int i = 0; i < 10; i++)
{
Task.Run(() =>
{
using (RedisClient client = new RedisClient("127.0.0.1", 6379, "12345", 10))
{
lock ("123")
{
if (client.Get("number") == null)
{
Console.WriteLine("number == null");
client.Set<string>("number", "100");
}
else
{
Console.WriteLine("number != null");
}
}
}
});
}
}
Console.ReadLine();

Redis之品鉴之旅(五)的更多相关文章

  1. Redis之品鉴之旅(一)

    Redis之品鉴之旅(一) 好知识就如好酒,需要我们坐下来,静静的慢慢的去品鉴.Redis作为主流nosql数据库,在提升性能的方面是不可或缺的.下面就拿好小板凳,我们慢慢的来一一品鉴. 1)redi ...

  2. Redis之品鉴之旅(七)

    分布式锁 1)阻塞锁: 尝试在redis中创建一个字符串结构缓存,方法传入的key,value为锁的过期时间timeout的时间戳. 若redis中没有这个key,则创建成功(即抢到锁),然后立即返回 ...

  3. Redis之品鉴之旅(六)

    持久化 快照的方式(RDB) 文件追加方式(AOF) 快照形式: save和bgsave能快速的备份数据.但是.........., Save命令:将内存数据镜像保存为rdb文件,由于redis是单线 ...

  4. Redis之品鉴之旅(二)

    2)hash类型,上代码 using (RedisClient client = new RedisClient("127.0.0.1", 6379, "12345&qu ...

  5. Redis之品鉴之旅(四)

    发布订阅,简单场景下的发布订阅完全可以使用. 可以简单的理解,将一个公众号视为发布者,关注公众号的人视作订阅者,公众号发布一条文章或者消息,凡事订阅公众号的都可以收到消息.一个人可以订阅多个公众号,一 ...

  6. Redis之品鉴之旅(三)

    3)Set,可以去重的.无序的集合.可以取交集.并集.zset(sorted set),有序的.去重的集合,排序不是根据value排序,而是根据score排序. using (RedisClient ...

  7. redis成长之路——(五)

    单例.哨兵.Cluster redis应用广泛,主要体现于实际场景的可用化,但是对于码农来说初步入手很多理念难以理解:码农的想法就是:为什么我要管那么多,我只想用,能用就行!所以必须将三个场景透明化. ...

  8. Redis源码阅读(五)集群-故障迁移(上)

    Redis源码阅读(五)集群-故障迁移(上) 故障迁移是集群非常重要的功能:直白的说就是在集群中部分节点失效时,能将失效节点负责的键值对迁移到其他节点上,从而保证整个集群系统在部分节点失效后没有丢失数 ...

  9. Redis数据结构详解,五种数据结构分分钟掌握

    redis数据类型分为:字符串类型.散列类型.列表类型.集合类型.有序集合类型.redis这么火,它运行有多块?一台普通的笔记本电脑,可以在1秒钟内完成十万次的读写操作.原子操作:最小的操作单位,不能 ...

随机推荐

  1. MVVMLight学习笔记(六)---DispatchHelper更新UI

    一.概述 在应用程序中,线程可以被看做是应用程序的一个较小的执行单位.每个应用程序都至少拥有一个线程,我们称为主线程.当调用和操作主线程的时候,该操作将动作添加到一个队列中,每个操作均按照将它们添加到 ...

  2. C++继承体系中的内存对齐

    本篇随笔讨论一个比较冷门的知识,继承结构中内存对齐的问题,如今内存越来越大也越来越便宜,大部分人都已经不再关注内存对齐的问题了.但是作为一个有追求的技术人员,实现功能永远都是最基本的要求,把代码优化到 ...

  3. vue2.0中模拟数据的配置

    在开发过程中,有时候接口跟不上我们的进度,我们要测试,就需要自测. 现在vue已经升级到2.0版本了,早期在vue构建工程文件在build里面有dev-server.js,但是后来构建去除了该文件集成 ...

  4. transient用法

    1 import java.io.FileInputStream; 2 import java.io.FileNotFoundException; 3 import java.io.FileOutpu ...

  5. 二进制I/O

    1 import java.io.BufferedInputStream; 2 import java.io.BufferedOutputStream; 3 import java.io.DataIn ...

  6. opencv入门系列教学(五)图像的基本操作(像素值、属性、ROI和边框)

    0.序言 每个图像是由一个个点组成的,而这些点可以表示为像素值的形式. 这篇博客里我们将学会: 访问像素值并修改它们 . 访问图像属性 . 设置感兴趣区域(ROI) . 分割和合并图像. 对于图像的基 ...

  7. docker PXC MYSQL集群节点启动失败/节点顺序消失/只剩一个节点存在问题的解决

    转载于:https://my.oschina.net/u/4884318/blog/4908669 大牛 佩服此人 截取本人遇到的问题: "error:0407008A:rsa routin ...

  8. java深度复制

    索要克隆的类必须实现:Serializable,Cloneable接口import java.io.ByteArrayInputStream; import java.io.ByteArrayOutp ...

  9. 在Raspberry Pi 3B+上安装Windows 10 IoT

    下载 进入树莓派下载页面,当前网址https://www.raspberrypi.org/downloads/ 选择Windows 10 IoT Core,当前网址https://docs.micro ...

  10. Python3实现打格点算法的GPU加速

    技术背景 在数学和物理学领域,总是充满了各种连续的函数模型.而当我们用现代计算机的技术去处理这些问题的时候,事实上是无法直接处理连续模型的,绝大多数的情况下都要转化成一个离散的模型再进行数值的计算.比 ...