依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<!--不依赖Redis的异步客户端lettuce -->
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--引入Redis的客户端驱动jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
数据库配置
application.properties
# REDIS (RedisProperties)
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=0
有了上述的配置,Spring Boot就会自动地为我们生成相关对象,如RedisTemplate、StringRedis Template等
测试
package com.example.demo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.Assert;
@SpringBootTest
class DemoApplicationTests {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
void contextLoads() {
}
@Test
public void test() throws Exception{
stringRedisTemplate.opsForValue().set("aaa","111");
System.out.println(stringRedisTemplate.opsForValue().get("aaa"));
}
}
序列化对象
User.java
public class User implements Serializable {
private String name;
private int age;
public void print(){
System.out.println(name);
System.out.println(age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
测试
@SpringBootTest
class DemoApplicationTests {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private RedisTemplate redisTemplate;
@Test
void contextLoads() {
}
@Test
public void test() throws Exception{
stringRedisTemplate.opsForValue().set("aaa","111");
System.out.println(stringRedisTemplate.opsForValue().get("aaa"));
User user = new User();
user.setAge(12);
user.setName("sdfs");
redisTemplate.opsForValue().set("user1",user);
User temp = (User) redisTemplate.opsForValue().get("user1");
temp.print();
}
}
如何在redis中使用lua脚本
@Autowired
StringRedisTemplate stringRedisTemplate = null;
/*
* Redis sadd 命令将一个或多个成员元素加入到集合中,已经存在于集合的成员元素将被忽略。
* .. 是lua链接字符串的方式
* tonumber 这个函数会尝试将它的参数转换为数字,如果参数已经是一个数字或者是一个可以转换成数字的字符串,那么这个函数就会返回转换后的数字,否者返回nil表示无法转换。
* Redis Hget 命令用于返回哈希表中指定字段的值。
* HSET key field value 将哈希表 key 中的字段 field 的值设为 value 。
* RPUSH key value1 [value2] 在列表中添加一个或多个值
* */
String purchaseScript =
// 先将产品编号保存到集合中
" redis.call('sadd', KEYS[1], ARGV[2]) \n"
// 购买列表
+ "local productPurchaseList = KEYS[2]..ARGV[2] \n"
// 用户编号
+ "local userId = ARGV[1] \n"
// 产品key
+ "local product = 'product_'..ARGV[2] \n"
// 购买数量
+ "local quantity = tonumber(ARGV[3]) \n"
// 当前库存
+ "local stock = tonumber(redis.call('hget', product, 'stock')) \n"
// 价格
+ "local price = tonumber(redis.call('hget', product, 'price')) \n"
// 购买时间
+ "local purchase_date = ARGV[4] \n"
// 库存不足,返回0
+ "if stock < quantity then return 0 end \n"
// 减库存
+ "stock = stock - quantity \n"
+ "redis.call('hset', product, 'stock', tostring(stock)) \n"
// 计算价格
+ "local sum = price * quantity \n"
// 合并购买记录数据
+ "local purchaseRecord = userId..','..quantity..','"
+ "..sum..','..price..','..purchase_date \n"
// 保存到将购买记录保存到list里
+ "redis.call('rpush', productPurchaseList, purchaseRecord) \n"
// 返回成功
+ "return 1 \n";
// Redis购买记录集合前缀
private static final String PURCHASE_PRODUCT_LIST = "purchase_list_";
// 抢购商品集合
private static final String PRODUCT_SCHEDULE_SET = "product_schedule_set";
// 32位SHA1编码,第一次执行的时候先让Redis进行缓存脚本返回
private String sha1 = null;
public boolean purchaseRedis(Long userId, Long productId, int quantity) {
// 购买时间
Long purchaseDate = System.currentTimeMillis();
Jedis jedis = null;
try {
// 获取原始连接
jedis = (Jedis) stringRedisTemplate
.getConnectionFactory().getConnection().getNativeConnection();
// 如果没有加载过,则先将脚本加载到Redis服务器,让其返回sha1
if (sha1 == null) {
sha1 = jedis.scriptLoad(purchaseScript);
}
// 执行脚本,返回结果
Object res = jedis.evalsha(sha1, 2, PRODUCT_SCHEDULE_SET,
PURCHASE_PRODUCT_LIST, userId + "", productId + "",
quantity + "", purchaseDate + "");
Long result = (Long) res;
return result == 1;
} finally {
// 关闭jedis连接
if (jedis != null && jedis.isConnected()) {
jedis.close();
}
}
}
- 步骤:
- 写脚本(用字符串保存),purchaseScript
- 返回一个哈希 sha1 = jedis.scriptLoad(purchaseScript);
- 用evalsha执行 jedis.evalsha(sha1, .......);