众所周知,在做高并发,多进程业务时,会有很多条请求到方法中,为了保证数据的准确性,我们需要给业务代码中上排他锁,保证同一时间只有一个线程能够处理业务。在分布式的系统中,传统的synchronized已经满足不了我们的需求,需要分布式锁,分布式锁实现的方式有多种,其中一种方案就是数据库分布式锁。在mysql中 for update可以为数据库中的行上一个排它锁。当一个事务的操作未完成时候,其他事务可以读取但是不能写入或更新。
在这里我就简单实现一下该方案:
(1)定义一个lock工具类方法
@Component
public class DatabaseLock {
@Autowired
protected ApplicationContext applicationContext;
private static String lockSql = "select * from lock where name= ? for update";
public void lock(String serviceName, Runnable runnable) {
Connection connection = null;
Boolean autoComit = null;
PreparedStatement preparedStatement = null;
//获取数据库源
DataSource dataSource = applicationContext.getBean(DataSource.class);
try {
connection = dataSource.getConnection();
autoComit = connection.getAutoCommit();
connection.setAutoCommit(false);
preparedStatement = connection.prepareStatement(lockSql);
preparedStatement.setString(1, serviceName);
preparedStatement.execute();
//执行业务逻辑
runnable.run();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (connection != null) {
try {
connection.commit();
} catch (SQLException throwables) {
}
try {
connection.setAutoCommit(autoComit);
} catch (SQLException throwables) {
}
try {
connection.close();
} catch (SQLException throwables) {
}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException throwables) {
}
}
}
}
}
(2)定义数据库,数据库脚本
DROP TABLE IF EXISTS `lock`;
CREATE TABLE `lock` (
`name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
PRIMARY KEY (`name`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC;
(3)数据库分布式锁使用
@Slf4j
@Component
public class DatabaseLockTest {
@Autowired
private DatabaseLock lock;
public void test() {
lock.lock("test",() -> {
log.info("do something");
});
}
}
好了,今天的方案就分享到这里。下次有机会给大家分享其他实现分布式锁的方案。