在Java中,分布式锁是一种在多个JVM或多台服务器上实现同步访问共享资源的机制,为了解决这个问题,我们可以使用以下三种方式来实现分布式锁:
(图片来源网络,侵删)
接下来,我们将详细介绍这三种实现方式的操作方法。
基于数据库的分布式锁
1、创建一个表,用于存储锁信息。
CREATE TABLEdistributed_lock
(id
bigint(20) NOT NULL AUTO_INCREMENT,resource_id
varchar(255) NOT NULL,lock_value
varchar(255) NOT NULL,expire_time
datetime NOT NULL, PRIMARY KEY (id
), UNIQUE KEYuk_resource_id
(resource_id
,lock_value
) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2、在Java代码中使用数据库操作进行加锁和解锁:
public class DistributedLock { private static final String LOCK_TABLE = "distributed_lock"; private static final String LOCK_COLUMN = "lock_value"; private static final String RESOURCE_ID = "resource_id"; private static final String EXPIRE_TIME = "expire_time"; public boolean lock() { Connection connection = null; PreparedStatement preparedStatement = null; try { connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "password"); String lockValue = generateLockValue(); // 生成锁值,例如UUID String updateSql = "INSERT INTO " + LOCK_TABLE + "(" + RESOURCE_ID + ", " + LOCK_COLUMN + ", " + EXPIRE_TIME + ") VALUES (?, ?, NOW() + INTERVAL 30 SECOND) ON DUPLICATE KEY UPDATE " + LOCK_COLUMN + " = ?, " + EXPIRE_TIME + " = NOW() + INTERVAL 30 SECOND"; preparedStatement = connection.prepareStatement(updateSql); preparedStatement.setString(1, "resource_id"); // 设置资源ID preparedStatement.setString(2, lockValue); // 设置锁值 preparedStatement.setString(3, lockValue); // 更新锁值和过期时间 int result = preparedStatement.executeUpdate(); return result > 0; // 如果插入成功,则表示获取锁成功 } catch (SQLException e) { e.printStackTrace(); } finally { if (preparedStatement != null) { try { preparedStatement.close(); } catch (SQLException e) { e.printStackTrace(); } } if (connection != null) { try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } return false; // 如果获取锁失败,则返回false } public void unlock() { Connection connection = null; PreparedStatement preparedStatement = null; try { connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "password"); String deleteSql = "DELETE FROM " + LOCK_TABLE + " WHERE " + RESOURCE_ID + " = 'resource_id' AND " + LOCK_COLUMN + " = 'lock_value'"; // 根据资源ID和锁值删除记录 preparedStatement = connection.prepareStatement(deleteSql); int result = preparedStatement.executeUpdate(); if (result > 0) { // 如果删除成功,则表示释放锁成功 System.out.println("释放锁成功"); } else { // 如果删除失败,则表示没有获取到锁,无需释放锁 System.out.println("没有获取到锁,无需释放锁"); } } catch (SQLException e) { e.printStackTrace(); } finally { if (preparedStatement != null) { try { preparedStatement.close(); } catch (SQLException e) { e.printStackTrace(); } } if (connection != null) { try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
基于Redis的分布式锁
1、使用Redis的SETNX命令实现加锁和解锁:
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; import java.util.concurrent.TimeUnit; import java.util.UUID; import javax.annotation.Resource; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; @Component("distributedLock") // Spring容器中的bean名称为distributedLock,以便在其他类中注入使用@Resource(name = "distributedLock") private DistributedLock distributedLock; public void doSomething() { if (distributedLock.lock()) { try { // 执行业务逻辑 } finally { distributedLock.unlock(); } } } @Override public boolean lock() { ValueOperations<String, String> valueOperations = this.redisTemplate.opsForValue(); String key = this.resourceId + this.lockValuePrefix; String lockValue = generateLockValue(); if (valueOperations.setIfAbsent(key, lockValue, this.lockExpireTime, TimeUnit.SECONDS)) { return true; } else { return false; } } @Override public void unlock() { String key = this.resourceId + this.lockValuePrefix; String lockValue = generateLockValue(); if (!StringUtils.isEmpty(lockValue)) { this.redisTemplate.delete(key); } } private String generateLockValue() { return UUID.randomUUID().toString(); } private String resourceId; private String lockValuePrefix = "lock:"; private int lockExpireTime = 30; // 默认锁定时间为30秒}```
原创文章,作者:酷盾叔,如若转载,请注明出处:https://www.kdun.com/ask/295044.html
本网站发布或转载的文章及图片均来自网络,其原创性以及文中表达的观点和判断不代表本网站。如有问题,请联系客服处理。
发表回复