以查询热点商品为例:
在查询热点商品的场景中,可以使用Redis来实现缓存功能,以减轻MySQL数据库的负担。
确保Spring Boot项目已经配置了StringRedisTemplate。通常,需要在配置文件中配置Redis的连接信息。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
spring:
redis:
host: 你的RedisIP地址
password: 你的Redis授权密码
使用StringRedisTemplate来处理热点商品的缓存。热点商品数据存储在Redis的哈希结构中,其中键是"HOT_PRODUCTS",字段是产品ID,值是产品信息。在getHotProduct方法中,我们首先尝试从缓存中获取商品信息,如果缓存中存在,就返回缓存中的数据;如果缓存中不存在,就从MySQL查询商品信息,然后将查询结果写回缓存。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
@Service
public class HotProductService {
private static final String HOT_PRODUCT_KEY = "hot_products";
@Autowired
private StringRedisTemplate stringRedisTemplate;
// 查询热点商品,如果缓存中存在则从缓存获取,否则从MySQL查询并写回缓存
public String getHotProduct(String productId) {
String cachedProduct = stringRedisTemplate.opsForHash().get(HOT_PRODUCT_KEY, productId);
if (cachedProduct != null) {
return cachedProduct;
} else {
// 如果缓存中不存在,从MySQL查询
String productFromDatabase = queryProductFromDatabase(productId);
// 将查询结果写回缓存
stringRedisTemplate.opsForHash().put(HOT_PRODUCT_KEY, productId, productFromDatabase);
return productFromDatabase;
}
}
// 模拟从MySQL查询商品信息的方法
private String queryProductFromDatabase(String productId) {
// 实际场景中,这里会查询MySQL数据库并返回商品信息
// 这里使用一个简单的示例,返回一个模拟的商品信息
return "Product: " + productId;
}
}
在控制器或其他业务逻辑中,可以使用热点商品服务来实现热点商品的查询:
在这个控制器中,用户可以通过HTTP请求来查询热点商品的信息。如果商品信息已经被缓存,将从缓存中获取,否则将查询数据库并写入缓存。
@RestController
@RequestMapping("/hot-products")
public class HotProductController {
@Autowired
private HotProductService hotProductService;
@GetMapping("/{productId}")
public ResponseEntity<String> getHotProduct(@PathVariable String productId) {
String productInfo = hotProductService.getHotProduct(productId);
return ResponseEntity.ok(productInfo);
}
}
大致思路:使用StringRedisTemplate编写业务逻辑,实现登录控制功能,要求用户输入电话号,获取验证码,后台生成验证码并将验证码存储在Redis中,有效期5分钟。当用户在5分钟内输入正确的验证码,验证通过,然后从MySQL查询用户信息是否存在,如果存在,根据用户信息生成Token,以Token为key将用户信息放入Redis缓存,并将Token返回给用户客户端;如果用户不存在,就根据用户的电话号码生成一个用户信息到插入到MySQL,并生成Token,将用户信息存储到Redis,并将Token返回给用户客户端;用户登录成功后,将用户信息存储到ThreadLocal内。
添加依赖:
确保Spring Boot项目已经配置了StringRedisTemplate,并且添加必要的依赖,包括Spring Web、Spring Data JPA(用于操作MySQL)、以及验证码生成工具(如Google’s Guava)。
编写验证码和登录服务:
创建一个服务,包含生成验证码、验证验证码、查询用户信息、生成Token等功能。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
@Service
public class AuthService {
private static final String VERIFICATION_CODE_KEY = "verification_code:";
private static final String USER_INFO_KEY = "user_info:";
@Autowired
private StringRedisTemplate stringRedisTemplate;
// 生成验证码并存储到Redis,设置有效期为5分钟
public String generateVerificationCode(String phoneNumber) {
String code = generateRandomCode();
String key = VERIFICATION_CODE_KEY + phoneNumber;
stringRedisTemplate.opsForValue().set(key, code, 300, TimeUnit.SECONDS);
return code;
}
// 验证验证码
public boolean verifyVerificationCode(String phoneNumber, String code) {
String key = VERIFICATION_CODE_KEY + phoneNumber;
String storedCode = stringRedisTemplate.opsForValue().get(key);
return code != null && code.equals(storedCode);
}
// 查询用户信息,如果用户不存在则插入到MySQL
public UserInfo getUserInfo(String phoneNumber) {
String key = USER_INFO_KEY + phoneNumber;
UserInfo userInfo = stringRedisTemplate.opsForValue().get(key);
if (userInfo == null) {
userInfo = getUserInfoFromDatabase(phoneNumber);
stringRedisTemplate.opsForValue().set(key, userInfo);
}
return userInfo;
}
// 生成Token并将用户信息存储到Redis
public String generateAndStoreToken(UserInfo userInfo) {
String token = generateToken();
String key = "token:" + token;
stringRedisTemplate.opsForValue().set(key, userInfo, 24, TimeUnit.HOURS); // 设置Token有效期为24小时
return token;
}
private String generateRandomCode() {
// 实现生成随机验证码的逻辑,可以使用Guava或其他工具
return "123456"; // 示例:固定验证码为123456
}
private UserInfo getUserInfoFromDatabase(String phoneNumber) {
// 查询MySQL数据库,如果用户存在,则返回用户信息,否则插入新用户并返回用户信息
// 实际场景中,需要使用Spring Data JPA或其他数据库访问方式
return new UserInfo(phoneNumber, "User Name"); // 示例:生成用户信息
}
private String generateToken() {
// 实现生成Token的逻辑,可以使用UUID或其他方式
return UUID.randomUUID().toString(); // 示例:使用UUID生成Token
}
}
@RestController
@RequestMapping("/auth")
public class AuthController {
@Autowired
private AuthService authService;
// 获取验证码
@GetMapping("/get-verification-code")
public ResponseEntity<String> getVerificationCode(@RequestParam String phoneNumber) {
String code = authService.generateVerificationCode(phoneNumber);
return ResponseEntity.ok("Verification code sent: " + code);
}
// 验证验证码并登录
@PostMapping("/login")
public ResponseEntity<String> login(@RequestParam String phoneNumber, @RequestParam String code) {
if (authService.verifyVerificationCode(phoneNumber, code)) {
UserInfo userInfo = authService.getUserInfo(phoneNumber);
String token = authService.generateAndStoreToken(userInfo);
// 将用户信息存储到ThreadLocal
ThreadLocalUserInfo.setUserInfo(userInfo);
return ResponseEntity.ok("Login successful. Token: " + token);
} else {
return ResponseEntity.badRequest().body("Invalid verification code.");
}
}
}
用户可以通过HTTP请求获取验证码和登录。如果验证码验证通过,将生成Token并将用户信息存储到ThreadLocal中,以便在请求处理过程中使用。
分布式锁可以用于确保在多个应用实例之间,只有一个实例可以执行更新操作,以避免竞争条件。
用户可以通过HTTP请求模拟更新库存的操作。在更新库存之前,首先尝试获取分布式锁,如果成功获取到锁,则执行库存更新操作,然后释放锁。如果无法获取锁,表示有其他实例正在执行更新操作,返回冲突状态码(HTTP 409)。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
@Service
public class InventoryService {
private static final String LOCK_KEY = "inventory_lock";
private static final String INVENTORY_KEY = "inventory";
@Autowired
private StringRedisTemplate stringRedisTemplate;
// 获取分布式锁
public boolean acquireLock() {
Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(LOCK_KEY, "locked");
if (success != null && success) {
return true;
}
return false;
}
// 释放分布式锁
public void releaseLock() {
stringRedisTemplate.delete(LOCK_KEY);
}
// 更新商品库存
public boolean updateInventory(int quantity) {
String inventoryStr = stringRedisTemplate.opsForValue().get(INVENTORY_KEY);
if (inventoryStr != null) {
int currentInventory = Integer.parseInt(inventoryStr);
int newInventory = currentInventory + quantity;
stringRedisTemplate.opsForValue().set(INVENTORY_KEY, String.valueOf(newInventory));
return true;
}
return false;
}
}
@RestController
@RequestMapping("/inventory")
public class InventoryController {
@Autowired
private InventoryService inventoryService;
@PostMapping("/update")
public ResponseEntity<String> updateInventory(@RequestParam int quantity) {
if (inventoryService.acquireLock()) {
try {
boolean success = inventoryService.updateInventory(quantity);
if (success) {
return ResponseEntity.ok("Inventory updated successfully.");
} else {
return ResponseEntity.badRequest().body("Failed to update inventory.");
}
} finally {
inventoryService.releaseLock();
}
} else {
return ResponseEntity.status(HttpStatus.CONFLICT).body("Inventory update in progress.");
}
}
}
要使用Redis实现获取附近的饭店信息,你可以结合地理空间索引功能,Redis提供了Geospatial数据类型,如有序集合(Sorted Set)来存储地理位置数据。
// 添加饭店的位置信息到有序集合
stringRedisTemplate.opsForZSet().add("restaurants", "Restaurant A", new GeoCoordinate(13.361389, 38.115556));
stringRedisTemplate.opsForZSet().add("restaurants", "Restaurant B", new GeoCoordinate(15.087269, 37.502669));
// ...添加更多饭店的位置信息
// 查找离指定经度和纬度坐标10千米范围内的饭店
List<GeoResult<GeoLocation<String>>> restaurants = stringRedisTemplate.opsForGeo()
.radius("restaurants", new Circle(new Point(13.361389, 38.115556), new Distance(10, Metrics.KILOMETERS)));
上述代码会返回一个GeoResult列表,其中包含了附近饭店的信息,包括名称和距离等。
这只是一个简单的示例,实际中你可能需要更复杂的逻辑,如根据用户当前位置、提供排序、筛选等功能。另外,为了减少网络延迟,通常可以将附近饭店的信息缓存在应用程序中,定期从Redis中刷新。此外,可以考虑使用其他地理空间索引数据库如MongoDB或专用的地理信息服务提供商如Mapbox,以获得更多高级的地理查询功能。
要使用Redis获取共同好友,你可以使用Redis的集合数据结构来存储每个用户的好友列表,并使用集合操作来查找两个用户的共同好友。以下是一个基本的实现思路:
// 用户A的好友列表
stringRedisTemplate.opsForSet().add("user:A:friends", "B", "C", "D");
// 用户B的好友列表
stringRedisTemplate.opsForSet().add("user:B:friends", "A", "C", "E");
// ... 添加更多用户和好友关系
// 查找用户A和用户B的共同好友
Set<String> commonFriends = stringRedisTemplate.opsForSet().intersect("user:A:friends", "user:B:friends");
commonFriends集合中包含了用户A和用户B的共同好友。
实际中你可能需要更复杂的逻辑,如支持分页、提供搜索功能、处理用户关系的变化等。另外,你可以考虑使用Redis的有序集合数据结构来存储好友列表,并为每个好友指定一个分数,以支持更复杂的好友关系操作。
使用Redis实现会议签到功能是一种常见的用例,其中Redis可以用作临时存储签到信息和记录会议参与者的状态。以下是一个示例,演示如何使用Redis实现会议签到功能:
首先,你需要在Redis中存储会议信息以及签到记录。你可以使用Redis的哈希(Hash)数据结构来存储会议信息,以及有序集合(Sorted Set)来存储签到记录。例如:
// 存储会议信息
stringRedisTemplate.opsForHash().put("meeting:123", "name", "Team Meeting");
stringRedisTemplate.opsForHash().put("meeting:123", "location", "Conference Room A");
// 记录签到
stringRedisTemplate.opsForZSet().add("meeting:123:attendees", "user:A", System.currentTimeMillis());
stringRedisTemplate.opsForZSet().add("meeting:123:attendees", "user:B", System.currentTimeMillis());
// ... 添加更多签到记录
当会议参与者到达会议现场时,可以执行签到操作。签到时,你可以添加用户到会议的有序集合中,并记录签到的时间戳。
String userId = "user:C";
String meetingId = "meeting:123";
stringRedisTemplate.opsForZSet().add(meetingId + ":attendees", userId, System.currentTimeMillis());
你可以使用有序集合操作来查询会议的签到记录。例如,你可以使用ZRANGE命令来获取签到用户列表。
String meetingId = "meeting:123";
Set<String> attendees = stringRedisTemplate.opsForZSet().range(meetingId + ":attendees", 0, -1);
attendees集合中包含了所有签到的用户。
你可以通过检查用户是否在会议的有序集合中来确定其签到状态。
String userId = "user:D";
String meetingId = "meeting:123";
Boolean isAttended = stringRedisTemplate.opsForZSet().score(meetingId + ":attendees", userId) != null;
isAttended将返回true表示用户已签到,返回false表示用户未签到。
这只是一个简单的示例,实际中,你可能需要更多的功能,如处理签到状态的变化、签到时间的统计、检查会议是否已经开始等。使用Redis来实现会议签到功能可以提供快速的读写操作,但也需要考虑并发处理、数据保护等问题。根据具体需求,你可以设计更复杂的签到系统。