本博客日IP超过2000,PV 3000 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog2,之前的微信号好友位已满,备注:返现
受密码保护的文章请关注“业余草”公众号,回复关键字“0”获得密码
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
腾讯云】1核2G5M轻量应用服务器50元首年,高性价比,助您轻松上云
锁不管是在工作中还是生活中都到处存在。在编程的世界中,也是普遍的存在,用不好,会产生很多麻烦问题。
前两天有一个网友在群里问我 synchronized 锁的问题,当时没怎么细说,以后有时间了来写篇文章。本文主要是介绍借用数据库的悲观锁来实现一个分布式的锁。
分布式锁的实现有很多种方法,后面我还会写几篇用 Redis、Zookeeper 等来实现分布式锁。
目前几乎所有的大型网站和应用都采用的是分布式架构。在分布式环境中 CAP 理论至关重要,不懂 CAP 理论的可以查看我前面的文章《详解 CAP 定理 Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性)》。
分布式锁顾名思义是发生在分布式环境中的。对于单进程场景,我们可以使用语言和类库提供的锁,对于分布式锁,我也可以使用分布式锁。也就是说同样的锁使用的环境不同,分布式环境中用的锁就叫分布式锁!
根据上面的理解,分布式锁是不是应该具备下面的特点:
- 分布式锁必须保证在分布式部署的应用集群中,同一个方法在同一时间只能被一台机器上的一个线程执行;
- 一个线程获得了锁,其他线程必须等待持有锁的线程释放掉才能再获取;
- 锁必须要有超时机制(避免死锁)
基于上面的特点,我们就可以通过数据库的悲观锁来实现一个分布式锁。
代码非常的简单,使用 for update 即可。具体如下:
public class XttblogLock { private DataSource dataSource; private static final String cmd = "select * from xttblog_lock where id = 1 for update"; public XttblogLock(DataSource ds) { this.dataSource = ds; } public static interface CallBack{ public void doAction(); } public void lock(CallBack callBack) { Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { //try get lock System.out.println(Thread.currentThread().getName() + " begin try lock"); conn = dataSource.getConnection(); conn.setAutoCommit(false); stmt = conn.prepareStatement(cmd); rs = stmt.executeQuery(); //do business thing callBack.doAction(); //release lock conn.commit(); System.out.println(Thread.currentThread().getName() + " release lock"); } catch (SQLException e) { e.printStackTrace(); } finally { if (null != conn) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
使用数据库悲观锁实现分布式锁主要用了数据库的 for update 命令,执行改命令后,对应行记录会被锁住,其它线程会被阻塞主,直到获取到这行记录的线程提交了事务。这里需要注意要把自动提交设置为 false。
该锁的调用也非常的简单,具体代码如下:
final XttblogLock xttblogLock = new XttblogLock(dataSource); xttblogLock.lock(new CallBack() { @Override public void doAction() { System.out.println(Thread.currentThread().getName() + "beging do somthing"); try { System.out.println("业余草:www.xttblog.com 欢迎你!"); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "end do somthing"); } });
虽然数据库的 for update 悲观锁可以用来做分布式锁,但实际的生产过程中采用这种方法的非常少,因为它性能不是很高。
最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加作者微信号:xttblog2。备注:“1”,添加博主微信拉你进微信群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作也可添加作者微信进行联系!
本文原文出处:业余草: » 教你使用数据库的悲观锁 for update 创建分布式锁