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();

最新文章

  1. 3.1 js基本概念
  2. Linux 系统命令
  3. Python绘图
  4. Java线程间通信方式剖析——Java进阶(四)
  5. hibernate报错Unknown integral data type for ids : java.lang.String
  6. 根据上一行填充本行的空白栏位,SQL处理方式
  7. JSON序列化和反序列化的实例
  8. Problem K 栈
  9. DNS劫持和DNS污染解决办法
  10. mysql基本定义--数据类型
  11. 按键消抖VERILOG实现
  12. 操作cookie
  13. agentzh --春哥--调试专家
  14. 加入BOINC(伯克利开放式网络计算平台)
  15. LaTeX笔记
  16. Java 彩色图转灰度图
  17. [Luogu1801] 黑匣子 - Treap
  18. 第一周——数据分析之表示 —— Numpy入门
  19. KeyValuePair 和 Dictionary 的关系和区别
  20. P1081 开车旅行(Not Finish)

热门文章

  1. 【springcloud】配置中心(Config-Server)
  2. java中的静态内部类
  3. pyspark启动与简单使用----本地模式(local)----shell
  4. git 使用代理出现 LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to github.com:443 错误
  5. 常用cron表达式
  6. Jenkins手动下载并安装插件
  7. Docker数据映射
  8. 20210715 noip16
  9. shell脚本测试变量是否为空,测试文件是否存在,sed修改配置文件参数,分支语句
  10. JS021. 拦截事件的显式处理与默认动作(Web API: event.preventDefault)