企业网站建设验收,网站如何赚钱,wordpress 加密查看,国内常见的博客网站不管是jvm锁还是mysql锁#xff0c;为了保证线程的并发安全#xff0c;都提供了悲观独占排他锁。所以独占排他也是分布式锁的基本要求。
可以利用唯一键索引不能重复插入的特点实现。设计表如下#xff1a;
CREATE TABLE tb_lock (id bigint(20) NOT NULL AUTO_INCREMENT,… 不管是jvm锁还是mysql锁为了保证线程的并发安全都提供了悲观独占排他锁。所以独占排他也是分布式锁的基本要求。
可以利用唯一键索引不能重复插入的特点实现。设计表如下
CREATE TABLE tb_lock (id bigint(20) NOT NULL AUTO_INCREMENT,lock_name varchar(50) NOT NULL COMMENT 锁名,class_name varchar(100) DEFAULT NULL COMMENT 类名,method_name varchar(50) DEFAULT NULL COMMENT 方法名,server_name varchar(50) DEFAULT NULL COMMENT 服务器ip,thread_name varchar(50) DEFAULT NULL COMMENT 线程名,create_time timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT 获取锁时间,desc varchar(100) DEFAULT NULL COMMENT 描述,PRIMARY KEY (id),UNIQUE KEY idx_unique (lock_name)
) ENGINEInnoDB AUTO_INCREMENT1332899824461455363 DEFAULT CHARSETutf8;
Lock实体类
Data
AllArgsConstructor
NoArgsConstructor
TableName(tb_lock)
public class Lock {private Long id;private String lockName;private String className;private String methodName;private String serverName;private String threadName;private Date createTime;private String desc;
}
LockMapper接口
public interface LockMapper extends BaseMapperLock {
}
4.1. 基本思路 synchronized关键字和ReetrantLock锁都是独占排他锁即多个线程争抢一个资源时同一时刻只有一个线程可以抢占该资源其他线程只能阻塞等待直到占有资源的线程释放该资源。 线程同时获取锁insert 获取成功执行业务逻辑执行完成释放锁delete 其他线程等待重试 4.2. 代码实现
改造StockService
Service
public class StockService {Autowiredprivate StockMapper stockMapper;Autowiredprivate LockMapper lockMapper;/*** 数据库分布式锁*/public void checkAndLock() {// 加锁Lock lock new Lock(null, lock, this.getClass().getName(), new Date(), null);try {this.lockMapper.insert(lock);} catch (Exception ex) {// 获取锁失败则重试try {Thread.sleep(50);this.checkAndLock();} catch (InterruptedException e) {e.printStackTrace();}}// 先查询库存是否充足Stock stock this.stockMapper.selectById(1L);// 再减库存if (stock ! null stock.getCount() 0){stock.setCount(stock.getCount() - 1);this.stockMapper.updateById(stock);}// 释放锁this.lockMapper.deleteById(lock.getId());}
}
加锁
// 加锁
Lock lock new Lock(null, lock, this.getClass().getName(), new Date(), null);
try {this.lockMapper.insert(lock);
} catch (Exception ex) {// 获取锁失败则重试try {Thread.sleep(50);this.checkAndLock();} catch (InterruptedException e) {e.printStackTrace();}
}
解锁
// 释放锁
this.lockMapper.deleteById(lock.getId());
使用Jmeter压力测试结果 可以看到性能感人。mysql数据库库存余量为0可以保证线程安全。
4.3. 缺陷及解决方案
缺点 这把锁强依赖数据库的可用性数据库是一个单点一旦数据库挂掉会导致业务系统不可用。 解决方案给 锁数据库 搭建主备 这把锁没有失效时间一旦解锁操作失败就会导致锁记录一直在数据库中其他线程无法再获得到锁。 解决方案只要做一个定时任务每隔一定时间把数据库中的超时数据清理一遍。 这把锁是非重入的同一个线程在没有释放锁之前无法再次获得该锁。因为数据中数据已经存在了。 解决方案记录获取锁的主机信息和线程信息如果相同线程要获取锁直接重入。 受制于数据库性能并发能力有限。 解决方案无法解决。