幂等性是指:同一个操作,执行多次,后台的业务处理结果都是一样的
发生原因:交通卡开卡,充值接口,有个测试同学他突然发觉我们开卡,充值接口因为其实开卡成功,充值钱到交通卡芯片里面是在倒数第二次apud指令就完成了,然后他就就可以无限开卡,然后退款(他还没出钱),他可以明明充值成功,但是还是劫持指令,让最好一次收到结果是充值失败,他用这个交易序号连续充值,让每次都失败。
原因就是这部分逻辑没有保证幂等性。
解决办法:将每次充值的交易序号保存下来,在每次进行充值时候都做合法性交易,这个交易我已经有了,你不能再使用了,直接报错,没有就保存到表里面。
然后了解到右很多其它保证幂等性的方法,虽然我们这里可能不适合用。
一、数据库幂等性
1、悲观锁幂等性
悲观锁就是我觉得一定有人修改记录,所以我操作时候都加锁,只有我一个人获取到cpu资源。
Eg:select issuerid from a where id =xxx for update。这里加for update就是加锁,然后id需要是唯一索引或者主键id,否则就锁表了
2、乐观锁幂等性
乐观锁就是乐观认为不会有人修改,但是他在修改数据时候也会校验下数据是否已经被修改过了,故一般使用版本号/时间戳去作为条件校验下是否可以修改
eg:先查询数据库获得版本号,然后更新数据时候带上版本号,如果一致就更新,不一致就不更新
3、唯一索引
eg:对数据唯一字段加上索引,这样我们重复插入时候就会报错
4、状态机幂等
这个很重要,特别是有状态,生命周期管理的项目
交通卡这边有个订单,比如充值状态这样变化:未支付-已支付-开始充值-充值成功,就是状态你只能从前面变道后面,不能从后面变成前面,这样就保证高并发多请求情况下,状态不会随便乱变,比如不会从已支付变为未支付,什么意思,都支付了怎么又未支付了
二、jvm的幂等
就是使用lock,Synchronized这种去锁资源,但是比如lock他适合单机环境啊,在现在的分布式集群环境下是不行的
三、分布式锁幂等
我们可以使用redis的分布式锁来进行幂等性,分布式锁就是高并发多请求情况下,不是上来每个都去执行业务,而是先拿到锁,拿到锁才能执行业务,比如redis通过setNx获取锁,拿到才执行业务,然后记得设置过期时间。
一般是用唯一标识作为key。