1.测试
package com.zx;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import java.util.List;
import java.util.Set;
public class RedisTest {
@Test
public void testContent(){
Jedis jedis = new Jedis("127.0.0.1", 6379);
String ping= jedis.ping();
System.out.println("ping = " + ping);
Set<String> keys = jedis.keys("*");
System.out.println("keys = " + keys);
//判断某个key是否存在
Boolean k1 = jedis.exists("k1");
System.out.println("k1 = " + k1);
//获取key类型
String k7 = jedis.type("k7");
System.out.println("k7 = " + k7);
//k1的值
String k11 = jedis.get("k1");
System.out.println("k1的值 = " + k11);
//k5的值list
List<String> k51 = jedis.lrange("k5", 0, -1);
for (String s :k51){
System.out.println("s = " + s);
}
//获取set
Set<String> k4 = jedis.smembers("k4");
System.out.println("k4 = " + k4);
//hash
Set<String> k71 = jedis.hkeys("k7");
System.out.println("k71 = " + k71);
List<String> k72 = jedis.hvals("k7");
System.out.println("k72 = " + k72);
//zset
Set<String> k8 = jedis.zrange("k8", 0, -1);
System.out.println("k8 = " + k8);
}
}
运行结果:
ping = PONG
keys = [k3, k4, k5, k7, k8, k1, k2]
k1 = true
k7 = hash
k1的值 = v2
s = v6
s = k6
s = v5
k4 = [v3, v1, v4, v2, v5]
k71 = [name, birth, age]
k72 = [zhangsan, 24, 2020-08-08]
k8 = [v3, v2, v1]
2.Redis手机验证码
Redis依赖
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<!--servlet-api-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
前端代码
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="static/jquery/jquery-3.1.0.js" ></script>
<link href="static/bs/css/bootstrap.min.css" rel="stylesheet" />
<script src="static/bs/js/bootstrap.min.js" ></script>
</head>
<body>
<div class="container">
<div class="row">
<div id="alertdiv" class="col-md-12">
<form class="navbar-form navbar-left" role="search" id="codeform">
<div class="form-group">
<input type="text" class="form-control" placeholder="填写手机号" name="phone_no">
<button type="button" class="btn btn-default" id="sendCode">发送验证码</button><br>
<font id="countdown" color="red" ></font>
<br>
<input type="text" class="form-control" placeholder="填写验证码" name="verify_code">
<button type="button" class="btn btn-default" id="verifyCode">确定</button>
<font id="result" color="green" ></font><font id="error" color="red" ></font>
</div>
</form>
</div>
</div>
</div>
</body>
<script type="text/javascript">
var t=120;//设定倒计时的时间
var interval;
function refer(){
$("#countdown").text("请于"+t+"秒内填写验证码 "); // 显示倒计时
t--; // 计数器递减
if(t<=0){
clearInterval(interval);
$("#countdown").text("验证码已失效,请重新发送! ");
}
}
$(function(){
$("#sendCode").click( function () {
$.post("SendCodeServlet",$("#codeform").serialize(),function(data){
if(data=="true"){
t=120;
clearInterval(interval);
interval= setInterval("refer()",1000);//启动1秒定时
}else if (data=="limit"){
clearInterval(interval);
$("#countdown").text("单日发送超过次数! ")
}
});
});
$("#verifyCode").click( function () {
$.post("CheckCodeServlet",$("#codeform").serialize(),function(data){
if(data=="true"){
$("#result").attr("color","green");
$("#result").text("验证成功");
clearInterval(interval);
$("#countdown").text("")
}else{
$("#result").attr("color","red");
$("#result").text("验证失败");
}
});
});
});
</script>
</html>
后端用servlet接收
1.接收手机号进行,生成验证码存入数据库120s,并进行每天3次判断
package com.atguigu.redis.servlet;
import javafx.scene.input.KeyCode;
import redis.clients.jedis.Jedis;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Duration;
import java.time.LocalTime;
import java.util.Random;
//处理发送验证码的Servlet
@WebServlet("/SendCodeServlet")
public class SendCodeServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取前端返回的值
String phoneNo = request.getParameter("phone_no");
System.out.println("phoneNo = " + phoneNo);
//进行非空判断
if (phoneNo==null|| "".equals(phoneNo)){
return;
}
//手机号的次数
String countKey=phoneNo+":count";
System.out.println("countKey = " + countKey);
//连接Redis
Jedis jedis = new Jedis("127.0.0.1", 6379);
String count = jedis.get(countKey);
if (count==null){
//调用计数方法
long theLeftSeconds = getTheLeftSeconds();
//写入数据库
jedis.setex(countKey,(int)theLeftSeconds,"1");
}else if("3".equals(count)){
response.getWriter().write("limit");
jedis.close();
}else {
//证明今天发送未超三次,将计数器加一
jedis.incr(countKey);
}
System.out.println("count = " + count);
String code = getCode(6);
System.out.println("code = " + code);
String keycode=phoneNo +":code";
//写入数据库
String setex = jedis.setex(keycode, 120, code);
response.getWriter().write("true");
jedis.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
// 随机生成验证码的方法
private String getCode(int len) {
String code = "";
for (int i = 0; i < len; i++) {
int rand = new Random().nextInt(10);
code += rand;
}
return code;
}
//获取当天剩余秒数的方法
private long getTheLeftSeconds(){
//获取现在的时间
LocalTime now = LocalTime.now();
//获取当日23点59分59秒的时间
LocalTime end = LocalTime.of(23, 59, 59);
//获取end与now相差的秒数
long millis = Duration.between(now, end).toMillis()/1000;
return millis;
}
}
2.接收数据库的验证码和前端输入的验证码经行判断
package com.atguigu.redis.servlet;
import redis.clients.jedis.Jedis;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//处理验证验证码请求的Servlet
@WebServlet("/CheckCodeServlet")
public class CheckCodeServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String verifyCode = request.getParameter("verify_code");
String phoneNo = request.getParameter("phone_no");
//非空判断
if (verifyCode==null||"".equals(verifyCode)||phoneNo==null|| "".equals(phoneNo)){
return;
}
String keycode=phoneNo +":code";
//连接数据库
Jedis jedis = new Jedis("127.0.0.10", 6379);
//取值
String riderskey = jedis.get(keycode);
System.out.println("riderskey = " + riderskey);
//和前端的值进行比较
if (verifyCode.equals(riderskey)){
jedis.del(keycode);
response.getWriter().write("true");
}
jedis.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
Redis事务
Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
Redis事务的主要作用就是串联多个命令防止别的命令插队
从输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行,直到输入Exec后,Redis会将之前的命令队列中的命令依次执行。
组队的过程中可以通过discard来放弃组队
。
组队中某个命令出现了报告错误,执行时整个的所有队列都会被取消。
如果执行阶段某个命令报出了错误,则只有报错的命令不会被执行,而其他的命令都会执行,不会回滚。
悲观锁
悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁
乐观锁
乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis就是利用这种check-and-set机制实现事务的。
WATCH key [key …]
在执行multi之前,先执行watch key1 [key2],可以监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。
unwatch
取消 WATCH 命令对所有 key 的监视。
如果在执行 WATCH 命令之后,EXEC 命令或DISCARD 命令先被执行了的话,那么就不需要再执行UNWATCH 了。
4.6. Redis事务三特性
- 单独的隔离操作
事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。- 没有隔离级别的概念
队列中的命令没有提交之前都不会实际被执行,因为事务提交前任何指令都不会被实际执行- 不保证原子性
事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚
秒杀(方法)
//秒杀过程
public static boolean doSecKill(String uid,String prodid) throws IOException {
String kckey="sk:"+prodid+":qt";
String userKey="sk:"+prodid+":usr";
//Jedis jedis = new Jedis("127.0.0.1", 6379);
//连接池对象
JedisPool jedisPoolInstance = JedisPoolUtil.getJedisPoolInstance();
//获取Jedis
Jedis jedis = jedisPoolInstance.getResource();
//添加乐观锁
jedis.watch(kckey);
String count = jedis.get(kckey);
//判断
if ("0".equals(count)){
System.err.println("已经没有了");
JedisPoolUtil.release(jedisPoolInstance,jedis);
return false;
}
//添加事务
Transaction multi = jedis.multi();
//组队
multi.decr(kckey);
//jedis.decr(kckey);
//jedis.sadd(userKey,uid);
multi.sadd(userKey,uid);
//执行
List<Object> exec = multi.exec();
if (exec==null||exec.size()==0){
//秒杀失败
System.out.println("秒杀失败");
//关闭资源
JedisPoolUtil.release(jedisPoolInstance,jedis);
jedis.close();
return false;
}
return true;
}
前后端交互
package com.atguigu.redis;
import redis.clients.jedis.Jedis;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Random;
/**
* 秒杀案例
*/
@WebServlet("/doseckill")
public class SecKillServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//随机生成用户id
String userid = new Random().nextInt(50000) +"" ;
//获取商品id
String prodid =request.getParameter("prodid");
//秒杀
//boolean isSuccess=SecKill_redis.doSecKill(userid,prodid);
//解决库存问题
boolean isSuccess = SecKill_redisByScript.doSecKill(userid, prodid);
//给前端响应
response.getWriter().print(isSuccess);
}
}
Redis连接池
package com.atguigu.redis;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;ipackage com.atguigu.redis;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class JedisPoolUtil {
private static volatile JedisPool jedisPool = null;
//连接池
private JedisPoolUtil() {
}
public static JedisPool getJedisPoolInstance() {
if (null == jedisPool) {
synchronized (JedisPoolUtil.class) {
if (null == jedisPool) {
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(200);
poolConfig.setMaxIdle(32);
poolConfig.setMaxWaitMillis(100*1000);
poolConfig.setBlockWhenExhausted(true);
poolConfig.setTestOnBorrow(true); // ping PONG
jedisPool = new JedisPool(poolConfig, "127.0.0.1", 6379, 60000 );
}
}
}
return jedisPool;
}
public static void release(JedisPool jedisPool, Jedis jedis) {
if (null != jedis) {
jedisPool.returnResource(jedis);
}
}
}
import redis.clients.jedis.JedisPooiesConfig;
public class JedisPoolUtil {
private static volatile JedisPool jedisPool = null;
//连接池
private JedisPoolUtil() {
}
public static JedisPool getJedisPoolInstance() {
if (null == jedisPool) {
synchronized (JedisPoolUtil.class) {
if (null == jedisPool) {
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(200);
poolConfig.setMaxIdle(32);
poolConfig.setMaxWaitMillis(100*1000);
poolConfig.setBlockWhenExhausted(true);
poolConfig.setTestOnBorrow(true); // ping PONG
jedisPool = new JedisPool(poolConfig, "127.0.0.1", 6379, 60000 );
}
}
}
return jedisPool;
}
public static void release(JedisPool jedisPool, Jedis jedis) {
if (null != jedis) {
jedisPool.returnResource(jedis);
}
}
}