今天带着学生学习了Redis的事务功能,Redis的事务与传统的关系型数据库(如MySQL)有所不同,Redis的事务不能回滚。

Redis中使用multi、exec、discard、watch、unwatch等命令来操作事务。

例如:

> MULTI

OK

> INCR aaa

QUEUED

> INCR bbb

QUEUED

> EXEC

1) (integer) 1

2) (integer) 1

multi命令表示启动事务(begin transaction),exec表示执行事务(commit),如果中间的操作有错误,有两种情形:

1.语法错误,表现为在EXEC执行前,命令不能正常添加到Queue中。例如,命令出现语法错误等。
2. 代码在执行的时候错误,表现为在EXEC执行后,命令不能正确执行。例如,将string当做list操作。此种操作比较奇怪,在redis事务中,并不会因为中间失败了导致整个不能执行,而是将正确的部分执行了。有种观点认为 Redis 处理事务的做法会产生 bug ,然而需要注意的是,在通常情况下,回滚并不能解决编程错误带来的问题,并且这类错误通常不会在生产环境中出现,所以 Redis 选择了更简单、更快速的无回滚方式来处理事务。

那么这种事务如何去实现秒杀功能呢。答案是使用watch,watch能监控某一个key的变化,在事务执行时,如果其他的client改变了这个可以所对应的值,将会导致当前client的事务不执行,即类似于乐观锁机制。

示例代码如下:

首先没有watch的代码:

示例为有10张优惠券,有多人来抢,需要提供秒杀功能。

首先在redis中设置一个key为num值为0:

命令为:set num 0

public class MyThread extends Thread {

@Override

public void run() {

for (int i = 0; i < 10; i++){

Jedis jedis = RedisConnection.getJedis();

String num = jedis.get("num");

int n = Integer.parseInt(num);

if (n < 10){

try {

Thread.sleep(1);

} catch (InterruptedException e) {

e.printStackTrace();

}

jedis.incr("num");

String name = UUID.randomUUID().toString().replaceAll("-", "");

System.out.println(name + "抢到一张优惠券");

}

}

}

}

public class TestMain {

public static void main(String[] args) {

for (int i = 0; i < 5; i++){

MyThread thread = new MyThread();

thread.start();

}

}

}

当执行这种代码时,会发现会有超过10个人抢到优惠券。

加入watch时,代码如下,修改Mythred类:

public class MyThread extends Thread {

@Override

public void run() {

for (int i = 0; i < 10; i++){

Jedis jedis = RedisConnection.getJedis();

String watch = jedis.watch("num");

String num = jedis.get("num");

int n = Integer.parseInt(num);

if (n < 10){

try {

Thread.sleep(1);

} catch (InterruptedException e) {

e.printStackTrace();

}

Transaction transaction = jedis.multi();

transaction.incr("num");

List<Object> list = transaction.exec();

String name = UUID.randomUUID().toString().replaceAll("-", "");

if (list == null || list.size() == 0){

System.out.println(watch + "==="+list+"----" + name + "手慢了,抢票失败");

}else {

System.out.println(watch + "==="+list+"----" + name + "抢到一张优惠券");

}

}

}

}

}

测试结果,你会发现,虽然一样会有多人去抢,但是始终只有10个人能正取的抢到。

Redis事务和实现秒杀功能的实现的更多相关文章

  1. php+redis实现电商秒杀功能

    这一次总结和分享用Redis实现分布式锁来完成电商的秒杀功能.先扯点个人观点,之前我看了一篇博文说博客园的文章大部分都是分享代码,博文里强调说分享思路比分享代码更重要(貌似大概是这个意思,若有误请谅解 ...

  2. redis使用watch完成秒杀抢购功能

    Redis使用watch完成秒杀抢购功能: 使用redis中两个key完成秒杀抢购功能,mywatchkey用于存储抢购数量和mywatchlist用户存储抢购列表. 它的优点如下: 1. 首先选用内 ...

  3. redis使用watch完成秒杀抢购功能(转)

    redis使用watch完成秒杀抢购功能: 使用redis中两个key完成秒杀抢购功能,mywatchkey用于存储抢购数量和mywatchlist用户存储抢购列表. 它的优点如下: 1. 首先选用内 ...

  4. redis使用watch完成秒杀抢购功能:

    redis使用watch完成秒杀抢购功能: 使用redis中两个key完成秒杀抢购功能,mywatchkey用于存储抢购数量和mywatchlist用户存储抢购列表. 它的优点如下: 1. 首先选用内 ...

  5. thinkphp+redis实现秒杀功能

    好久没来整理文章了,闲了没事写篇文章记录下php+redis实现商城秒杀功能. 1,安装redis,根据自己的php版本安装对应的redis扩展(此步骤简单的描述一下) 1.1,安装 php_igbi ...

  6. Redis分布式锁实现简单秒杀功能

    这版秒杀只是解决瞬间访问过高服务器压力过大,请求速度变慢,大大消耗服务器性能的问题. 主要就是在高并发秒杀的场景下,很多人访问时并没有拿到锁,所以直接跳过了.这样就处理了多线程并发问题的同时也保证了服 ...

  7. spring boot:redis+lua实现生产环境中可用的秒杀功能(spring boot 2.2.0)

    一,秒杀需要具备的功能: 秒杀通常是电商中用到的吸引流量的促销活动方式 搭建秒杀系统,需要具备以下几点: 1,限制每个用户购买的商品数量,(秒杀价格为吸引流量一般会订的很低,不能让一个用户全部抢购到手 ...

  8. flask+redis实现抢购(秒杀)功能

    今天面试了 一家非常高大上的公司,问了我关于redis的实用性问题,但是答的不是很好,所以下午通过再次学习 redis,实现相关实用性功能的一种. 对于抢购功能,难点在于 抢购时 由于高并发请求,导致 ...

  9. redis 事务 及发布于订阅功能

    事务: Redis事务可以一次执行多个命令,事务具有以下特征: 1.隔离操作:事务中的所有命令都会序列化.按顺序地执行,不会被其他命令打扰. 2.原子操作:事务中的命令要么全部被执行,要么全部都不执行 ...

随机推荐

  1. vue双向数据绑定

    本文来源于 https://jingyan.baidu.com/article/91f5db1b0c2a4f1c7f05e3a8.html

  2. [Oracle][DATAGUARD]关于REDO_TRANSPORT_USER参数

    大家可能已经知道,在Oracle的DATAGUARD(这里指的是PHYSICAL STANDBY)环境中,Primary端会把生成的REDO传到Standby端,然后由Standby端的MRP进程应用 ...

  3. 安装CaffeOnSpark过程中遇到的问题及解决方案

    安装教程来自 http://blog.csdn.net/sadonmyown/article/details/72781393 首先,我使用的节点环境是ubuntu 16.04.1,事先 成功安装了s ...

  4. 报表工具highcharts使用心得

    公司让做一个报表页面,搜索了下发现highcharts比较符合业务需求,下面就说一下使用心得. $('#container').highcharts({ title: { text: '部门统计图' ...

  5. vivado封装IP

    reference: https://www.cnblogs.com/mouou/p/5851736.html   1.新建一个测试工程 工程化的设计方法是离不开工程的,第一步往往都是新建工程,后面我 ...

  6. .net webService保存全局变量中

    遇到坑,然后找到解决方案,我就习惯做个记录. 情景:通过webservice调用一个第三方的库,在初始化第三方库的时候需要花费较长时间 目的:希望通过初始化一次,缓存下来,下次直接调用,而不必每次初始 ...

  7. 自己动手写CPU——寄存器堆、数据存储器(基于FPGA与Verilog)

    上一篇写的是基本的设计方案,由于考研复习很忙,不知道下一次什么时候才能打开博客,今天就再写一篇.写一写CPU中涉及到RAM的部件,如寄存器堆.数据存储器等. 大家应该在大一刚接触到计算机的时候就知道R ...

  8. hibernate基本的配置与验证

    导入jar包与mysql驱动包 javaBean src/com/crazyit/app/domain/News.java package com.crazyit.app.domain; import ...

  9. oracle中创建数据库

    一.在Oracle中创建数据库之前先改一下虚拟机的IP地址,以便访问 2. 3. 3.1 3.2 3.3 3.4 创建完成:输入sqlplus sys/123456 as sysdba测试

  10. DFS和BFS

    BFS 代码步骤: 1.写出每个点和每个点的邻接点的对应关系 2.方法参数:传一个对应关系和起始点 3.创建一个队列,然后每次都移除第一个,然后把移除的邻接点添加进去,打印取出的第一个,然后循环,一直 ...