mysql锁怎么实现的 macbook窗口快捷键( 二 )


3、临键锁Next-key-lock,行锁和间隙锁组合,同时锁住数据,并锁住数据前面的间隙Gap,在RR隔离级别下支持 。
innodb实现了以下两种类型的行锁
1、共享锁 S: 允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁 。
2、排他锁 X: 允许获取排他锁的事务更新数据 , 阻止其他事务获得相同数据集的共享锁和排他锁 。
insert 语句 排他锁 自动添加的
update语句 排他锁 自动添加
delete 语句 排他锁 自动添加
select 正常查询语句 不加锁。。。
select。。。lock in share mode 共享锁 需要手动在select 之后加lock in share mode
select。。。for update 排他锁 需要手动在select之后添加for update
默认情况下 , innodb在repeatable read事务隔离级别运行 , innodb使用next-key锁进行搜索和索引扫描 , 以防止幻读 。
间隙锁唯一目的是防止其它事务插入间隙,间隙锁可以共存 , 一个事务采用的间隙锁不会阻止另一个事务在同一间隙上采用的间隙锁 。
用 MySQL 实现分布式锁 , 你听过吗?以前参加过一个库存系统 , 由于其业务复杂性,搞了很多个应用来支撑 。这样的话一份库存数据就有可能同时有多个应用来修改库存数据 。
比如说,有定时任务域xx.cron , 和SystemA域和SystemB域这几个JAVA应用,可能同时修改同一份库存数据 。如果不做协调的话,就会有脏数据出现 。
对于跨JAVA进程的线程协调,可以借助外部环境 , 例如DB或者Redis 。下文介绍一下如何使用DB来实现分布式锁 。
本文设计的分布式锁的交互方式如下:
在使用synchronized关键字的时候,必须指定一个锁对象 。
进程内的线程可以基于obj来实现同步 。obj在这里可以理解为一个锁对象 。如果线程要进入synchronized代码块里,必须先持有obj对象上的锁 。这种锁是JAVA里面的内置锁,创建的过程是线程安全的 。那么借助DB,如何保证创建锁的过程是线程安全的呢?
可以利用DB中的UNIQUE KEY特性,一旦出现了重复的key,由于UNIQUE KEY的唯一性,会抛出异常的 。在JAVA里面,是SQLIntegrityConstraintViolationException 异常 。
transaction_id是事务Id,比如说,可以用
来组装一个transaction_id,表示某仓库某销售模式下的某个条码资源 。不同条码,当然就有不同的transaction_id 。如果有两个应用 , 拿着相同的transaction_id来创建锁资源的时候,只能有一个应用创建成功 。
在写操作频繁的业务系统中,通常会进行分库,以降低单数据库写入的压力 , 并提高写操作的吞吐量 。如果使用了分库,那么业务数据自然也都分配到各个数据库上了 。
在这种水平切分的多数据库上使用DB分布式锁,可以自定义一个DataSouce列表 。并暴露一个getConnection(String transactionId) 方法,按照transactionId找到对应的Connection 。
实现代码如下:
首先编写一个initDataSourceList方法,并利用Spring的PostConstruct注解初始化一个DataSource 列表 。相关的DB配置从db.properties读取 。
DataSource使用阿里的DruidDataSource 。
接着最重要的一个实现getConnection(String transactionId)方法 。实现原理很简单,获取transactionId的hashcode,并对DataSource的长度取模即可 。
连接池列表设计好后,就可以实现往distributed_lock表插入数据了 。
接下来利用DB的select for update 特性来锁住线程 。当多个线程根据相同的transactionId并发同时操作 select for update 的时候,只有一个线程能成功,其他线程都block住 , 直到 select for update 成功的线程使用commit操作后,block住的所有线程的其中一个线程才能开始干活 。

推荐阅读