基于数据库的分布式锁(基于主键id和唯一索引)
1基于主键实现分布式锁
2基于唯一索引实现分布式锁
其实原理一致,都是采用一个唯一的标识进行判断是否加锁。
原理:通过主键或者唯一索性两者都是唯一的特性,如果多个服务器同时请求到数据库,数据库只会允许同一时间只有一个服务器的请求在对数据库进行操作,其他服务器的请求就需要进行阻塞等待或者进行自旋。如何实现的呢?可以理解为同一时间只有一个请求能够拿到锁,当方法执行完成过后,对锁进行释放过后,其他请求就可以拿到锁再对数据库进行操作,这样就避免了数据不安全问题。
阻塞:线程等待锁释放的一种方式
自旋:自旋包括了递归自旋,while自旋。意思就是不断地去尝试获取锁,只有获取锁才会停止自旋过程,没有拿到就会一直尝试获取锁。
以下是一个基于MySQL实现分布式锁的示例代码:
import java.sql.*;
import java.util.Properties;
public class DatabaseLock {
private Connection conn;
private static final String dbUrl = "jdbc:mysql://localhost:3306/test";
private static final String username = "xxxx";
private static final String password = "xxxxx";
// 构造函数,建立数据库连接
public DatabaseLock() throws SQLException {
Properties props = new Properties();
props.setProperty("user", username);
props.setProperty("password", password);
conn = DriverManager.getConnection(dbUrl, props);
}
// 尝试获取锁
public boolean tryLock(String lockId) throws SQLException {
PreparedStatement stmt = conn.prepareStatement("INSERT INTO locks (id) VALUES (?)");
stmt.setString(1, lockId);
try {
stmt.executeUpdate();
return true;
} catch (SQLException e) {
if (e.getErrorCode() == 1062) { // 锁已存在
return false;
} else {
throw e;
}
}
}
// 释放锁
public void releaseLock(String lockId) throws SQLException {
PreparedStatement stmt = conn.prepareStatement("DELETE FROM locks WHERE id=?");
stmt.setString(1, lockId);
stmt.executeUpdate();
}
}
在使用时,通过创建一个DatabaseLock实例来获取和释放锁:
DatabaseLock databaseLock = new DatabaseLock();
// 尝试获取锁,获取成功返回true,获取失败返回false
if (databaseLock.tryLock("lockId")) {
try {
// do something
} finally {
databaseLock.releaseLock("lockId"); // 释放锁
}
} else {
// get lock failed
}
基于Redis的分布式锁
下面就来介绍基于Redis的分布式锁,直接上图;

虚拟机A和虚拟机B两个虚拟机都想对可变的共享资源(广义的概念,可以是数据库的某一张表和数据库中的某一行数据 ),就会出现线程安全问题,就需要基于锁模型实现同步互斥的手段,保证只有一个虚拟机中的线程进而实现这个线程的相对安全。现在虚拟机要对共享资源上锁,锁对象是Redis,操作的对象就是这个共享资源(假如数据库的一行数据)。
基于Redis实现分布式锁执行流程:
1虚拟机实例A根据Hash算法选择Redis节点(Redis采用的是集群部署,每个服务器都是一个节点),执行Lua脚本加锁(就是通过setnx方法,即set一个key(主键id)到Redis当中,判断Redis中是否有当前key,没有,就返回1,表示加锁成功,有就返回0,表示加锁失败),并且设置锁的过期时间。当虚拟机A对共享资源上锁成功过后,就拥有了对共享数据的操作权限,然后就可以对共享数据的操作处理,执行事务处理。
问题:在从Redis获取锁的过程和进行设置锁的过期时间过程中出现宕机,就会出现锁一辈子不会被释放?出现死锁问题?

最低0.47元/天 解锁文章
1万+

被折叠的 条评论
为什么被折叠?



