当前位置: 首页 > wzjs >正文

做一个商城网站需要多少钱seo优化

做一个商城网站需要多少钱,seo优化,学技术网站,旅行社手机网站建设方案基于redis的分布式锁 lua脚本解决原子性 之前我们实现的乐观锁和悲观锁来控制超卖有一定效果,但它们都只能在单机环境下生效。在分布式系统中,我们需要更强大的锁机制来确保跨多个服务实例的数据一致性。Redisson是一个在Redis基础上实现的Java分布式服务…

基于redis的分布式锁 lua脚本解决原子性

之前我们实现的乐观锁和悲观锁来控制超卖有一定效果,但它们都只能在单机环境下生效。在分布式系统中,我们需要更强大的锁机制来确保跨多个服务实例的数据一致性。Redisson是一个在Redis基础上实现的Java分布式服务,它提供了强大的分布式锁实现,可以帮助我们解决分布式环境下的并发控制问题。

分布式锁:满足分布式系统或集群模式下多进程可见并且互斥的锁

分布式锁的核心思想就是让大家都使用同一把锁,只要大家使用的是同一把锁,那么我们就能锁住线程,不让线程进行,让程序串行执行,这就是分布式锁的核心思路

事实上我们有很多实现分布式锁的方法 但redis优势更大一些 接下来我们用redis来实现一下分布式锁

主要分两步

  • 获取锁:
    • 互斥:确保只能有一个线程获取锁
    • 非阻塞:尝试一次,成功返回true,失败返回false
  • 释放锁:
    • 手动释放
    • 超时释放:获取锁时添加一个超时时间

我们利用redis 的setNx 方法,当有多个线程进入时,我们就利用该方法,第一个线程进入时,redis 中就有这个key 了,返回了1,如果结果是1,则表示他抢到了锁,那么他去执行业务,然后再删除锁,退出锁逻辑,没有抢到锁的哥们,等待一定时间后重试即可

public class SimpleRedisLock implements ILock{//不同的业务应该有不同的所private String name;private StringRedisTemplate stringRedisTemplate;//给锁加一个前缀private static final String KEY_PREFIX="lock:";//接收用户传递给我们的参数public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) {this.name = name;this.stringRedisTemplate = stringRedisTemplate;}/*** 尝试获取锁** @param timeoutSec* @return*/@Overridepublic boolean tryLock(long timeoutSec) {//获取线程标识long thresdId = Thread.currentThread().getId();//获取锁——如果不存在才执行:nxBoolean success = stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX+name,threadId+"", timeoutSec, TimeUnit.SECONDS);/*** 若success是true,这里返回true* 若sucess是false,这里返回false* 若这里为空,返回的也是false* 避免空指针异常*/return Boolean.TRUE.equals(success);}/*** 释放锁*/@Overridepublic void unlock() {stringRedisTemplate.delete(KEY_PREFIX+name);}
}
//足够,创建订单Long userId = UserHolder.getUser().getId();//创建锁对象SimpleRedisLock lock = new SimpleRedisLock("order" + userId, stringRedisTemplate);//获取锁boolean isLock = lock.tryLock(1200);//判断是否获取锁成功if (!isLock) {//获取锁失败,返回错误return Result.fail("不允许重复下单!");}try {//获取代理对象(事务)IVoucherOrderService proxy= (IVoucherOrderService) AopContext.currentProxy();return proxy.createVoucherOrder(voucherId);} finally {//释放锁lock.unlock();}

这样我们在测试的时候就会发现 我们虽然部署两台tomcat服务器 但锁不仅仅是在一个jvm中的 而是作用域全局的

但还有一些问题 例如 持有锁的线程在锁的内部出现了阻塞,导致他的锁自动释放,这时其他线程,线程2来尝试获得锁,就拿到了这把锁,然后线程2在持有锁执行过程中,线程1反应过来,继续执行,而线程1执行过程中,走到了删除锁逻辑,此时就会把本应该属于线程2的锁进行删除,这就是误删别人锁的情况说明

解决起来也很简单 解决方案就是在每个线程释放锁的时候,去判断一下当前这把锁是否属于自己,如果属于自己,则不进行锁的删除,假设还是上边的情况,线程1卡顿,锁自动释放,线程2进入到锁的内部执行逻辑,此时线程1反应过来,然后删除锁,但是线程1,一看当前这把锁不是属于自己,于是不进行删除锁逻辑,当线程2走到删除锁逻辑时,如果没有卡过自动释放锁的时间点,则判断当前这把锁是属于自己的,于是删除这把锁。(是不是很像版本号法解决)

  1. 修改之前的分布式锁实现,满足:在获取锁时存入线程标示(可以用UUID表示)
    在释放锁时先获取锁中的线程标示,判断是否与当前线程标示一致
  2. 如果一致则释放锁 如果不一致则不释放锁
    核心逻辑:在存入锁时,放入自己线程的标识,在删除锁时,判断当前这把锁的标识是不是自己存入的,如果是,则进行删除,如果不是,则不进行删除。
    /*** 释放锁*/@Overridepublic void unlock() {//获取线程标识String thresdId = ID_PREFIX+Thread.currentThread().getId();//获取锁中的标识String id = stringRedisTemplate.opsForValue().get(KEY_PREFIX + name);//判断标识是否一致if (threadId.equals(id)) {stringRedisTemplate.delete(KEY_PREFIX+name);}}

这样就解决我们刚刚的问题了

假设还有更极端的一种情况

线程1现在持有锁之后,在执行业务逻辑过程中,他正准备删除锁,而且已经走到了条件判断的过程中,比如他已经拿到了当前这把锁确实是属于他自己的,正准备删除锁,但是此时他的锁到期了,那么此时线程2进来,但是线程1他会接着往后执行,当他卡顿结束后,他直接就会执行删除锁那行代码,相当于条件判断并没有起到作用,这就是删锁时的原子性问题,之所以有这个问题,是因为线程1的拿锁,比锁,删锁,实际上并不是原子性的,我们要防止刚才的情况发生

就需要lua登场了 lua是一种脚本语言 Redis提供了Lua脚本功能,在一个脚本中编写多条Redis命令,确保多条命令执行时的原子性。这里重点介绍Redis提供的调用函数,我们可以使用lua去操作redis,又能保证他的原子性,这样就可以实现拿锁比锁删锁是一个原子性动作了

这里重点介绍Redis提供的调用函数,语法如下:

redis.call('命令名称', 'key', '其它参数', ...)
# 先执行 set name jack
redis.call('set', 'name', 'Rose')
# 再执行 get name
local name = redis.call('get', 'name')
# 返回
return name

如果脚本中的key、value不想写死,可以作为参数传递。key类型参数会放入KEYS数组,其它参数会放入ARGV数组,在脚本中可以从KEYS和ARGV数组获取这些参数:

EVAL "return redis.call('set',KEYS[1],ARGV[1])" 1 name tom

因此我们可以改造一下 我们希望最后两步保证原子性 因此只需要把最后两步写入lua脚本 执行即可

-- 比较线程标示与锁中的标示是否一致
if(redis.call('get', KEYS[1]) ==  ARGV[1]) then-- 释放锁 del keyreturn redis.call('del', KEYS[1])
end
return 0
private static final DefaultRedisScript<Long> UNLOCK_SCRIPT;static {UNLOCK_SCRIPT = new DefaultRedisScript<>();UNLOCK_SCRIPT.setLocation(new ClassPathResource("unlock.lua"));UNLOCK_SCRIPT.setResultType(Long.class);}public void unlock() {// 调用lua脚本stringRedisTemplate.execute(UNLOCK_SCRIPT,Collections.singletonList(KEY_PREFIX + name),ID_PREFIX + Thread.currentThread().getId());
}

基于Redis的分布式锁实现思路:

  • 利用set nx ex获取锁,并设置过期时间,保存线程标示
  • 释放锁时先判断线程标示是否与自己一致,一致则删除锁
    • 特性:
      • 利用set nx满足互斥性
      • 利用set ex保证故障时锁依然能释放,避免死锁,提高安全性
      • 利用Redis集群保证高可用和高并发特性
http://www.dtcms.com/wzjs/350824.html

相关文章:

  • 知名网站规划网站优化seo是什么意思
  • wordpress 数据库配置文件天津seo招聘
  • 公司网站建设需要显示什么国内手机搜索引擎十大排行
  • 做爰全过程网站免费的视频seo网址
  • 中午网站做google广告好吗一个关键词要刷多久
  • 青岛网络营销网络推广介绍seo关键词外包
  • 深圳推荐企业网站制作维护友情链接交换
  • 简述建设一个网站的过程推广软文发布平台
  • 乐清最新招聘信息网seo顾问什么职位
  • 手机网站关闭窗口代码百度百家号怎么赚钱
  • 建网站要大约多少钱百度软件
  • 网站改版的方式大致有福州百度快速优化
  • 一个人做企业网站要多少天郑州seo网站有优化
  • 网站服务器搭建XP磁力狗bt
  • 建设局网站管理办法深圳网站建设找哪家公司好
  • vps搭建vpn无法访问国内网站短链接在线生成器
  • 公司网站推广计划书怎么做百度seo自动优化
  • 阿里云服务器在哪里seo研究中心
  • 站内搜索本网站怎么做seo整站优化服务教程
  • 有什么网站可以做3d天津百度推广电话
  • 免费企业网站创建曼联对利物浦新闻
  • wordpress调用文章发布时间seo包括什么
  • 建设网站如何写文案北京网站制作
  • 对视频播放网站做性能测试整站优化工具
  • 网站兼容所有浏览器四川seo哪里有
  • 宝应吧 百度贴吧关键词优化公司靠谱推荐
  • 校园官方网站如何制作搜索引擎优化包括哪些方面
  • 网站建设 团队怎么推广一个网站
  • 如何查询某个网站的设计公司宁波网站建设公司
  • 网站 域名推广员是做什么的