文章目录
- 第1关:Redis 事务与锁机制
- 第2关:流水线
- 第3关:发布订阅
- 第4关:超时命令
- 第5关:使用Lua语言
第1关:Redis 事务与锁机制
编程要求
根据提示,在右侧编辑器Begin-End补充代码,根据以下要求完成一个模拟一次银行卡支付扣款的流程:
1、当余额不足时,放弃所有被监控的键,返回false。
2、在余额扣除消费的金额,在支付金额里加上消费的金额。
测试说明
我会对你编写的代码进行测试:
测试输入:无;
预期输出:
支付成功
本次扣款10元,余额为90元
开始你的任务吧,祝你成功!
示例代码如下:
package com.test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
import java.util.List;
public class TestRedis {
private static String host = "127.0.0.1";
private static int port = 6379;
private static Jedis jedis = new Jedis(host, port);
public static boolean payMent(int deduction) throws InterruptedException {
int balance; // 余额
//设置余额金额
jedis.set("balance", "100");
jedis.set("deduction", "0");
//监控扣款和余额
jedis.watch("balance", "deduction");
/***********Begin***********/
balance = Integer.parseInt(jedis.get("balance"));
// 余额不足
if (balance < deduction) {
jedis.unwatch(); // 放弃所有被监控的键
System.out.println("对不起,你的余额不足");
return false;
}
Transaction transaction = jedis.multi();
// 扣钱
transaction.decrBy("balance", deduction);
Thread.sleep(5000); // 在外部修改 balance 或者 debt
transaction.incrBy("deduction", deduction);
// list为空说明事务执行失败
List<Object> list = transaction.exec();
return !list.isEmpty();
/***********End***********/
}
public static void main(String[] args) throws InterruptedException {
boolean resultValue = payMent(10);
if (resultValue==true){
System.out.println("支付成功");
int balance = Integer.parseInt(jedis.get("balance"));
int deduction = Integer.parseInt(jedis.get("deduction"));
System.out.printf("本次扣款"+deduction+"元,余额为"+balance+"元");
}else{
System.out.println("支付失败");
}
jedis.close();
}
}
第2关:流水线
编程要求
根据提示,在右侧编辑器Begin-End补充代码,按照以下要求开启一次流水线技术:
开启流水线。
测试十万条读写操作,设置 key 值为 key0 、 key1 、 key2 …key99998、key99999,对应 value 值为 value0 、value1、value2…value99998、value99999。
结束流水线。
测试说明
我会对你编写的代码进行测试:
测试输入:无;
预期输出:
开启流水线
消耗时间:XXX毫秒
关闭流水线
流水线成功完成!
开始你的任务吧,祝你成功!
示例代码如下:
package com.test;
import redis.clients.jedis.*;
import java.util.List;
public class RedisPipeline {
public boolean pipeline() {
String redisHost = "127.0.0.1";
int redisPort = 6379;
Jedis jedis = new Jedis(redisHost, redisPort);
jedis.flushDB();
/**********Begin**********/
long start = System.currentTimeMillis();
// 开启流水线
Pipeline pipeline = jedis.pipelined();
System.out.println("开启流水线");
// 测试十万条读写操作
for (int i = 0; i < 100000; i++) {
pipeline.set("key"+i,"value"+i);
pipeline.get("key"+i);
}
long end = System.currentTimeMillis();
//关闭流水线
pipeline.close();
System.out.println("消耗时间:"+(end-start)+"毫秒");
System.out.println("关闭流水线");
/**********End**********/
return true;
}
}
第3关:发布订阅
编程要求
根据提示,在右侧编辑器Begin-End补充代码,按照以下要求:
在SubThread类中订阅指定频道redis。
测试说明
我会对你编写的代码进行测试:
测试输入:quit;
预期输出:
订阅redis, 订阅频道为 redis, 线程将被阻塞
订阅redis频道成功, 频道为 redis, 订阅频道为 1
请输入传输的信息:
关闭程序
开始你的任务吧,祝你成功!
示例代码如下:
package com.test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
public class SubThread extends Thread {
private final JedisPool jedisPool;
private final Subscriber subscriber = new Subscriber();
private final String channel = "redis";
public SubThread(JedisPool jedisPool) {
super("SubThread");
this.jedisPool = jedisPool;
}
@Override
public void run() {
System.out.println(String.format("订阅redis, 订阅频道为 %s, 线程将被阻塞", channel));
Jedis jedis = null;
try {
/************* Begin ***************/
jedis = jedisPool.getResource();
jedis.subscribe(subscriber, channel);
/************* End ***************/
} catch (Exception e) {
System.out.println(String.format("订阅频道错误, %s", e));
} finally {
if (jedis != null) {
jedis.close();
}
}
}
}
第4关:超时命令
编程要求
根据提示,在右侧编辑器Begin-End补充代码,按照以下要求使用 Spring 操作 Redis 超时命令过程:
创建键值对:key 值为“今天你吃了吗?”
获取 key 值
设置 key 的过期时间为 5 秒
测试说明
我会对你编写的代码进行测试:
测试输入:无;
预期输出:
今天你吃了吗?
null
开始你的任务吧,祝你成功!
示例代码如下:
package com.redis;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.concurrent.TimeUnit;
public class OverTimeRedisTest {
@SuppressWarnings({ "unchecked", "rawtypes", "resource" })
public static void main(String[] args) {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
RedisTemplate redisTemplate=applicationContext.getBean(RedisTemplate.class);
redisTemplate.execute((RedisOperations ops) -> {
/************Begin************/
ops.boundValueOps("key").set("今天你吃了吗?");
System.out.println(ops.boundValueOps("key").get());
ops.expire("key",5L, TimeUnit.SECONDS);
/************End************/
//睡眠6秒,使得key值过期
try {
Thread.sleep(6000);
}catch (InterruptedException e){
e.printStackTrace();
}
//获取key值
System.out.println(ops.boundValueOps("key").get());
//结束所有线程,退出系统
System.exit(0);
return null;
});
}
}
第5关:使用Lua语言
编程要求
根据提示,在右侧编辑器 Begin - End 处补充代码,根据以下要求完成一次手机销售库存的操作:
编写 ItemRedisTest.lua 文件,判断销售量是否比库存数量多,如果库存数量大于这次销售量,将新的库存数量更新到原来的 key 值上。
编写 ItemRedisTest.java 文件,使用 BufferedReader 读取ItemRedisTest.lua 文件,使用 eval 命令执行文件里的字符串,设置手机销售量为10。
ItemRedisTest.lua 地址为:/data/workspace/myshixun/step5/ItemRedisTest.lua
测试说明
我会对你编写的代码进行测试:
测试输入:无;
预期输出:
手机库存剩余:90
开始你的任务吧,祝你成功!
代码示例如下:
package com.redis;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
import redis.clients.jedis.Jedis;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class ItemRedisTest {
public static void main(String[] args) throws IOException {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
RedisTemplate redisTemplate=applicationContext.getBean(RedisTemplate.class);
Jedis jedis=(Jedis)redisTemplate.getConnectionFactory().getConnection().getNativeConnection();
jedis.set("phone_item_stock", "100");
/************Begin************/
BufferedReader in= new BufferedReader(new FileReader("/data/workspace/myshixun/step5/ItemRedisTest.lua"));
String context =null;
String script="";
while (null != (context = in.readLine())){
script+=context+"\n";
}
Object obj = jedis.eval(script, 1,"phone_item_stock","10");
/************End************/
System.out.println("手机库存剩余:"+obj);
//关闭连接
jedis.close();
System.exit(0);
}
}
之后在命令行中输入下列代码:
vim /data/workspace/myshixun/step5/ItemRedisTest.lua
编辑该文件内容
local count = redis.call('get', KEYS[1])
local a=tonumber(count)
local b=tonumber(ARGV[1])
---Begin
if a>=b then
redis.call('set',KEYS[1],count-b)
return redis.call('get', KEYS[1])
end
---End