基于DB排他锁(悲观锁)
方式:<br><br> public boolean lock(){<br> connection.setAutoCommit(false)<br> while(true){<br> try{<br> result = <b><font color="#c41230">select * from methodLock where method_name=xxx for update</font></b>;<br> if(result==null){<br> return true;<br> }<br> }catch(Exception e){<br> <br> }<br> sleep(1000);<br> }<br> return false;<br> }<br><br>
要给method_name添加唯一性索引
1. 会不会阻塞?
其他事务如果select... for update失败,则会一直阻塞
阻塞也会带来线程池撑爆风险
缺点
1. 使用不当会死锁
2. 性能上有额外开销
3. 加锁列如果不加索引会导致表锁
基于DB表记录的唯一性索引
瑜伽案例
CREATE TABLE `database_lock` (<br> `id` BIGINT NOT NULL AUTO_INCREMENT,<br> `resource` int NOT NULL COMMENT '锁定的资源',<br> `description` varchar(1024) NOT NULL DEFAULT "" COMMENT '描述',<br> PRIMARY KEY (`id`),<br> UNIQUE KEY `uiq_idx_resource` (`resource`) <br>) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据库分布式锁表';<br>//加锁<br>INSERT INTO database_lock(resource, description) VALUES (1, 'lock');<br>//解锁<br>DELETE FROM database_lock WHERE resource=1;<br><br>
缺点
锁没有失效时间,如果解锁失败会一直留在数据库中;可以用定时任务去清理
不可重入,同一个线程在释放之前无法再次获取锁
主从同步延迟?
基于DB乐观锁
CREATE TABLE `optimistic_lock` (<br> `id` BIGINT NOT NULL AUTO_INCREMENT,<br> `resource` int NOT NULL COMMENT '锁定的资源',<br> `version` int NOT NULL COMMENT '版本信息',<br> `created_at` datetime COMMENT '创建时间',<br> `updated_at` datetime COMMENT '更新时间',<br> `deleted_at` datetime COMMENT '删除时间', <br> PRIMARY KEY (`id`),<br> UNIQUE KEY `uiq_idx_resource` (`resource`) <br>) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据库分布式锁表';<br>//<br>//1. 加锁<br> <font color="#f15a23"><b>SELECT resource, version FROM optimistic_lock WHERE id = 1</b></font><br>//2. 执行业务逻辑<br>//3. 解锁<br><b><font color="#f15a23">UPDATE optimistic_lock SET resource = resource -1, version = version + 1 WHERE id = 1 AND version = oldVersion</font></b><br>
缺点
并发小的时候,有少量请求会失败;大促、秒杀场景下,会有大量请求作用于同一条行锁,对数据库有很大的写压力
缺点
1. 在数据量比较少的时候,会进行表锁,而不是行锁
2. 需要占用DB连接
3. 依赖数据库,避免单点