-
mysql 表锁和行锁下
2020-03-11 18:24:38可重复读: A session执行: B sesion执行: ...where id = 1,balance没有变成400-50=350,lilei的balance值用的是步骤 (2)中的350来算的,所以是300,数据的一致性倒是没有被破坏。可重复...可重复读:
幻读;
死锁:
----------------------------
可重复读:
A session 执行:
B sesion 执行:
3)BSession执行后,查看A执行
(4)在客户端A,接着执行update account set balance = balance - 50
where id = 1,balance没有变成400-50=350,lilei的balance值用的是步骤
(2)中的350来算的,所以是300,数据的一致性倒是没有被破坏。可重复读的
隔离级别下使用了MVCC(multi-version concurrency control)机制,select操作
不会更新版本号,是快照读(历史版本);insert、update和delete会更新版本
号,是当前读(当前版本)。5)
串行化使用频率低不再赘述。
Mysql默认级别是repeatable-read,有办法解决幻读问题吗?要避免幻读可以用间隙锁在Session_1下面执行update account set name ='aaa' where id > 10 and id <=20;,则其他Session没法在这个范围所包含的间隙里插入或修改任何数据.无索引行锁会升级为表锁:锁主要是加在索引上,如果对非索引字 段更新, 行锁可能会变表锁 session1执行: update account set balance = 800 where name = 'lilei'; session2对该表任一行操作都会阻塞住 InnoDB的行锁是针对索引加的锁,不是针对记录加的锁。并且该索引不能失 效,否则都会从行锁升级为表锁。死锁:set tx_isolation='repeatable-read';Session_1执行:select * from account where id=1 for update;Session_2执行:select * from account where id=2 for update;Session_1执行:select * from account where id=2 for update;Session_2执行:select * from account where id=1 for update;查看近期死锁日志信息:show engine innodb status;2.2.6 优化建议尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁 合理设计索引,尽量缩小锁的范围 尽可能减少检索条件范围,避免间隙锁 尽量控制事务大小,减少锁定资源量和时间长度,涉及事务加锁的sql 尽量放在事务最后执行 尽可能低级别事务隔离 -
redisson实现redis分布式锁
2019-11-06 16:01:541、概述 12306、京东、淘宝等电商,高并发的场景比较多;举几个栗子:春运抢票,秒杀,双十一等场景,都存在对核心资源...如果考虑给数据库加锁,但对于超过1000次/s的高并发,数据库可能由行锁变成表锁,性能极...1、概述
12306、京东、淘宝等电商,高并发的场景比较多;举几个栗子:春运抢票,秒杀,双十一等场景,都存在对核心资源争抢,比如商品库存的争夺,如若控制不当,库存量有可能被减少成负值,与现实不符。
Web应用,都是集群或分布式部署,在单实例上假同步加锁,根本无法实现分布式锁;如果考虑给数据库加锁,但对于超过1000次/s的高并发,数据库可能由行锁变成表锁,性能极具下降,显然不可取。然而,使用Redis的分布式锁,是个较好的策略。Redis官方推荐使用的Redisson,提供了分布式锁和相关服务。
2、pom.xml,引入jar
<!-- https://mvnrepository.com/artifact/org.redisson/redisson --> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.11.5</version> </dependency>
3、代码实现案例
package com.redis; import org.redisson.Redisson; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.redisson.config.Config; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class TestRedissonLock { //最长等待时长 private static final Integer WAIT_TIME = 20; //自动解锁时长 private static final Integer TIME_OUT = 10; private static final String IP = "192.168.30.153"; private static final String PORT = "6379"; private static final RedissonClient redissonClient; static { Config config = new Config(); config.useSingleServer().setAddress(IP + ":" + PORT); redissonClient = Redisson.create(config); } public static void main(String[] args) { //获取锁,场景:集群或分布式模式下可以使用前缀+订单号作为锁的key String lockKey = "cloudLock"; RLock rLock = redissonClient.getLock(lockKey); //所有线程共用一把锁 new TestRedissonLock().testExecuteThreads(rLock); } public void testExecuteThreads(RLock cloudLock) { ExecutorService pool = Executors.newFixedThreadPool(10); for (int i = 1; i <= 10; i++) { pool.execute(new IThread("【Thread_" + i+"】", cloudLock)); } } class IThread implements Runnable { private String threadName; private RLock rLock; public IThread(String threadName, RLock rLock) { this.threadName = threadName; this.rLock = rLock; } @Override public void run() { boolean lockFlag = false; System.out.println(threadName + "开始执行"); try { lockFlag = rLock.tryLock(WAIT_TIME, TIME_OUT, TimeUnit.SECONDS); if (lockFlag) { System.out.println(this.threadName + "任务开始执行..."); //任务执行2秒钟 TimeUnit.SECONDS.sleep(2); System.out.println(this.threadName + "任务完美结束!"); } else { System.out.println(threadName + "等待超时,执行失败!!!"); } } catch (InterruptedException e) { e.printStackTrace(); } finally { if (lockFlag) { rLock.unlock(); } } } } }
-
springboot整合redisson实现分布式锁
2020-05-24 17:01:10库存数量可能被减少到负数,出现超卖的情况,或者 产生唯一的一个递增ID,由于web应用部署在多个机器上,简单的同步加锁是无法实现的,给数据库加锁的话,对于高并发,1000/s的并发,数据库可能由行锁变成表锁,性能...1、为什么要用分布式锁?
在一些高并发的场景中,比如秒杀,抢票,抢购这些场景,都存在对核心资源,商品库存的争夺,控制不好,库存数量可能被减少到负数,出现超卖的情况,或者 产生唯一的一个递增ID,由于web应用部署在多个机器上,简单的同步加锁是无法实现的,给数据库加锁的话,对于高并发,1000/s的并发,数据库可能由行锁变成表锁,性能下降会厉害。这个时候就需要用分布式锁了实现分布式锁的方式很多,我们今天就用redis的分布式锁,redisson也是官方比较推荐的。当然我们其实也可以自己用redis的setntx,delete方式自己写一个。
2、分布式锁的实现方式
大概有三种:
- 基于关系型数据库(基于mysql数据库的分布式锁)
- 基于缓存(本文讲解了基于redis的redisson实现分布式锁)
- 基于zookeeper(基于zookeeper实现分布式锁)
大部分网站使用的是基于缓存的,有更好的性能,而缓存一般是以集群方式部署,保证了高可用性。
3、原理
在Redisson中,使用key来作为是否上锁的标志,当通过getLock(String key)方法获得相应的锁之后,这个key即作为一个锁存储到Redis集群中,在接下来如果有其他的线程尝试获取名为key的锁时,便会向集群中进行查询,如果能够查到这个锁并发现相应的value的值不为0,则表示已经有其他线程申请了这个锁同时还没有释放,则当前线程进入阻塞,否则由当前线程获取这个锁并将value值加一,如果是可重入锁的话,则当前线程每获得一个自身线程的锁,就将value的值加一,而每释放一个锁则将value值减一,直到减至0,完全释放这个锁。因为底层是基于分布式的Redis集群,所以Redisson实现了分布式的锁机制。
4、实现
4.1、pom引入
<!--redisson--> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.5.0</version> </dependency>
4.2、redisson配置
spring redis: database: 1 host: 127.0.0.1 port: 6379 #password: 12345678 redisson: address: redis://127.0.0.1:6379 #password: web2017
4.2、redisson操作锁的工具
package com.example.mybatiesplus.utils; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.concurrent.TimeUnit; /** * @DESCRIPTION redisson操作锁的工具 * @Author lst * @Date 2020-05-22 15:00 */ @Component public class RedissonUtil { @Autowired private RedissonClient redissonClient; // RedissonClient已经由配置类生成,这里自动装配即可 /** * 锁住不设置超时时间(拿不到lock就不罢休,不然线程就一直block) * @author lst * @date 2020-5-24 16:23 * @param lockKey * @return org.redisson.api.RLock */ public RLock lock(String lockKey) { RLock lock = redissonClient.getLock(lockKey); lock.lock(); return lock; } /** * leaseTime为加锁时间,单位为秒 * @author lst * @date 2020-5-24 16:23 * @param lockKey * @param leaseTime * @return org.redisson.api.RLock */ public RLock lock(String lockKey, long leaseTime) { RLock lock = redissonClient.getLock(lockKey); lock.lock(leaseTime, TimeUnit.SECONDS); return null; } /** * timeout为加锁时间,时间单位由unit确定 * @author lst * @date 2020-5-24 16:24 * @param lockKey * @param unit * @param timeout * @return org.redisson.api.RLock */ public RLock lock(String lockKey, TimeUnit unit, long timeout) { RLock lock = redissonClient.getLock(lockKey); lock.lock(timeout, unit); return lock; } /** * 尝试获取锁 * @author lst * @date 2020-5-24 16:24 * @param lockKey * @param unit * @param waitTime * @param leaseTime * @return boolean */ public boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime) { RLock lock = redissonClient.getLock(lockKey); try { return lock.tryLock(waitTime, leaseTime, unit); } catch (InterruptedException e) { return false; } } /** * 通过lockKey解锁 * @author lst * @date 2020-5-24 16:24 * @param lockKey * @return void */ public void unlock(String lockKey) { RLock lock = redissonClient.getLock(lockKey); lock.unlock(); } /** * 直接通过锁解锁 * @author lst * @date 2020-5-24 16:25 * @param lock * @return void */ public void unlock(RLock lock) { lock.unlock(); } }
4.3、redisson基本配置类
@Configuration public class RedissonConfig { @Value("${redisson.address}") private String addressUrl; @Bean public RedissonClient getRedisson() throws Exception{ RedissonClient redisson = null; Config config = new Config(); config.useSingleServer() .setAddress(addressUrl); redisson = Redisson.create(config); System.out.println(redisson.getConfig().toJSON().toString()); return redisson; } }
4.3、接下来,写一个测试类
package com.example.mybatiesplus.controller; import com.example.mybatiesplus.result.BaseResponse; import com.example.mybatiesplus.result.ResultGenerator; import com.example.mybatiesplus.utils.RedissonUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.TimeUnit; /** * @DESCRIPTION 测试类 * @Author lst * @Date 2020-05-24 */ @RestController @RequestMapping("/test") @Api(value = "TestController", tags = "测试类") @Slf4j public class TestController { public final static String REDISSON_KEY = "redisson_key"; @Autowired private RedissonUtil redissonUtil; /** * 通过redisson高并发测试 * @author lst * @date 2020-5-24 16:29 * @param * @return com.example.mybatiesplus.result.BaseResponse */ @GetMapping(value = "/redisson", produces = "application/json; charset=utf-8") @ApiOperation(value = "通过redisson高并发测试", notes = "通过redisson高并发测试", code = 200, produces = "application/json") public BaseResponse redisson() { try{ log.info("============={} 线程访问开始============",Thread.currentThread().getName()); //TODO 尝试获取锁,等待3秒,自己获得锁后一直不解锁则5秒后自动解锁 boolean lock = redissonUtil.tryLock(REDISSON_KEY, TimeUnit.SECONDS, 3L, 5L); if (lock) { log.info("线程:{},获取到了锁",Thread.currentThread().getName()); //TODO 获得锁之后可以进行相应的处理 睡一会 Thread.sleep(100); log.info("======获得锁后进行相应的操作======" + Thread.currentThread().getName()); //redissonUtil.unlock(REDISSON_KEY); log.info("=============================" + Thread.currentThread().getName()); } }catch (Exception e){ log.info("错误信息:{}",e.toString()); log.info("线程:{} 获取锁失败",Thread.currentThread().getName()); } return ResultGenerator.genSuccessResult(); } }
4.4、使用jmeter测试
第一步:创建线程组
第二步:添加http请求,设置并发数(先测试100)
第二步:添加接口信息
4.5、测试数据
在redissonUtil.unlock(REDISSON_KEY);锁未释放的测试下,可能看到后台日志只有线程26获取到了锁。
将redissonUtil.unlock(REDISSON_KEY);释放开在测试,只要某个抢到锁的线程执行完毕并且释放了锁资源,其他的线程很快就会获取到锁。
-
高性能分布式锁-redisson的使用
2019-11-04 15:12:01高性能分布式锁-redisson的使用 本文摘自网文 1,概述:在一些高并发的...简单的同步加锁是无法实现的,给数据库加锁的话,对于高并发,1000/s的并发,数据库可能由行锁变成表锁,性能下降会厉害。那相对而言,re...高性能分布式锁-redisson的使用
本文摘自网文
1,概述:在一些高并发的场景中,比如秒杀,抢票,抢购这些场景,都存在对核心资源,商品库存的争夺,控制不好,库存数量可能被减少到负数,出现超卖的情况,或者 产生唯一的一个递增ID,由于web应用部署在多个机器上,简单的同步加锁是无法实现的,给数据库加锁的话,对于高并发,1000/s的并发,数据库可能由行锁变成表锁,性能下降会厉害。那相对而言,redis的分布式锁,相对而言,是个很好的选择,redis官方推荐使用的Redisson就提供了分布式锁和相关服务。
下面介绍下如何使用Redisson。2,Redisson的使用方式十分简单,详见官方文档:https://github.com/redisson/redisson/wiki/2.-%E9%85%8D%E7%BD%AE%E6%96%B9%E6%B3%95
3,加入jar包的依赖:
org.redisson redisson 2.7.04,配置Redisson
public class RedissonManager {
private static Config config = new Config();
//声明redisso对象
private static Redisson redisson = null;
//实例化redisson
static{
config.useSingleServer().setAddress(“127.0.0.1:6379”);
//得到redisson对象
redisson = (Redisson) Redisson.create(config);
}
//获取redisson对象的方法
public static Redisson getRedisson(){
return redisson;
}
}5,锁的获取和释放
public class DistributedRedisLock {
//从配置类中获取redisson对象
private static Redisson redisson = RedissonManager.getRedisson();
private static final String LOCK_TITLE = “redisLock_”;
//加锁
public static boolean acquire(String lockName){
//声明key对象
String key = LOCK_TITLE + lockName;
//获取锁对象
RLock mylock = redisson.getLock(key);
//加锁,并且设置锁过期时间,防止死锁的产生
mylock.lock(2, TimeUnit.MINUTES);
System.err.println(“lock”+Thread.currentThread().getName());
//加锁成功
return true;
}
//锁的释放
public static void release(String lockName){
//必须是和加锁时的同一个key
String key = LOCK_TITLE + lockName;
//获取所对象
RLock mylock = redisson.getLock(key);
//释放锁(解锁)
mylock.unlock();
System.err.println(“unlock”+Thread.currentThread().getName());
}
}6,业务逻辑中使用分布式锁
@RequestMapping("/redder")
@ResponseBody
public String redder() throws IOException{
String key = “test123”;
//加锁
DistributedRedisLock.acquire(key);
//执行具体业务逻辑
dosoming
//释放锁
DistributedRedisLock.release(key);
//返回结果
return soming;
} -
redission的使用--高性能分布式锁
2019-07-30 20:23:001,概述:在一些高并发的...简单的同步加锁是无法实现的,给数据库加锁的话,对于高并发,1000/s的并发,数据库可能由行锁变成表锁,性能下降会厉害。那相对而言,redis的分布式锁,相对而言,是个很好的选择,redis... -
高性能分布式锁-redisson(基于Redis)
2019-08-13 16:33:22库存数量可能被减少到负数,出现超卖的情况,或者 产生唯一的一个递增ID,由于web应用部署在多个机器上,简单的同步加锁是无法实现的,给数据库加锁的话,对于高并发,1000/s的并发,数据库可能由行锁变成表锁,性能... -
(转)高性能分布式锁-redisson的使用
2019-08-15 15:19:561,概述:在一些高并发的...简单的同步加锁是无法实现的,给数据库加锁的话,对于高并发,1000/s的并发,数据库可能由行锁变成表锁,性能下降会厉害。那相对而言,redis的分布式锁,相对而言,是个很好的选择,redis... -
springboot+redisson实现分布式锁
2019-05-18 23:43:37库存数量可能被减少到负数,出现超卖的情况,或者 产生唯一的一个递增ID,由于web应用部署在多个机器上,简单的同步加锁是无法实现的,给数据库加锁的话,对于高并发,1000/s的并发,数据库可能由行锁变成表锁,性能... -
高并发环境下,Redisson实现redis分布式锁
2017-06-10 13:12:29库存数量可能被减少到负数,出现超卖的情况,或者 产生唯一的一个递增ID,由于web应用部署在多个机器上,简单的同步加锁是无法实现的,给数据库加锁的话,对于高并发,1000/s的并发,数据库可能由行锁变成表锁,性能... -
Redisson分布式锁使用说明
2020-08-12 09:45:49库存数量可能被减少到负数,出现超卖的情况,或者 产生唯一的一个递增ID,由于web应用部署在多个机器上,简单的同步加锁是无法实现的,给数据库加锁的话,对于高并发,1000/s的并发,数据库可能由行锁变成表锁,性能... -
mysql InnoDB 的行锁
2019-10-01 00:24:56表的引擎类型必须为InnoDB才可以进行此操作。 ... 共享锁:单独运行前两句,然后新建一个会话使用第三句、会发现无法使用。然后使用第四句即可解除锁...否则会变成无法实现行锁,而会变成表锁 (PS:表锁的相关链接... -
mysql创建表出现锁_一不小心MYSQL成了表锁
2021-01-21 09:31:15大家都知道MYSQL数据库INNODB引擎是默认的行锁,但是今天意外发现我的数据库怎么变成表锁了,让我很费解~~~~1、首先看看我的数据库引擎show variables like '%storage_engine%';2、创建test表CREATE TABLE `test` (`... -
闲谈mysql三种行锁(记录锁、间隙锁与临键锁)
2020-06-11 14:22:54行锁在 InnoDB 中是基于索引实现的,但是如果某个加锁操作没有使用索引,那么该锁就会退化为表锁。 行锁的分类 记录锁(Record Locks) 记录锁就是为某行记录加锁,它封锁该行的索引记录: SELECT*... -
全局锁和表锁什么场景会用到
2020-05-28 14:39:25数据库往往是多个用户在连接使用的,那么**如何保证数据...当执行上面这个命令后,所有的表都变成只读状态,数据更新或者字段更新都将会被阻塞,可以使用下面命令解锁: unlock tables; 全局锁一般会在什么时候用到呢 -
springboot记录 ~~~~~
2019-11-25 13:34:08for update 查询字段需要时索引列 才是行锁,否则变成表锁(悲观锁) -
详解 MySql InnoDB 中的三种行锁(记录锁、间隙锁与临键锁)
2020-12-10 15:40:51行锁在 InnoDB 中是基于索引实现的,所以一旦某个加锁操作没有使用索引,那么该锁就会退化为表锁。 记录锁(Record Locks) 顾名思义,记录锁就是为某行记录加锁,它封锁该行的索引记录: -- id 列为主键列或... -
mysql与oracle的区别
2018-03-07 17:33:39一、并发性(行锁的区别)mysql的InnoDB存储引擎虽然支持行锁,但是当表无索引或者sql语句索引失效时,行锁会变成表锁。oracle行锁,不依赖于表的索引二、事务mysql的MyISAM存储引擎不支持事务,在InnoDB存储引擎下... -
了解mysql的锁
2020-11-29 19:17:12mysql的锁行锁表锁间隙锁分析innoDB引擎锁的一些情况 行锁 首先将mysql自动提交改为手动提交 1.打开一个窗口,修改第一行,将name字段改成张三 查看当前数据已经变成张三 打开第二个窗口,查看第一条数据,name并... -
mysql数据一致性和副本复制-part3
2015-07-30 17:34:061.5 加锁机制 MVCC实质上是通过避免读写...InnoDB主要使用行级锁(row lock),其行锁是通过在索引项上加锁而实现的,如果mysql的执行计划没能用到索引,那么行锁就不会生效,这时加锁的粒度就会跃变成表锁,会严重 -
mysql 锁的理解
2019-02-21 19:33:31如果没有走索引,则可能锁住所有记录,变成了表锁了。 注意:行锁仅在事务中才有效,不在事务行锁无效,即使锁住了记录,其它程序也可以操作记录并能正常提交,结果如下所示。 但myisam的表锁,请大家自行研究,...
-
MySQL 数据库的基本操作(数据完整性约束)
-
网络安全等级保护等级测评实施培训-公安部.pdf
-
MySQL 高可用工具 DRBD 实战部署详解
-
神通科技首次公开发行股票招股说明书.pdf
-
【毕设】jsp+基于JB的人事管理系统(源代码+论文)
-
2021年 系统分析师 系列课
-
《文件和目录操作命令》
<2.> -
2014年重庆理工大学《物联网平台设计与开发》期末考试试卷).pdf
-
【写作技巧】毕业论文如何写目录?
-
12.2 布尔函数的表示
-
Python基于Flask人力资源管理系统设计
-
Windows10蓝牙驱动合集
-
PD协议 协议层
-
Day2-运算符和变量作业
-
树莓派自启动
-
MySQL 函数、用户自定义函数
-
实现 MySQL 读写分离的利器 mysql-proxy
-
基于Flink+Hudi构建企业亿级云上实时数据湖教程(PC、移动、小
-
云开发后台+微信扫码点餐小程序+cms网页管理后台 含后厨端和用户端
-
linux系统下文件夹没有权限