insert
)实现记录锁的乐观锁方案。基于数据库的实现方式的核心思想是:在数据库中创建一个表,表中包含方法名等字段,并在方法名字段上创建唯一索引,想要执行某个方法,就使用这个方法名向表中插入数据,成功插入则获取锁,执行完成后删除对应的行数据释放锁。
优点
缺点
DROP TABLE IF EXISTS `method_lock`; CREATE TABLE `method_lock` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', `lock_key` varchar(64) NOT NULL DEFAULT '' COMMENT '锁的键值', `lock_timeout` datetime NOT NULL DEFAULT NOW() COMMENT '锁的超时时间', `remarks` varchar(255) NOT NULL COMMENT '备注信息', `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uidx_lock_key` (`lock_key`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='锁定中的方法';
① 获取锁:想要执行某个方法,就使用这个方法名向表中插入数据
INSERT INTO method_lock (lock_key, lock_timeout, remarks) VALUES ('methodName', '2021-07-19 18:20:00', '测试的methodName');
② 释放锁:释放锁的时候就删除记录
DELETE FROM method_lock WHERE lock_key ='methodName';
版本号对比更新的乐观锁方案。一般是通过为数据库表添加一个 version
字段来实现读取出数据时,将此版本号一同读出。之后更新时,对此版本号加 1
,在更新过程中,会对版本号进行比较,如果是一致的,没有发生改变,则会成功执行本次操作;如果版本号不一致,则会更新失败。实际就是个CAS
过程。
缺点
for update
)实现基于排它锁的悲观锁方案。通过在select语句后增加for update
来获取锁,数据库会在查询过程中给数据库表增加排他锁。当某条记录被加上排他锁之后,其他线程无法再在该行记录上增加排他锁,我们可以认为获得排它锁的线程即可获得分布式锁。释放锁通过connection.commit();
操作,提交事务来实现。
优点
缺点
建表脚本
CREATE TABLE `methodLock` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', `lock_key` varchar(64) NOT NULL DEFAULT '' COMMENT '锁的键值', `lock_timeout` datetime NOT NULL DEFAULT NOW() COMMENT '锁的超时时间', `remarks` varchar(255) NOT NULL COMMENT '备注信息', `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY ( `id` ), UNIQUE KEY `uidx_lock_key` ( `lock_key ` ) USING BTREE ) ENGINE = INNODB DEFAULT CHARSET = utf8 COMMENT = '锁定中的方法';
加解锁操作
/** * 加锁 */ public boolean lock() { // 开启事务 connection.setAutoCommit(false); // 循环阻塞,等待获取锁 while (true) { // 执行获取锁的sql String sql = "select * from methodLock where lock_key = xxx for update"; // 创建prepareStatement对象,用于执行SQL ps = conn.prepareStatement(sql); // 获取查询结果集 int result = ps.executeQuery(); // 结果非空,加锁成功 if (result != null) { return true; } } // 加锁失败 return false; } /** * 解锁 */ public void unlock() { // 提交事务,解锁 connection.commit(); }
更多JAVA、高并发、微服务、架构、解决方案、中间件的总结在:https://github.com/yu120/lemon-guide