Redis事务和实现秒杀功能的实现

今天带着学生学习了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个人能正取的抢到。

猜你喜欢

转载自www.cnblogs.com/qfchen/p/10672161.html