redis缓存管理问题

3 篇文章 0 订阅
2 篇文章 0 订阅

springboot redis缓存功能的初步了解和使用

之前做了用注解的方式管理缓存的功能,但是现在发现可能会发生问题。那就是注解的@CacheEvict和@CachePut行为是立即发生的,而不是事务提交后再调用,而事务回退了缓存也不会回退。

我先测试了@CachePut

@Service
public class MachineRuntimeServiceImpl implements IMachineRuntimeService {	
    @Override
	@Transactional(rollbackFor=Exception.class)
	public void saveMachine(String userId, EqMachineInfoModel machine, Long time) throws Exception {
		//1.保存当前的机器信息
		{
			machineDao.save(machine);
			if(time != null) {
				Thread.sleep(time);
			}
			if(machine.getMachineName().equals("error"))
				throw new Exception("自定义抛出异常");
		}
		
	}
}
@Repository
public interface MachineDao extends JpaRepository<EqMachineInfoModel, Integer>{
    @Cacheable(value = "machineModel", key = "'machineModel'+#p0")
	EqMachineInfoModel findOne(Integer machineId);

	@CachePut(value = "machineModel", key = "'machineModel'+#p0.id")
	EqMachineInfoModel save(EqMachineInfoModel machine);
}
@Controller
public class TestAction {
	Logger logger = LoggerFactory.getLogger(this.getClass());
	@Resource
	IMachineRuntimeService machineRuntimeService;
	@RequestMapping(value="/saveTest")
	@ResponseBody
	public String saveTest(@RequestParam(value="time",required=false)Long time
			, @RequestParam(value="machineId",required=false)int machineId
			, @RequestParam(value="machineName",required=false)String machineName) {
		String result = "success";
		try {
			EqMachineInfoModel machine = machineRuntimeService.getMachineById("", machineId);
			machine.setMachineName(machineName);
			machineRuntimeService.saveMachine("", machine, time);
		} catch (Exception e) {
			result = "fail";
			logger.info(e.getMessage(), e);
			// TODO: handle exception
		}
		return result;
	}
	@RequestMapping(value="/getTest")
	@ResponseBody
	public EqMachineInfoModel getTest(@RequestParam(value="machineId",required=false)int machineId) throws Exception {
		EqMachineInfoModel machine = machineRuntimeService.getMachineById("", machineId);
		return machine;
	}
}

发出请求 /saveTest?machineName=error&machineId=10000000&time=0

在save方法后故意抛出异常,结果缓存里的machineName变成了error,而数据库里的machineName并没有变。

 

@CacheEvict则比较安全,即使修改失败了,缓存也只是被删除而不是变成错误的值。所以我们使用了这种策略,一开始使用的确没有问题,但是后来还是发现了问题。还是事务的问题,save方法时缓存的确被删除了,但是在save方法事务提交之前,如果有另外的接口调用了findOne方法,就会查询到修改前的缓存,这时事务再提交,查询到的还是之前的缓存。当然,概率比较低,但是还是有可能发生。

把@CacheEvict改成@CachePut

@Repository
public interface MachineDao extends JpaRepository<EqMachineInfoModel, Integer>{
    @Cacheable(value = "machineModel", key = "'machineModel'+#p0")
	EqMachineInfoModel findOne(Integer machineId);

	@CacheEvict(value = "machineModel", key = "'machineModel'+#p0.id")
	EqMachineInfoModel save(EqMachineInfoModel machine);
}

请求 /saveTest?machineName=mmm2&machineId=10000000&time=10000

在十秒钟之内请求 /getTest?machineId=10000000最后缓存里面还是老的数据,数据库里面是更新后的数据。

要解决这个问题,初步的设想是在事务提交后再更新或删除缓存,不过删除缓存实现会简单很多。

使用监听器实现在事务提交后发送消息

我会尝试用注解切面编程的方式实现。

另一种方式是使用锁,不管是查询还是编辑,跟缓存有关的都加上锁,不过这明显太复杂,并且会影响效率,失去了缓存的初衷。

不过我很好奇,这个问题应该十分常见,难道别人没有碰到过这种问题吗?难道springboot没有考虑到事务的影响吗?所以我还是会找找看有没有现成的方案

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值