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. .net core 微服务参考文章

    网址: https://www.cnblogs.com/edisonchou/p/9124985.html Tip: 此篇已加入.NET Core微服务基础系列文章索引 一.Consul基础介绍 Co ...

  2. 个人笔记-----Vue中多个router-view应用

    单个 <router-view/> 和多个 <router-view/> 的区别,单个 <router-view/> 只是一个区域的变化,不需要设置name属性,在 ...

  3. TCP三次握手中SYN,ACK,Seq含义

    TCP(Transmission Control Protocol)传输控制协议 TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接: 位码即tcp标志位,有6种标示 ...

  4. WPF 中的 路由事件

    public class ReportTimeEventArgs:RoutedEventArgs { public ReportTimeEventArgs(RoutedEvent routedEven ...

  5. C#基础知识---?为何物

    一. 可空类型修饰符(?)引用类型可以使用空引用表示一个不存在的值,而值类型通常不能表示为空.例如:string str=null; 是正确的,int i=null; 编译器就会报错.可空类型的出现, ...

  6. WPF---数据模板(一)

    一.场景模拟 假设我们现在有如下需求: 我们需要在ListBox中的每个Item中显示某个成员的姓名.年龄以及喜欢的颜色,点击Item的时候,会在右边显示详细信息,同时也想让ListBox的样式变得好 ...

  7. MongoDB学习笔记三 - MongooseAPI操作数据

    在上一篇我们讲了如何通过Mongoose想数据库动态添加数据, 接下来我们一起来看一下如何通过Mongoose来对数据库进行增删改查等一系列操作 Model 对象的方法 remove(cinditio ...

  8. CentOS_Server with GUI入门

    安装模式: Server with GUI:基本的桌面系统,包括常用的桌面软件,如文档查看工具 Minimal:基本的系统,不含有任何可选的软件包 Basic Server :安装的基本系统的平台支持 ...

  9. php ltrim() rtrim() trim()删除字符空格

    php$str=" 去除前后空格 ";echo "方括号中为原始字符串:[".$str."]";echo "原始字符串长度:&qu ...

  10. BeanUtils基本使用方法与原理

    使用BeanUtils的原因 因为setProperty是JSP中的标签,因此使用model 2模式JSP+Servlet+JavaBean的时候,JSP将form提交给Servlet程序,而Serv ...