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

织梦 我的网站做易拉宝设计的网站

织梦 我的网站,做易拉宝设计的网站,做电商网站需要注册什么公司,找网页设计公司去哪个平台大家好#xff0c;今天我们来看下如何使用本地MySql实现一把分布式锁#xff0c;以及Mysql实现分布式锁的原理是怎么样的 MySql实现分布式锁有三种方式 1#xff1a;基于行锁实现分布式锁 k1.png 实现原理 首先我们的表lock要提前存好相对应的lockName#xff0c;这时候…大家好今天我们来看下如何使用本地MySql实现一把分布式锁以及Mysql实现分布式锁的原理是怎么样的 MySql实现分布式锁有三种方式 1基于行锁实现分布式锁 k1.png 实现原理 首先我们的表lock要提前存好相对应的lockName这时候多个客户端来执行 select lock_name from lock where lock_name #{lockName} for update 由于第一个客户端来执行这条sql语句给这行记录加了行锁在这个客户端没有提交事务之前其它客户端就会被阻塞住。所以这时候就只能有一个客户端去执行我们自己的业务了其它客户端就只能阻塞等待那么这个过程就是加锁 那么释放锁该怎么操作呢 其实释放锁就很简单了也就是将获取到锁的这个客户端的事务提交这样其它客户端就可以来获取到这把行锁了所以这时候就需要我们手动的提交事务了 代码实现 首先就是编写我们的加锁SQL语句了 Select(“select lock_name from lock where lock_name #{lockName} for update”) List queryLockNameForUpdate(Param(“lockName”) String lockName); 然后我们需要实现我们的加锁 和 解锁 public class MySqlDistributeLock { //加锁的KEY也就是我们提前存到表lock的值 private String lockName;//手动提交事务需要的事务管理器,由外部传入 private DataSourceTransactionManager dataSourceTransactionManager;//自定义编写的mybatis的mapper文件 private MySqlLockMapper mySqlLockMapper;private TransactionStatus status;public MySqlDistributeLock(String lockName,DataSourceTransactionManager dataSourceTransactionManager,MySqlLockMapper mySqlLockMapper) {this.lockName lockName;this.dataSourceTransactionManager dataSourceTransactionManager;this.mySqlLockMapper mySqlLockMapper; }public void lock() {TransactionDefinition transactionDefinition new DefaultTransactionDefinition();status dataSourceTransactionManager.getTransaction(transactionDefinition);while (true) {try{mySqlLockMapper.queryLockNameForUpdate(this.lockName);//如果加锁成功就退出该循环break;}catch (Exception e) {//说明抛出异常了,让线程重试try {//让线程休眠一会Thread.sleep(100);} catch (InterruptedException ignored) { }}} }public void unLock() {//手动提交事务,也就是释放锁dataSourceTransactionManager.commit(this.status); }} 最后看下业务方如何使用 Service public class LockService { Resource private DataSourceTransactionManager dataSourceTransactionManager;Resource private MySqlDistributeLock.MySqlLockMapper mySqlLockMapper;public String deductStockMysqlLock(String productId,Integer count) {MySqlDistributeLock lock null;try{lock new MySqlDistributeLock(productId,dataSourceTransactionManager,mySqlLockMapper);//加锁lock.lock();//加锁成功开始执行我们自己的业务逻辑}finally {if(lock ! null) {lock.unLock();}}return success; }} 2基于唯一索引实现分布式锁 k2.png 实现原理 首先我们的lock表要给lock_name字段建立一个唯一索引这时候有多个客户端来加锁本质上也就是添加一条记录只不过lockName的值都是一样的 这时候客户端A成功的把lockName保存到lock表中了那么其它客户端要保存这个lockName的时候(也就是执行加锁),由于唯一索引的缘故就会插入失败。也就保证了同一个时间只能有一个客户端保存成功也就是加锁成功了 那么如何释放锁呢 在这个客户端业务执行完之后手动的把这条记录删除掉那么其它客户端就可以来继续加锁了 代码实现 首先我们在mapper文件中编写 加锁 和 解锁 的SQL这里为什么还要保存个uuid后续会讲到主要是防止锁被误删 //加锁语句 Insert(“insert into record_lock (lock_name, uuid) values (#{lockName}, #{uuid})”) Integer insert(Param(“lockName”) String lockName, Param(“uuid”) String uuid); //解锁语句 Delete(“delete from record_lock where lock_name #{lockName} and uuid #{uuid}”) Integer delete(Param(“lockName”) String lockName, Param(“uuid”) String uuid); 然后我们需要实现我们的加锁 和 解锁 public class MySqlDistributeLock { private String lockName;//自定义编写的mybatis的mapper文件 private MySqlLockMapper mySqlLockMapper;private String uuid;public MySqlDistributeLock(String lockName,MySqlLockMapper mySqlLockMapper,String uuid) {this.lockName lockName;this.mySqlLockMapper mySqlLockMapper;this.uuid uuid; }public void lock() {while (true) {try{int result mySqlLockMapper.insert(this.lockName, this.uuid);if(result 0) {//代表加锁成功break;}} catch (Exception e) {}//唯一索引加锁失败try {Thread.sleep(100);} catch (InterruptedException interruptedException) {throw new RuntimeException();}} }public void unLock() {mySqlLockMapper.delete(this.lockName,this.uuid); }} 最后看下业务方如何使用 Service public class LockService { Resource private MySqlDistributeLock.MySqlLockMapper mySqlLockMapper;public String deductStockMysqlLock(String productId,Integer count) {MySqlDistributeLock lock null;try{lock new MySqlDistributeLock(productId, mySqlLockMapper,UUID.randomUUID().toString());//加锁lock.lock();//加锁成功开始执行我们自己的业务逻辑}finally {if(lock ! null) {lock.unLock();}}return success; }} 基于唯一索引实现的分布式锁有没有什么问题呢 死锁问题 我们试想一下如果客户端A来加锁成功了业务也执行完了但是这时候释放锁的时候也就是执行删除语句的时候因为一些原因导致删除失败了那么这条记录一直存在后续的线程就没办法再获取到锁了这就是所谓的死锁 所以这时候我们还需要另外一个服务来定时扫描这些记录如果这个记录超过了10分钟或者20分钟还没有被删除掉那么大概率是释放锁的时候失败了所以需要再次删除这条记录 锁误删 为什么锁会误删呢 为了防止死锁我们会有一个单独的定时任务来扫描假设我们判断一把锁超过10分钟就认为是释放锁失败了这时候定时任务就会把这条记录删除掉但是这时候就会有问题了举个例子 客户端A首先获取到锁了然后开始执行业务但是因为业务比较复杂执行完业务可能需要15分钟这时候到第10分钟的时候定时任务就会把这条记录给删除掉了 这时候因为记录没有了客户端B来获取锁是能成功获取到的所以这时候这把锁的持有者应该是客户端B的 到第15分钟的时候客户端A业务执行完了就是执行释放锁的逻辑那么客户端A就会把这条记录给删除掉了也就导致客户端A把客户端B的锁给释放掉了 所以在开头的时候我们加锁除了要保存lockName,还要保存一个uuid,在释放锁的时候判断一下uuid是否相等如果不相等那就不能删除这条记录了因为这时候这把锁已经不是当前客户端持有的了 锁续期 大家可以想一下分布式锁的主要目的就是同一个时间点只能有一个线程去执行业务但是在上面我们可以看到即使加了uuid来保证了锁误删但是在 同一个时间点可能是有多个线程在一起执行业务的为了避免这种情况就需要保证一个客户端在没有执行完业务以前是不允许其它客户端执行业务的 但是定时任务判断的时间我们没办法预估可能业务需要10分钟也有可能是20分钟我们没办法准确预估这个时间 所以我们在一个客户端加锁成功之后可以起一个额外的线程时时的更新加锁的时间这就类似Redisson的看门狗机制了那么如何去做呢 1加锁的时候除了保存lockName,uuid,额外保存一个加锁时间lockTime 2加锁成功之后额外开启一个线程每过10秒就更新lockTime为当前时间 3定时任务扫描到lcokTime距离当前时间超过10分钟或者5分钟的记录就删除掉这条记录 3基于乐观锁实现分布式锁 基于乐观锁机制就是依靠版本机制来实现我们一般在数据库会保存version,或者是时间戳至于实现方式大家可以自己实现一下这里就不做赘述了
http://www.hkea.cn/news/14537435/

相关文章:

  • 中国十大购物网站排行榜集安网站制作
  • 能联系做仿瓷的网站关于美丽乡村建设的活动和网站
  • 用dw个人网站怎么建立网站开发中常用的技术和工具
  • 网站优化客户报表如何把qq音乐导入到wordpress
  • 怎样建立网站卖东西泉州网站建设方案详细
  • 网站首页模块网络美工是做什么的
  • 建电商网站要多少钱设计旅游网站的主色调
  • 1688网站如何运营互联网公司大厂排名
  • 泰安企业网站建设电话网站后端做留言板功能
  • 如何查看一个网站是用什么程序做的做app还是做网站
  • 个人网站备案技巧龙潭湖网站建设
  • 美食电子商务网站建设规划书哈尔滨优惠的网站建设
  • 邢台做网站推广服务做网站有哪些流程
  • 国内互联网建站公司排名紫色网站模板
  • 吉林网络推广公司电商网站优化方案
  • 教育一对一直播网站建设备案多个网站
  • 北京天仪建设工程质量检测所网站6孵化器网站平台建设
  • 广西百色建设局网站免费的网站域名和空间
  • 嘉祥县建设局官方网站广东网站seo
  • 湛江做网站开发哪些网站可以做微课
  • 做的网站怎么申请软件著作权网上接单干活的平台
  • 网站搭建十大品牌公司ae免费模板下载网站
  • wordpress存储镜像做网站和优化共多少钱
  • 廊坊做网站1766534168太原做网络推广
  • 建立网站需要投入的成本网站管理员密码忘记
  • 网站做推广的企业网站框架文案
  • 上海网站建设公司网广东网站建设网站
  • 湖南网站建设oqiandu中美关系最新消息2022年
  • 中太建设集团股份有限公司官方网站网站建设项目规划审批
  • 站长之家 seo查询阿里云 iis 多个网站