redis实现商城秒杀活动

  |  

介绍

1、使用watch,采用乐观锁
2、不使用悲观锁,因为等待时间非常长,响应慢
3、不使用队列,因为并发量会让队列内存瞬间升高

Redis事务
Redis中的事务(transaction)是一组命令的集合。事务同命令一样都是Redis最小的执行单
位,一个事务中的命令要么都执行,要么都不执行。Redis事务的实现需要用到 MULTI 和
EXEC 两个命令,事务开始的时候先向Redis服务器发送 MULTI 命令,然后依次发送需要在
本次事务中处理的命令,最后再发送 EXEC 命令表示事务命令结束。Redis的事务是下面4
个命令来实现

1.multi,开启Redis的事务,置客户端为事务态。
2.exec,提交事务,执行从multi到此命令前的命令队列,置客户端为非事务态。
3.discard,取消事务,置客户端为非事务态。
4.watch,监视键值对,作用时如果事务提交exec时发现监视的监视对发生变化,事务将被取消。

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
const config = require('./app/config/config');
const Redis = require('ioredis');

const redisServer = new Redis({
'port': config.redis_common.port,
'host': config.redis_common.host,
'password': config.redis_common.password,
'db': config.redis_common.db || 0,
});
const moment = require('moment');

(async () => {
try {
// let t_exp = new Date(moment().add(1, 'days').format('YYYY-MM-DD')).valueOf();
// await redisServer.set('boboTeacher_other_modules:skill-count', 50);
// await redisServer.pexpireat('boboTeacher_other_modules:skill-count', t_exp); // 设置过期时间

// boboTeacher_other_modules:skill-count
let count = await redisServer.get('boboTeacher_other_modules:skill-count');
console.log('count', count);
// 监听
let watch = await redisServer.watch('boboTeacher_other_modules:skill-count'); // OK
console.log('watch', watch);
// 开启事务
let multi = await redisServer.multi();
// 减 1
await multi.decrby('boboTeacher_other_modules:skill-count', 1);
// 结束事务
let result = await multi.exec();// 正常 result====> [ [ null, 46 ] ] 异常 result====> null
console.log('result====>', result);
// 取消监听
let unwatch = await redisServer.unwatch();
console.log('unwatch', unwatch); // OK

let count1 = await redisServer.get('boboTeacher_other_modules:skill-count');
console.log('count1', count1);
} catch (error) {
console.log('error', error);
}
})();

异常测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
const config = require('./app/config/config');
const Redis = require('ioredis');

const redisServer = new Redis({
'port': config.redis_common.port,
'host': config.redis_common.host,
'password': config.redis_common.password,
'db': config.redis_common.db || 0,
});
const moment = require('moment');
(async () => {
try {
// let t_exp = new Date(moment().add(1, 'days').format('YYYY-MM-DD')).valueOf();
// await redisServer.set('boboTeacher_other_modules:skill-count', 50);
// await redisServer.pexpireat('boboTeacher_other_modules:skill-count', t_exp); // 设置过期时间

// boboTeacher_other_modules:skill-count
let count = await redisServer.get('boboTeacher_other_modules:skill-count');
console.log('count', count);
// 监听
let watch = await redisServer.watch('boboTeacher_other_modules:skill-count'); // OK
console.log('watch', watch);
// 开启事务
let multi = await redisServer.multi();
setTimeout(async () => {

// 减 1
await multi.decrby('boboTeacher_other_modules:skill-count', 1);
// 结束事务
let result = await multi.exec(); // 正常 result====> [ [ null, 46 ] ] 异常 result====> null

console.log('result====>', result);
// 取消监听
let unwatch = await redisServer.unwatch();
console.log('unwatch', unwatch); // OK

let count1 = await redisServer.get('boboTeacher_other_modules:skill-count');
console.log('count1', count1);

}, 5000);

await redisServer.decrby('boboTeacher_other_modules:skill-count', 1);
let count3 = await redisServer.get('boboTeacher_other_modules:skill-count');
console.log('count3', count3);
console.log('-----------------');
} catch (error) {
console.log('error', error);
}
})();
文章目录
  1. 1. 介绍
  2. 2. 使用