Redis 事务、性能优化

13 篇文章 1 订阅
10 篇文章 0 订阅


redis 的事务指的是提供一种将多个命令打包,一次性按顺序地执行
redis的事务可以保证只有在执行完事务中的所有命令后,才会继续处理此客户端的其他命令。
也就是说只有一个用户可以操作事务当中的数据
redis 中的事务开始到结束要经历三个阶段

  • 开启事务
  • 命令入列
  • 执行事务/放弃事务
开启事务命令

redis 事务四大指令:MULTI、EXEC、DISCARD、WATCH

  • MULTI 开启一个事务
  • EXEC 执行一个事务
  • DISCARD 取消一个事务
  • WATCH 用于客户端并发情况下,为事务提供一个锁可以用 watch 命令来监控一个或多个变量如果在执行事务之前,某个监控项被修改了,那么整个事务就会终止执行

watch 必须写在事务的前面,不能写在事务当中

这是一个处理抢购并发的流程图

在这里插入图片描述

@GetMapping("/shopping")
@ResponseBody
public Boolean snappedUp(@RequestParam Long id) {
	//实现购买代码
	//先去 redis 查询一下
	Object value = redisTemplate.opsForValue().get(id);
	int stock = 0;
	//如果 redis 没有则去数据库查询
	if (value == null) {
		//去数据库查询该商品的信息
		ProductDO product = productDAO.selectById(id);
		//将信息缓存到 redis 中
		stock = product.getStock();
		redisTemplate.opsForValue().set(product.getId(), stock);
	} else {
		stock = (int) value;
	}

	redisTemplate.execute(new SessionCallback<List<Object>>() {
		@Override
		public List<Object> execute(RedisOperations operations) throws DataAccessException {
			Integer stock = (Integer) redisTemplate.opsForValue().get(id);
			//判断该商品的库存是否大于1
			if (Integer.valueOf(stock) >= 1) {
				//监听商品的名字,redis 里面的 key
				operations.watch(id);
				//开启事务
				operations.multi();
				//将该商品的库存自减1
				operations.opsForValue().set(id, stock-1);
				//修改mysql数据库的库存量
				ProductDO productDO = new ProductDO();
				productDO.setId(id);
				productDO.setStock(stock-1);
				productDAO.updateStock(productDO);
				//执行事务
				List exec = operations.exec();
				if (exec.size() > 0) {
					//可以有其他的业务逻辑,例如插入订单等,视具体的需求
					LOG.info("抢购成功");
				} else {
					LOG.info("抢购失败");
				}
				return exec;
			} else {
				LOG.info("商品库存不足");
				return null;
			}
		}
	});
	return true;
}

一般来说,数据库(MySQL)作为标准的持久化存储,Redis 作为性能跟高的缓存使用,所以有两大步骤:

1. Redis数据初始化

既然 Redis 是缓存,就要考虑什么时候把初始化的数据存入到数据库,可以在抢购前先查询库存再存入Redis中,也可以在项目启动时初始化,在标记为@PostConstruct的方法中把输入存入Redis

2. 执行事务

redisTemplate.execute()是执行器方法,可以执行一系列的操作
使用Redis事务时:

redisTemplate.execute(new SessionCallback<List<Object>>) {
	@Override
	public List<Object> execute(RedisOperations operations) throws DataAccessException {
	}
}

基本上是固定写法了。

监听 -> 开启事务 -> 读写数据 -> 执行事务

Redis 过期处理

对存储在 Redis 数据库中的值可以设置一个过期时间
设置 key 的有效时间 Expires 字典保存了所有键的过期时间

格式

在这里插入图片描述

删除策略
1.惰性删除

每次查询或写键时,都会检查取得的键是否过期。如果过期就删除,否则就返回该键

2.定期删除

每个一段时间,就对数据库进行检查,删除里面的过期键

3.定时删除

在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除

注册用户的性能优化

在这里插入图片描述
将邮箱以及对应的用户数据缓存在 Redis 里,每次校验先从 Redis 里查询用户数据。减少对数据库的访问

当用户数据更新时,也需要实时更新 Redis 数据
例如判断邮箱是否已经被注册过的逻辑

//每次先去 Redis 校验
String pwd = (String) redisTemplate.opsForValue().get(userDO.getEmail());
//当redis没有数据时再去数据库查询
if (StringUtils.isEmpty(pwd)) {
	//redis 缓存没有,为了安全起见
	UserDO user = userDAO.selectByEamil(userDO.getEmail());
	if (user != null) {
		LOG.info("邮箱已经被注册过了");
		return false;
	}
}
redisTemplate.opsForValue().set(userDO.getEmail(), userDO.getPassword());
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值