下面是一个基于Spring Boot和Redis的购物车功能示例:
- 集成Redis
在Spring Boot中集成Redis很简单,只需要在pom.xml中添加以下依赖:
phpCopy code
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
然后在application.properties中配置Redis连接信息,例如:
Copy code
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=yourpassword
2.设计购物车数据结构
购物车可以使用Redis的Hash类型来存储,其中每一个Hash对应一个用户的购物车,Hash的key为用户ID,Hash的field为商品ID,Hash的value为商品数量。
makefileCopy code
redisKey: cart:userId
redisField: productId
redisValue: productNum
3.实现购物车功能
下面是一个简单的购物车功能实现示例,包括添加商品、删除商品和清空购物车功能:
typescriptCopy code
@Service
public class CartServiceImpl implements CartService {
@Autowired
private RedisTemplate redisTemplate;
@Override
public void addProduct(String userId, String productId, int productNum) {
BoundHashOperations<String, String, Integer> ops = redisTemplate.boundHashOps("cart:" + userId);
Integer oldNum = ops.get(productId);
if (oldNum == null) {
oldNum = 0;
}
ops.put(productId, oldNum + productNum);
}
@Override
public void removeProduct(String userId, String productId) {
BoundHashOperations<String, String, Integer> ops = redisTemplate.boundHashOps("cart:" + userId);
ops.delete(productId);
}
@Override
public void clearCart(String userId) {
redisTemplate.delete("cart:" + userId);
}
}
4.结合数据库设计
购物车功能常常需要与商品信息进行联合查询,可以使用MySQL来存储商品信息。下面是一个简单的商品信息表设计:
sqlCopy code
CREATE TABLE `product` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`price` decimal(10,2) NOT NULL,
`description` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
5.实现购物车与数据库联合查询功能
在购物车中加入商品信息查询:
ShoppingCartService接口的实现类ShoppingCartServiceImpl:
javaCopy code
@Service
public class ShoppingCartServiceImpl implements ShoppingCartService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private ShoppingCartMapper shoppingCartMapper;
private static final String REDIS_KEY_PREFIX = "shopping_cart_";
private static final long REDIS_KEY_EXPIRATION = 3600L; // Redis键过期时间,单位秒
@Override
public void addToCart(int userId, int productId, int quantity) {
// 1. 向数据库中插入购物车记录
ShoppingCart shoppingCart = new ShoppingCart(userId, productId, quantity);
shoppingCartMapper.insert(shoppingCart);
// 2. 向Redis中插入购物车记录
String redisKey = REDIS_KEY_PREFIX + userId;
String field = String.valueOf(productId);
redisTemplate.opsForHash().put(redisKey, field, quantity);
redisTemplate.expire(redisKey, REDIS_KEY_EXPIRATION, TimeUnit.SECONDS);
}
@Override
public void updateQuantity(int userId, int productId, int quantity) {
// 1. 更新数据库中的购物车记录
shoppingCartMapper.updateQuantity(userId, productId, quantity);
// 2. 更新Redis中的购物车记录
String redisKey = REDIS_KEY_PREFIX + userId;
String field = String.valueOf(productId);
redisTemplate.opsForHash().put(redisKey, field, quantity);
redisTemplate.expire(redisKey, REDIS_KEY_EXPIRATION, TimeUnit.SECONDS);
}
@Override
public void deleteFromCart(int userId, int productId) {
// 1. 删除数据库中的购物车记录
shoppingCartMapper.delete(userId, productId);
// 2. 删除Redis中的购物车记录
String redisKey = REDIS_KEY_PREFIX + userId;
String field = String.valueOf(productId);
redisTemplate.opsForHash().delete(redisKey, field);
}
@Override
public Map<Integer, Integer> getCart(int userId) {
// 1. 从Redis中获取购物车记录
String redisKey = REDIS_KEY_PREFIX + userId;
Map<Object, Object> redisEntries = redisTemplate.opsForHash().entries(redisKey);
// 2. 如果Redis中不存在购物车记录,则从数据库中获取
if (redisEntries == null || redisEntries.isEmpty()) {
List<ShoppingCart> shoppingCarts = shoppingCartMapper.selectByUserId(userId);
if (shoppingCarts == null || shoppingCarts.isEmpty()) {
return null;
} else {
Map<Integer, Integer> cart = new HashMap<>();
for (ShoppingCart shoppingCart : shoppingCarts) {
cart.put(shoppingCart.getProductId(), shoppingCart.getQuantity());
}
return cart;
}
} else {
Map<Integer, Integer> cart = new HashMap<>();
for (Map.Entry<Object, Object> entry : redisEntries.entrySet()) {
int productId = Integer.parseInt((String) entry.getKey());
int quantity = (int) entry.getValue();
cart.put(productId, quantity);
}
return cart;
}
}
}
注意:上述的demo只是简单例子,上面的demo代码会存在redis与数据库数据一致性的问题,后续后出一篇详细介绍如何保证缓存与数据库数据一致性的文章。