1 .分布式事务
2. 分布式锁
Java原生API虽然有并发锁,但并没有提供分布式锁的能力,所以针对分布式场景中的锁需要解决的方案。
分布式锁的解决方案大致有以下几种:
-
<李>
基于数据库实现
李>
<李>
基于缓存(复述,memcached等)实现
李>
<李>
基于管理员实现
李>
2.1。基于数据库实现分布式锁
实现
1. 创建表
<前> CREATE TABLE “methodLock”, ( “id”才能,int (11), NOT NULL AUTO_INCREMENT COMMENT & # 39;主键& # 39;, “method_name”,才能varchar (64), NOT NULL DEFAULT & # 39; & # 39;, COMMENT & # 39;锁定的方法名& # 39;, “desc”,才能varchar (1024), NOT NULL DEFAULT & # 39;备注信息& # 39;, “update_time”,才能timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP 提醒UPDATE CURRENT_TIMESTAMP COMMENT & # 39;保存数据时间,自动生成& # 39;, PRIMARY 才能;KEY (id), UNIQUE 才能;KEY “uidx_method_name”, (“method_name ”), USING BTREE ),引擎=InnoDB DEFAULT CHARSET=utf8 评论=& # 39;锁定中的方法& # 39;; >之前2. 获取锁
想要锁住某个方法时,执行以下SQL:
<前> insert into  methodLock (method_name desc), values (‘method_name’,‘desc) >之前因为我们对, <代码> method_name 代码> ,做了唯一性约束,这里如果有多个请求同时提交到数据库的话,数据库会保证只有一个操作可以成功,那么我们就可以认为操作成功的那个线程获得了该方法的锁,可以执行方法体内容。
成功插入则获取锁。
3.释放锁
当方法执行完毕之后,想要释放锁的话,需要执行以下Sql:
<前> delete 得到methodLock where method_name =& # 39; method_name # 39; >之前
问题
-
<李>
这把锁强依赖数据库的可用性。如果数据库是一个单点,一旦数据库挂掉,会导致业务系统不可用。
李>
<李>
这把锁没有失效时间,一旦解锁操作失败,就会导致锁记录一直在数据库中,其他线程无法再获得到锁。
李>
<李>
这把锁只能是非阻塞的,因为数据的插入操作,一旦插入失败就会直接报错。没有获得锁的线程并不会进入排队队列,要想再次获得锁就要再次触发获得锁操作。
李>
<李>
这把锁是非重入的,同一个线程在没有释放锁之前无法再次获得该锁。因为数据中数据已经存在了。
李>
解决办法
-
<李>
单点问题可以用多数据库实例,同时塞N个表,N/2 + 1个成功就任务锁定成功
李>
<李>
写一个定时任务,隔一段时间清除一次过期的数据。
李>
<李>
写一个而循环,不断的重试插入,直到成功。
李>
<李>
在数据库表中加个字段,记录当前获得锁的机器的主机信息和线程信息,那么下次再获取锁的时候先查询数据库,如果当前机器的主机信息和线程信息在数据库可以查到的话,直接把锁分配给他就可以了。
李>
小结
-
<李>
优点:直接借助数据库,容易理解。
李>
<李>
缺点:会有各种各样的问题,在解决问题的过程中会使整个方案变得越来越复杂。操作数据库需要一定的开销,性能问题需要考虑。
李>
2.2。基于复述,实现分布式锁
相比于用数据库来实现分布式锁,基于缓存实现的分布式锁的性能会更好一些。目前有很多成熟的分布式产品,包括复述,memcache, Tair等。这里以复述,举例。