设为首页 - 加入收藏 ASP站长网(Aspzz.Cn)- 科技、建站、经验、云计算、5G、大数据,站长网!
热搜: 创业者 数据 手机
当前位置: 首页 > 站长学院 > MySql教程 > 正文

为什么Zookeeper天生就是一副分布式锁的胚子?(4)

发布时间:2020-03-15 20:08 所属栏目:115 来源:站长网
导读:`description`varchar(1024)NOTNULLDEFAULTCOMMENT'描述', PRIMARYKEY(`id`), UNIQUEKEY`uiq_idx_resource`(`resource`) )ENGINE=InnoDBDEFAULTCHARSET=utf8mb4COMMENT='数据库分布式锁表'; ①获得锁 我们可以插入

`description` varchar(1024) NOT NULL DEFAULT "" COMMENT '描述', 

PRIMARY KEY (`id`), 

UNIQUE KEY `uiq_idx_resource` (`resource`) 

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据库分布式锁表'; 

①获得锁

我们可以插入一条数据:

INSERT INTO database_lock(resource, description) VALUES (1, 'lock'); 

因为表 database_lock 中 resource 是唯一索引,所以其他请求提交到数据库,就会报错,并不会插入成功,只有一个可以插入。插入成功,我们就获取到锁。

②删除锁

INSERT INTO database_lock(resource, description) VALUES (1, 'lock'); 

这种实现方式非常的简单,但是需要注意以下几点:

①这种锁没有失效时间,一旦释放锁的操作失败就会导致锁记录一直在数据库中,其他线程无法获得锁。这个缺陷也很好解决,比如可以做一个定时任务去定时清理。

②这种锁的可靠性依赖于数据库。建议设置备库,避免单点,进一步提高可靠性。

③这种锁是非阻塞的,因为插入数据失败之后会直接报错,想要获得锁就需要再次操作。

如果需要阻塞式的,可以弄个 for 循环、while 循环之类的,直至 INSERT 成功再返回。

④这种锁也是非可重入的,因为同一个线程在没有释放锁之前无法再次获得锁,因为数据库中已经存在同一份记录了。

想要实现可重入锁,可以在数据库中添加一些字段,比如获得锁的主机信息、线程信息等。

那么在再次获得锁的时候可以先查询数据,如果当前的主机信息和线程信息等能被查到的话,可以直接把锁分配给它。

乐观锁

顾名思义,系统认为数据的更新在大多数情况下是不会产生冲突的,只在数据库更新操作提交的时候才对数据作冲突检测。如果检测的结果出现了与预期数据不一致的情况,则返回失败信息。

为什么Zookeeper天生就是一副分布式锁的胚子?

乐观锁大多数是基于数据版本(version)的记录机制实现的。何谓数据版本号?

即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表添加一个 “version”字段来实现读取出数据时,将此版本号一同读出,之后更新时,对此版本号加 1。

在更新过程中,会对版本号进行比较,如果是一致的,没有发生改变,则会成功执行本次操作;如果版本号不一致,则会更新失败。

为了更好的理解数据库乐观锁在实际项目中的使用,这里也就举了业界老生常谈的库存例子。

一个电商平台都会存在商品的库存,当用户进行购买的时候就会对库存进行操作(库存减 1 代表已经卖出了一件)。

如果只是一个用户进行操作数据库本身就能保证用户操作的正确性,而在并发的情况下就会产生一些意想不到的问题。

比如两个用户同时购买一件商品,在数据库层面实际操作应该是库存进行减 2 操作。

但是由于高并发的情况,第一个用户购买完成进行数据读取当前库存并进行减 1 操作,由于这个操作没有完全执行完成。

第二个用户就进入购买相同商品,此时查询出的库存可能是未减 1 操作的库存导致了脏数据的出现【线程不安全操作】。

数据库乐观锁也能保证线程安全,通常代码层面我们都会这样做:

(编辑:ASP站长网)

网友评论
推荐文章
    热点阅读