精华内容
下载资源
问答
  • 什么是锁升级

    2016-02-18 12:03:00
    它的作用又是什么呢?在什么情况下会出现锁升级呢? 锁升级,就是将众多细粒度锁转换为较少的粗粒度的锁以削减系统开销的进程。假如行锁是有开销的,那对1行加锁可能没问题,但对1万行加锁。那对系统开销就非常大...
        经常听到DBA在谈论各种数据库时。都会提到一个词语:锁升级。
        那么。什么是锁升级呢?它的作用又是什么呢?在什么情况下会出现锁升级呢?
        锁升级,就是将众多细粒度锁转换为较少的粗粒度的锁以削减系统开销的进程。假如行锁是有开销的,那对1行加锁可能没问题,但对1万行加锁。那对系统开销就非常大了,此时。数据库就会将其升级为表锁,以降低开销。

     
        在网上摘抄的一个样例,当事务从表中请求行时,SQL Server 自己主动获取受影响的行上的锁,并在包括这些行的页和表或者索引上放置更高级别的意向锁

    事务控制的锁数量超过了它的极限时。SQL Server 会试图将表上的意向锁更改为更强的锁(比如,将意向排它 (IX) 锁更改为排它 (X) 锁)。获取更强的锁后,表事务持有的全部页级锁和行级锁都被释放,从而削减锁的开销。

    转载于:https://www.cnblogs.com/bhlsheji/p/5197768.html

    展开全文
  • 锁升级

    2017-11-14 15:10:00
    锁升级是SQL Server使用的优化技术,用来控制在SQL Server锁管理里把持锁的数量。我们首先用SQL Server里所谓的锁层级(Lock Hierarchy)开始,因为那是在像SQL Server的关系数据库里,为什么有锁升级概念存在的原因...

    在今天的文章里,我想谈下SQL Server里锁升级(Lock Escalations)。锁升级是SQL Server使用的优化技术,用来控制在SQL Server锁管理里把持锁的数量。我们首先用SQL Server里所谓的锁层级(Lock Hierarchy )开始,因为那是在像SQL Server的关系数据库里,为什么有锁升级概念存在的原因。

    锁层级(Lock Hierarchy )

     下图展示了SQL Server使用的锁层级:

     

    从图里可以看到,锁层级开始于数据库层级,向下至行层级。在数据库本身层级,你一直有一个共享锁(Shared Lock (S) )。当你的查询连接到一个数据库(例如USE MyDatabase),共享锁会阻止数据库删除,或者在那个数据库上还原备份。当你进行一个操作时,在数据库层级下,在表上,在页上,在记录上都会有锁。

    当你执行一个SELECT语句,在表和页上会有一个意向共享锁(Intent Shared Lock (IS) ),在记录本身上有共享锁(Shared Lock (S) )。当你进行数据修改语句(INSERT,UPDATE,DELETE),在表和页上会有一个意向排它或更新锁( Intent Exclusive or Update Lock (IX or IU) ),在改变的记录上有排它或更新锁(Exclusive or Update Lock (X or U) )。当多个线程尝试在锁层级里并发获取锁时,SQL Server会一直获取从头到脚的锁来阻止所谓的竞争危害。当你对表进行20000条记录的删除操作时,现在想象下这个锁层级会是什么样的?我们来假定记录是400 bytes长,这就意味这在8kb的页里刚好有20条记录:

     

    在数据库上你有1个共享锁(S),在表上有1个意向排它锁(IX),在页上有1000个意向排它锁(IX)(20000条记录散布在1000个页上),最后在记录本身你有20000个排它锁(X)。对于DELETE操作总计你获取了21002个锁。在SQL Server里每个锁需要96 bytes的内存,因此对这个简单的查询需要1.9MB的锁。当你并行执行多个查询时,这个不会无限扩展。因此,SQL Server现在用所谓的锁升级(Lock Escalation)实现。

    锁升级(Lock Escalations)

    在你的锁层级里一旦有超过5000个锁,SQL Server会升级这么多的精细粒度(fine-granularity)的锁为简单的粗粒度(coarse-granularity)的锁。默认情况下,SQL Server“总是”升级到表层级。这意味着你的锁层级从刚才例子的样子,在锁升级成功执行后,变成如下的样子:

     

     

    如你所见,在表本身上你只有一个大锁。在DELETE操作的情况下,在表层级你有一个排它锁(X)。这会以负面伤及你数据库的并发。在表层级把持一个排它锁(X)意味者没有其他回话可以访问那个表——每个其它查询会阻塞。当你在可重读隔离级别(Repeatable Read Isolation Level)运行你的SELECT语句,你也在把持你的共享锁(S)直到事务结束,这也就是说只要你读超过5000条记录就会发生锁升级。这里的结果是一个共享锁(S)在表本身!你的表只是暂时只读,因为在表上每个其它数据修改都会阻塞!

    这里还有个误解——SQL Server会锁升级从行层级到页层级,最后到表层级。错了!在SQL Server里没有这样的代码路径存在!默认情况下,SQL Server总是会直接升级到表层级。到页层级的升级策略不存在。如果你的表被分区了(只针对企业版本的SQL Server),那样的话,你可以配置升级到分区层级。但这里你必须非常仔细测试你的数据访问模式,因为锁升级到分区层级会引起死锁。因此这个选项默认是没启用的。

    自SQL Server 2008开始,你可以控制SQL Server如何进行锁升级——通过ALTER TABLE语句和LOCK_ESCALTATION属性。有3个可用选项:

    • TABLE
    • AUTO
    • DISABLE
    复制代码
    1 -- Controllling Lock Escalation
    2 ALTER TABLE Person.Person
    3 SET
    4 (
    5     LOCK_ESCALATION = AUTO -- or TABLE or DISABLE
    6 )
    7 GO
    复制代码

    默认选项是TABLE,意味着SQL Server总是执行锁升级到表层级——即使这个表已被分区。如果你的表已被分区,你想设置分区层级的锁升级(因为你已经测试了你的数据访问模式,用它你不会引起死锁),那么你可以修改选项为AUTOAUTO意味着你的锁升级会执行到分区层级,如果表被分区的话,否则就到表层级。使用DISABLE选项你可以完全禁用那个表的锁升级。但是禁用锁升级并不是最好的选项,因为SQL Server的锁管理器会消耗大量的内存,如果你对你的查询和索引设计不深思熟虑的话。

    小结

    在SQL Server里锁升级基本是个噩梦。你如何才能从表里删除5000行记录而不产生锁升级?你可以临时禁用锁升级,但这里你要非常仔细。另外一个方法(我推荐的)是让你的DELETE/UPDATE语句在一个循环里,作为不同,独立的事务:DELETE/UPDATE少于5000行记录,这样的话你可以阻止锁升级。这样做的好处,你庞大的事务会分解为多个小事务,但也会让你的事务日志更多,带来自动增长问题。



    本文转自Woodytu博客园博客,原文链接:http://www.cnblogs.com/woodytu/p/4641124.html,如需转载请自行联系原作者

    展开全文
  • 1.1、为什么用分布式 在单机系统中,当多线程访问数据时,为了保证数据的正确性,我们一般都会采用加锁的方式,比较常见的synchronized或者ReentrantLock。他们都由Java为我们提供的实现,能够让多个线程之间...

    分布式锁

    1、分布式锁介绍

    1.1、为什么用分布式锁

    在单机系统中,当多线程访问数据时,为了保证数据的正确性,我们一般都会采用加锁的方式,比较常见的synchronized或者ReentrantLock。他们都是由Java为我们提供的锁实现,能够让多个线程之间只能串行化执行,从而保证数据的正确性。

    ​ 但是一旦将服务器从单机部署升级为多机部署后,则会发现Java提供的原生锁机制在多机部署下失效了。这是因为Java本身提供的锁,他们只对属于自己JVM里面的线程有效,对于其他JVM的线程是无效的。

    1.2 场景示例

    ​ 现在有一个电商系统,此时只通过一台机器进行部署,当用户下单时,首先会检查库存是否足够,只有当库存足够时,才会允许进行下单。

    ​ 为了提高系统的并发性能,因此会首先将商品库存信息预热到redis中,当用户下单时,会更新redis中的库存信息。

    在这里插入图片描述
    此时在单线程下执行是没有任何问题的,但是假设现在某一商品库存数量为1,且同时有两个线程同时对该商品执行下单操作,线程A和线程B查询库存结果都为1,此时线程A先执行第三步更新mysql将库存数量由1变为0。但是当线程B再来执行第三步更新mysql时,库存数量会变为-1,此时库存超卖出现。
    在这里插入图片描述
    此时要想解决超卖问题,则可以进行加锁,将2,3,4步利用synchronized或者ReentrantLock进行加锁,从而让线程排队,避免超卖问题的出现。

    在这里插入图片描述
    但是当随着并发量的增大,此时单机部署已经无法承受这么大的并发量了,则会将系统由单机变为多机部署。
    在这里插入图片描述
    此时假设同时有两个用户进行下单,请求分别进入两台机器中,那么这两个请求是可以同时执行的,则仍然会出现超卖问题。

    ​ 因为不管synchronized或者ReentrantLock都是只作用于自己机器的JVM中,对其他机器的JVM无效。相当于两台不同的机器使用的是不同的两把锁,导致锁失效。

    ​ 解决该问题的思路则需要保证不同的机器使用的是相同的一把锁,则此时需要使用分布式锁。对于分布式锁的实现,可以基于Mysql、redis、zookeeper、consule等进行实现。

    1.3 分布式锁具备的条件

    • 互斥性:同一时刻只能有一个服务(或应用)访问资源。
    • 原子性:一致性要求保证加锁和解锁的行为是原子性的。
    • 安全性:锁只能被持有该锁的服务(或应用)释放。
    • 容错性:在持有锁的服务崩溃时,锁仍能得到释放,避免死锁。
    • 高可用:获取锁和释放锁 要高可用。
    • 高性能:获取锁和释放锁的性能要好。
    • 持久性:锁按业务需要自动续约/自动延期。

    2、分布式锁的解决方案

    2.1 数据库实现分布式锁

    1、pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>org.example</groupId>
        <artifactId>mysqlLockDemo</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <!-- Spring boot 版本信息 -->
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.1.6.RELEASE</version>
            <relativePath/>
        </parent>
    
        <properties>
            <!-- Environment Settings -->
            <java.version>1.8</java.version>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <skipTests>true</skipTests>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.10</version>
                <scope>provided</scope>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <!-- mybatis-plus begin-->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>3.3.1</version>
            </dependency>
    
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
            <!-- mybatis-plus end-->
    
            <!--web起步依赖-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
        </dependencies>
    </project>
    

    application.yaml

    server:
      port: 9001
    spring:
      datasource:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/mysqlLock?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
        username: root
        password: root
      application:
        name: book
    

    启动类

    @SpringBootApplication
    @MapperScan(basePackages = {"com.itheima.dao"})//扫描mapper接口所在的包
    public class MyApplication {
        public static void main(String[] args) {
            SpringApplication.run(MyApplication.class,args);
        }
    }
    

    实体类pojo

    @Data
    @TableName(value = "tb_book")
    public class Book {
    
        // 图书ID
        @TableId
        private Integer id;
        // 图书名称
        private String name;
    
        //数量
        private Integer stock;
    }
    

    BookMapper

    public interface BookMapper extends BaseMapper<Book> {
    
        @Update("update tb_book set stock=stock-#{saleNum} where id = #{id}")
        void updateNoLock(@Param("id") int id, @Param("saleNum") int saleNum);
    }
    

    BookService

    public interface BookService {
    
        /**
         *
         * @param id
         * @param saleNum 销售数量
         */
        void updateStock(int id, int saleNum);
    }
    

    BookServiceImpl

    @Service
    public class BookServiceImpl implements BookService {
    
        @Autowired
        private BookMapper bookMapper;
    
        @Override
        @Transactional
        public void updateStock(int id, int saleNum) {
    
            Book book = bookMapper.selectById(id);
            if (book.getStock()>0){
                bookMapper.updateNoLock(1,1);
            }else {
                System.out.println("没有库存了");
            }
        }
    
    }
    

    BookController

    @RestController
    @RequestMapping("/book")
    public class BookController {
    
        @Autowired
        private BookService bookService;
    
        @GetMapping("/updateNoLock/{id}/{saleNum}")
        public void updateNoLock(@PathVariable("id") Integer id,@PathVariable("saleNum") int saleNum){
            bookService.updateStock(id,saleNum);
        }
    }
    

    在这里插入图片描述

    经过jemeter测试可以发现,库存出现了负数。相当于出现了商品超卖。

    2.1.1 基于条件

    对于分布式锁的实现,比较常见的一种就是基于MySQL乐观锁方式来完成,这种方式的思想就是利用MySQL的InnoDB引擎的行锁机制来完成。

    ​ 对于乐观锁的实现,又分为两种,分别为根据条件根据版本号

    实现代码
    BookMapper

    public interface BookMapper extends BaseMapper<Book> {
    
        @Update("update tb_book set stock=stock-#{saleNum} where id = #{id} and stock-#{saleNum}>=0")
        void updateNoLock(@Param("id") int id, @Param("saleNum") int saleNum);
    }
    

    controller

        @GetMapping("/updateByCondition/{id}/{saleNum}")
        public void updateByCondition(@PathVariable("id") Integer id, @PathVariable("saleNum") int saleNum){
            bookService.updateByCondition(id,saleNum);
        }
    

    在这里插入图片描述
    通过Jemeter进行并发测试,可以发现其已经可以保证库存不会被扣减超卖。

    2.1.2 基于version版本号

    有时我们并没有一些特定的条件让我们去进行判断。此时就会在数据表中新增一个字段版本字段version来进行数据并发控制。
    在这里插入图片描述
    BookMapper

    @Update("update tb_book set name=#{name},version=version+1 where id=#{id} and version=#{version}")
     int updateByVersion(@Param("id")int id,@Param("name")String name,@Param("version")int version);
    

    BookService

     void updateByVersion(int id,String name,int version);
    

    BookServiceImpl

    @Override
    @Transactional
    public void updateByVersion(int id, String name,int version) {
    
        int result = bookMapper.updateByVersion(id, name, version);
    
        System.out.println(result==1?"修改成功":"修改失败");
    }
    

    最终运行结果可以发现,只会有一个线程能够修改成功,另外一个修改失败。并且版本号进行了加1。

    使用数据库乐观锁实现分布式锁,在某些情况下频繁与数据库进行交互,会给数据库带来压力

    展开全文
  • 前言: 最近同事开发时遇到了一个事务阻塞的问题,...接着再聊聊数据库锁的触发及升级,以及死锁 最后说下出现锁问题时的常见排查命令 简述事务的特性与隔离级别: 在讲锁之前,必须要先聊聊 事务的特性与隔离级.

    前言:

    最近同事开发时遇到了一个事务阻塞的问题,通过网上查询发现关于MySQL事务、锁这一块的资料都比较絮乱,让人看的云里雾里,所以借着这个机会,刚好也对这一块内容做一个总结梳理,希望能比较全面去写一下MySQL的并发事务处理。

    本文主线:

    • 简述事务的特性与隔离级别

    • 聊聊MySql中各种类型的锁

    • 然后再聊聊MVCC是个什么东东

    • 接着再聊聊数据库锁的触发及升级,以及死锁

    • 最后说下出现锁问题时的常见排查命令

    简述事务的特性与隔离级别:

    在讲锁之前,必须要先聊聊 事务的特性与隔离级别 ,因为锁机制的存在是为了保证事务对应隔离级别下的特性。

    事务具有以下几个特性:

    说完特性,再聊聊MySql中的几种事务隔离级别:

    RU 读未提交:

    顾名思义,在这种隔离级别下,当多个事务并行对同一数据进行操作时,会读取未提交的数据,也被称之为 脏读

    这种隔离级别因为会出现脏读现象,所以在实际场景中很少用。

    RC 读提交:

    一个事务只能看见已经提交事务所做的改变。

    但这种隔离级别会出现 不可重复读 现象,即在一个事务内,多次读同一数据,在这个事务还没有结束时,如果另一个事务恰好修改了这个数据,那么,在第一个事务中,两次读取的数据就可能不一致。

    RR 可重复读:

    这是MySQL的 默认事务隔离级别 ,在这种隔离级别下,解决了RC存在的不可重复读问题,确保在同一事务中,会看到同样的数据行。

    但可能会出现 幻读 ,即当一个事务在执行读取操作,第一次查询数据总量后,另一个事务执行了新增数据的操作并提交后,这个时候第一个事务读取的数据总量和之前统计的不一样,就像产生幻觉一样。

    SERIALIZABLE 串行化:

    此隔离级别是四种隔离级别中最高的级别,解决了 脏读、可重复读、幻读 的问题。

    但是性能最差,它将事务的执行变为顺序执行,与其他三个隔离级别相比,在并行事务执行过程中,后一个事务的执行必须等待前一个事务结束。

    MySql中各种类型的锁:

    在MySQL中,按锁类型划分,有以下种类:

    提到锁到种类,需要提一下MySQL到存储引擎,MySQL常用引擎有 MyISAM和InnoDB ,而InnoDB是mysql默认的引擎。MyISAM是不支持行锁的,而InnoDB支持行锁和表锁。

    MyISAM 存储引擎下表锁:

    MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁;

    读锁会阻塞对同一张表的写操作,而写锁既会阻塞对同一张表的写操作,也会阻塞此表的读操作。

    排他锁、共享锁、意向锁 是什么东东?

    排他锁:

    通常我们在InnoDB存储引擎中对表执行一个更新操作,针对这一行数据会持有排他锁;

    持有排他锁时,不允许再在数据行上添加写锁与读锁,其他事务对此行数据的读、写操作都会被阻塞,只有当前事务提交了,锁释放了才允许其他事务进行读写,达到避免 脏读 的效果。

    共享锁:

    主要是为了支持并发的读取数据而出现的,当一个事务持有某一数据行的共享锁时,允许其它事务可以再获取共享锁,但不允许其它事务在此基础上获取排他锁;

    也就是说,在持有共享锁时,多个事务可以同时读取当前数据,但是不允许任何事务同时对当前数据进行修改操作,阻塞添加排它锁。

    意向锁:

    首先需要明白一点,意向锁的作用是在 表上 的,当一个事务需要获取共享锁或排他锁时,首先要获取对应的意向锁;

    为什么要这样做呢?举个例子,假设在事务A中,对某一行数据添加共享锁,这一行只能读,不能写;此时事务B申请获得表的写锁,假如加锁成功,那么事务B将能够对整个表的数据进行读写,与事务A冲突,这种操作肯定是不允许的呢;

    所以MySQL会在申请共享锁或者排他锁的时候,先获取对应的意向锁,也就是说,你要操作表中的某一行锁数据,先要看看整个表能不能被操作;意向锁的申请是由数据库完成的,不需要人为申请。

    Innodb 存储引擎下的行锁:

    上文对几种锁类型进行了简要分析,其实平时工作开发中接触到最多的还是行锁,行锁的实现有以下几种:

    注意:在Innodb 存储引擎中,行锁的实现是基于索引的

    Record Lock(记录锁):

    它是会锁住索引记录,比如 update table where id = 1, id 是主键,然后在聚簇索引上对 id=1 的个索引记录进行加锁;

    Gap Lock(间隙锁):

    实质上是对索引前后的间隙上锁,不对索引本身上锁,目的是为了防止幻读。

    当使用范围条件查询而不是等值条件检索数据,并请求排他锁、或共享锁时,对于该范围内不存在的记录,不允许其修改插入。

    举个例子:当表中只有一条id=101的记录,一个事务执行select * from user where user_id > 100 for update;此时另一个事务执行插入一条id=102的数据是会阻塞的,必须等待第一个事务提交后才能完成。

    间隙锁是针对事务隔离级别为可重复读或以上级别的。

    Next-Key Lock:

    Next-Key Lock 是 记录锁和间隙锁 的结合,会同时锁住记录与间隙。

    在innodb存储引擎中,如果没有通过 索引项 进行查询时:

    ①、在RR隔离级别下,会以Next-Key Lock的方式对数据行进行加锁,通过 行锁+间隙锁 实现了 “锁表” 的效果,但请记住这不是添加的表锁;

    ②、而在 RU、RC 隔离级别下还是只会锁行记录,为什么呢?因为在innodb存储引擎下的四种事务隔离级别中都支持行锁,但是间隙锁只存在于RR、Serializable 两种隔离级别下。

    可以通过下面这篇文章了解为什么在RR隔离级别下会实现"锁表"的效果,而在RC隔离级别下只会锁行记录: 互联网项目中mysql应该选什么事务隔离级别

    MVCC 是什么:

    锁机制可以控制并发操作,来保证一致性,但是系统开销会很大;在RC、RR的隔离级别下,MySQL的InnoDB存储引擎通过 MVCC (多版本并发控制) 机制来解决幻读。

    使用MVCC时具体的体现是什么呢?

    使事务在并发过程中,SELECT 操作不用加锁,读写不冲突从而提高性能。

    那么实现MVCC机制的原理是什么呢?

    其原理是通过保存数据在某个时间点的快照来实现的;通过在每行记录后面保存隐藏列来存放事务ID,这样每一个事务,都会对应一个递增的事务ID。

    假设三个事务同时更新来同一行数据,那么就会对应三个数据版本,但实际上版本1、版本2并不是物理存在的,而是通过关联记录在undo log 回滚日志中,这样就可以通过undo log找回数据的历史版本,比如回滚的操作,会使用上一个版本的数据覆盖数据页上的数据。

    举例一个RR隔离级别下快照读的例子:

    开启事务A按条件A查询到两条数据,此时事务B再插入1条数据且满足条件A的数据,并提交事务;

    此时事务A再按条件A进行查询,查询到的依然是两条数据,也就是说,事务A查询到的并不是当前最新的数据版本(三条数据),而是通过MVCC实现的历史快照版本;这也是可重复读的实现。

    介绍了完读操作,再举例一个RR隔离级别下 更新 写操作的例子:

    注意:对数据修改的操作(update、insert、delete)都会读到已提交事务的最新数据,因为这就是 当前读。

    假设事务A执行一个更新语句,满足更新条件A(条件A字段无索引或者存在非唯一索引)的数据是2条,更新成功后不提交事务;

    此时事务B插入一条新的满足条件A的数据时会被阻塞的,为什么呢?

    因为这里在事务A更新时使用到了Next-Key Lock锁,它会使用行锁+间隙锁实现了"锁表",所以后面事务B再进行插入数据时会被阻塞的;这也防止了幻读的出现。

    这里如果看的不是很明白的话,可以同时再参考下此文章,此文章详细分析了加锁情况:惊!史上最全的select加锁分析(Mysql)

    注意:

    MVCC只在RC和RR两个隔离级别下支持;其他两个隔离级别和MVCC不兼容,因为 RU总是读取最新的数据行,而不是符合当前事务版本的数据行;而S ERIALIZABLE 则会对所有读取的行都加锁,是当前读,也是读取的最新数据。

    数据库锁的触发及升级,以及死锁:

    数据库锁的触发及升级:

    什么时候会出现DeadLock:

    什么是死锁呢?

    死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。

    此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

    举例说明:

    事务A获取 id=20的锁,事务B获取id=30的锁,然后,事务A试图获取id=30的锁,而该锁已经被事务B持有,所以事务A等待事务 B释放该锁,然后事务B又试图获取id =20 的锁这个锁被事务 A 占有,于是两个事务之间相互等待,这就会导致死锁。

    死锁的场景还有许多,归根结底,都是因为多个事务想要获取的锁互斥且获取的顺序不一致所造成。

    如何避免死锁呢?

    通常Record Lock引起的死锁问题开发时都会比较小心,但Gap Lock可能导致死锁的问题通常会被忽略,所以这一点要多加注意,另外就是建立合适的索引,如果没有索引,那么在操作数据时会锁住每一行,会增大死锁的概率。

    出现锁问题时的常见排查命令:

    show open tabbles:

    SHOW OPEN TABLES where In_use > 0:查看哪些表被锁了

    show status like ‘table%’:

    • table_locks_waited:出现表级锁定争用发生等待的次数,此值高说明存在验证的表记锁争用情况

    • table_locks_immediate:表示立即释放表锁的次数

    show status like ‘innodb_row_lock%’:

    • Innodb_row_lock_current_waits:当前正在等待锁定的数量

    • Innodb_row_lock_time:系统启动到现在锁定总时间

    • Innodb_row_lock_time_avg:每次等待话费的平均时间

    • Innodb_row_lock_time_max:系统启动到现在等待最长一次所花时间

    • Innodb_row_lock_waits:系统启动后到现在共等待次数

    information_schema:

    information_schema是MySQL专门记录性能信息的库,在5.7版本后默认打开。

    • SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS: 查看当前InnoDB的锁的信息,会显示是什么锁类型,属于那个事务ID

    • SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX: 查看InnoDB事务ID,会显示是什么操作和一些常规信息,例如是否在运行running,还是等待锁

    • SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS:查看InnoDB锁的等待时间,和等待的是哪个事务ID的锁

    点赞 + 评论 + 转发 哟

    如果本文对您有帮助的话,请挥动下您爱发财的小手点下赞呀,您的支持就是我不断创作的动力,谢谢啦!

    您可以微信搜索 【木子雷】 公众号,大量Java学习干货文章,您可以来瞧一瞧哟!

    展开全文
  • 大家都知道oracle里面不会发生锁升级的。而在sqlserver,db2里面都会发生锁升级,也...而不像其他数据库里面行锁集中存放的,集中存放的话,当行锁的个数达到一定程度时,由于存放的空间问题,就需要发生锁升级
  • DB2 锁升级

    2019-11-28 18:22:49
    什么是锁升级 所谓的锁升级(lock escalation),是数据库的一种作用机制,为了节约内存的开销,其会将为数众多并占用大量资源的细粒度的锁转化为数量较少的且占用相对较少资源的粗粒度的锁,多数情况下主要指将...
  • SQL Server 锁升级

    2021-02-26 11:05:18
    锁升级是 SQL Server 使用的优化技术,用来控制在 SQL Server 锁管理里把持锁的数量。我们首先从 SQL Server 里所谓的锁层级(Lock Hierarchy )开始,因为那是在像 SQL Server 的关系数据库里,为什么有锁升级概念...
  • MySQL innoDB 中的锁升级

    2019-12-22 15:14:08
    锁升级是指将当前锁的粒度降低,如一把行锁升级唯一把页锁,或者将页锁升级为表锁,如果在数据库设计中认为锁是一中稀有资源,哪么就会频繁有锁升级的现象 发生锁升级的现象 当一条SQL语句对一个对象上持有的锁...
  • 什么是锁? 锁定问题 丢失更新 悲观锁定 乐观锁定 乐观锁定还是悲观锁定? 阻塞 死锁 锁升级
  • 一、基础规范: 1.必须使用InnoDB存储引擎... 解读:utf8mb4utf8的超集,emoji表情以及部分不常见汉字在utf8下会表现为乱码,故需要升级至utf8mb4。 默认使用这个字符集的原因:“标准,万国码,无需转码,无...
  • c#程序 数据库死锁 数据库不是队列。... 这一个愚蠢的故事,在整个过程中,我们将深入研究死锁,锁升级,执行计划和涵盖索引的一些有趣子图,噢,我的天! 希望我们会笑,我们会哭,最后得到坏人(原来我...
  • 数据库不是队列。... 这就是一个愚蠢的故事,在整个过程中,我们将深入研究死锁,锁升级,执行计划和涵盖索引的一些有趣的子图,噢,我的天! 希望我们会笑,我们会哭,最后得到坏人(原来我坏人)。 这...
  • 数据库相关

    2017-12-01 23:01:59
    数据库隔离级别是什么?有什么作用?MySQL主备同步的基本原理。select * from table t where size > 10 group by size order by size的sql语句执行顺序?如何优化数据库性能(索引、分库分表、批量操作、分页算法、...
  • 数据库备份

    2019-06-25 11:09:01
    需要升级数据库或者需要增加一个从库的时候 主库或者从库宕机,需要数据的备份 人为的DDl或者DML的语句,导致主从库的数据消失 跨机房的灾备,需要备份数据到远端程序 mysqldump备份数据库 一般使用的...
  • 数据库的部分理解

    2020-09-23 10:42:21
    数据库锁 数据库锁分为乐观锁和悲观锁 乐观锁:提交的所做的修改数据库时才会加锁,完成修改才会释放锁 悲观锁:从数据开始更改时就将数据锁住,知道更改完成才释放 悲观锁又分为表锁、行锁、页锁 表锁和行锁都分为...
  • 数据库事务有不同的隔离级别,不同的隔离级别对锁的使用不同的,的应用最终导致不同事务的隔离级别MVCC(Multi-Version Concurrency Control)多版本并发控制,可以简单地认为:MVCC就是行级的一个变种(升级版)...
  • 数据库事务有不同的隔离级别,不同的隔离级别对锁的使用不同的,的应用最终导致不同事务的隔离级别MVCC(Multi-Version Concurrency Control)多版本并发控制,可以简单地认为:MVCC就是行级的一个变种(升级版)...
  • 数据库系统实现

    2013-05-12 13:09:11
    本书斯坦福大学计算机科学专业数据库系列课程第二门课的教科书。书中对数据库系统实现原理进行了深入阐述,并具体讨论了数据库管理系统的三个主要成分—存储管理器、查询处理器和事务管理器的实现技术。书中还对...
  • 千次阅读 2018-05-26 17:03:50
    一方面要最大程度地利用数据库的并发访问,另一方面还要确保每个用户能一一致的方式读取和修改数据,这就有了锁的机制;...InnoDB存储引擎不需要锁升级,因为一个锁和多个锁的开销相同的;什么...
  • Firebird数据库中文版

    热门讨论 2011-11-29 08:48:43
    它很容易让您从单用户,单数据库升级到企业级的应用。 一个firebird数据库服务器能够管理多个独立的数据库,每一个数据库同时可支持多个客户端连结。 关键特性:支持原子性,并发性,隔离性等概念。 MGA:支持事务的...
  • 面试题(13)最全BAT数据库面试89题

    万次阅读 2019-04-30 23:00:43
    数据库隔离级别是什么?有什么作用? MySQL主备同步的基本原理。 如何优化数据库性能(索引、分库分表、批量操作、分页算法、升级硬盘SSD、业务优化、主从部署) SQL什么情况下不会使用索引(不包含,不等于,函数)...
  • MySQL

    2019-08-28 14:01:19
    一、什么是锁 锁是数据库系统区别于文件系统的一个关键特性,机制用于管理对共享资源的并发访问。InnoDB存储引擎会在行级别上对表数据加锁。MyIsAM引擎锁是表锁设计,并发情况下的读没有问题,但是并发的插入性能...
  • 数据库隔离级别是什么?有什么作用? MySQL主备同步的基本原理。 如何优化数据库性能(索引、分库分表、批量操作、分页算法、升级硬盘SSD、业务优化、主从部署) SQL什么情况下不会使用索引(不包含,不等于...
  • 多线程中的

    2021-01-29 09:03:14
    文章目录乐观锁和悲观锁公平锁和非公平锁独占锁和共享锁什么是可重入锁锁升级过程?Java对象头偏向锁轻量级锁重量级锁总结锁的升级流程什么是CASLockSupportCondition 乐观锁和悲观锁 乐观锁和悲观锁数据库中...

空空如也

空空如也

1 2 3 4 5 ... 9
收藏数 174
精华内容 69
关键字:

数据库锁升级是什么