精华内容
下载资源
问答
  • 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 尽量放在事务最后执行 尽可能低级别事务隔离
     
     
     
     
     
     
     
     
     
     
    展开全文
  • 1、概述 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、分布式锁的实现方式

    大概有三种:

    1. 基于关系型数据库(基于mysql数据库的分布式锁
    2. 基于缓存(本文讲解了基于redis的redisson实现分布式锁)
    3. 基于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的使用 本文摘自网文 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.0

    4,配置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:00
    1,概述:在一些高并发的...简单的同步加锁是无法实现的,给数据库加锁的话,对于高并发,1000/s的并发,数据库可能由行锁变成表锁,性能下降会厉害。那相对而言,redis的分布式锁,相对而言,是个很好的选择,redis...
  • 库存数量可能被减少到负数,出现超卖的情况,或者 产生唯一的一个递增ID,由于web应用部署在多个机器上,简单的同步加锁是无法实现的,给数据库加锁的话,对于高并发,1000/s的并发,数据库可能由行锁变成表锁,性能...
  • 1,概述:在一些高并发的...简单的同步加锁是无法实现的,给数据库加锁的话,对于高并发,1000/s的并发,数据库可能由行锁变成表锁,性能下降会厉害。那相对而言,redis的分布式锁,相对而言,是个很好的选择,redis...
  • 库存数量可能被减少到负数,出现超卖的情况,或者 产生唯一的一个递增ID,由于web应用部署在多个机器上,简单的同步加锁是无法实现的,给数据库加锁的话,对于高并发,1000/s的并发,数据库可能由行锁变成表锁,性能...
  • 库存数量可能被减少到负数,出现超卖的情况,或者 产生唯一的一个递增ID,由于web应用部署在多个机器上,简单的同步加锁是无法实现的,给数据库加锁的话,对于高并发,1000/s的并发,数据库可能由行锁变成表锁,性能...
  • 库存数量可能被减少到负数,出现超卖的情况,或者 产生唯一的一个递增ID,由于web应用部署在多个机器上,简单的同步加锁是无法实现的,给数据库加锁的话,对于高并发,1000/s的并发,数据库可能由行锁变成表锁,性能...
  • mysql InnoDB 的行锁

    2019-10-01 00:24:56
    表的引擎类型必须为InnoDB才可以进行此操作。 ... 共享锁:单独运行前两句,然后新建一个会话使用第三句、会发现无法使用。然后使用第四句即可解除锁...否则会变成无法实现行锁,而会变成表锁 (PS:表锁的相关链接...
  • 大家都知道MYSQL数据库INNODB引擎是默认的行锁,但是今天意外发现我的数据库怎么变成表锁了,让我很费解~~~~1、首先看看我的数据库引擎show variables like '%storage_engine%';2、创建test表CREATE TABLE `test` (`...
  • 行锁在 InnoDB 中是基于索引实现的,但是如果某个加锁操作没有使用索引,那么该锁就会退化为表锁行锁的分类 记录锁(Record Locks) 记录锁就是为某行记录加锁,它封锁该行的索引记录: SELECT*...
  • 数据库往往是多个用户在连接使用的,那么**如何保证数据...当执行上面这个命令后,所有的表都变成只读状态,数据更新或者字段更新都将会被阻塞,可以使用下面命令解锁: unlock tables; 全局锁一般会在什么时候用到呢
  • springboot记录 ~~~~~

    2019-11-25 13:34:08
    for update 查询字段需要时索引列 才是行锁,否则变成表锁(悲观锁)
  • 行锁在 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:12
    mysql的锁行锁表锁间隙锁分析innoDB引擎锁的一些情况 行锁 首先将mysql自动提交改为手动提交 1.打开一个窗口,修改第一行,将name字段改成张三 查看当前数据已经变成张三 打开第二个窗口,查看第一条数据,name并...
  • 1.5 加锁机制  MVCC实质上是通过避免读写...InnoDB主要使用行级锁(row lock),其行锁是通过在索引项上加锁而实现的,如果mysql的执行计划没能用到索引,那么行锁就不会生效,这时加锁的粒度就会跃变成表锁,会严重
  • mysql 锁的理解

    2019-02-21 19:33:31
    如果没有走索引,则可能锁住所有记录,变成表锁了。 注意:行锁仅在事务中才有效,不在事务行锁无效,即使锁住了记录,其它程序也可以操作记录并能正常提交,结果如下所示。 但myisam的表锁,请大家自行研究,...

空空如也

空空如也

1 2
收藏数 35
精华内容 14
关键字:

行锁变成表锁