一、基于数据库实现分布式锁
(1)利用数据库行级锁定功能实现悲观锁
在操作数据期间,通过select … for update语句锁定改行,其他事务无法修改。适用于高并发写操作、长事务处理。
inventory表结构:
CREATE TABLE inventory (
id INT PRIMARY KEY,
product_name VARCHAR(100),
quantity INT,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Mybatis实现Mapper示例:
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
@Mapper
public interface InventoryMapper {
@Select("SELECT quantity FROM inventory WHERE id = #{id} FOR UPDATE")
Integer selectForUpdate(int id);
@Update("UPDATE inventory SET quantity = quantity - 1 WHERE id = #{id}")
void decrementQuantity(int id);
}
Service层加锁、解锁示例:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class InventoryService {
@Autowired
private InventoryMapper inventoryMapper;
@Transactional
public void updateInventory(int productId) {
// 加锁
Integer quantity = inventoryMapper.selectForUpdate(productId);
if (quantity != null && quantity > 0) {
// 扣减库存
inventoryMapper.decrementQuantity(productId);
// 提交事务,解锁
} else {
throw new RuntimeException("库存不足");
}
}
}
使用了 @Transactional 注解来管理事务。Spring 会在方法开始时开启一个事务,执行的 SQL 语句(如SELECT … FOR UPDATE)将会在该事务中被加锁,直到事务提交或异常回滚被解锁。
(2)通过递增版本号字段实现乐观锁。
在数据表中增加一个版本号字段,每次更新时检查版本号是否一致。版本号不一致则表示有其他事务修改了该记录。适用于读多写少场景。
inventory表结构:
CREATE TABLE inventory (
id INT PRIMARY KEY,
product_name VARCHAR(100),
quantity INT,
version INT DEFAULT 0, -- 版本号字段
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Mybatis实现Mapper示例:
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
@Mapper
public interface InventoryMapper {
@Select("SELECT quantity, version FROM inventory WHERE id = #{id}")
Inventory selectInventory(int id);
@Update("UPDATE inventory SET quantity = quantity - 1, version = version + 1 WHERE id = #{id} AND version = #{version}")
int decrementQuantity(int id, int version);
}
Service层实现乐观锁:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class InventoryService {
@Autowired
private InventoryMapper inventoryMapper;
@Transactional
public void updateInventory(int productId) {
// 查询库存信息
Inventory inventory = inventoryMapper.selectInventory(productId);
if (inventory != null && inventory.getQuantity() > 0) {
// 扣减库存
int affectedRows = inventoryMapper.decrementQuantity(productId, inventory.getVersion());
if (affectedRows == 0) {
throw new RuntimeException("库存已被其他事务修改,请重试");
}
} else {
throw new RuntimeException("库存不足");
}
}
}