InnoDB存储引擎中的锁

文章目录

    • 概要
    • 一、需要解决的问题
    • 二、共享锁和独占锁
      • 1.1 锁定读
      • 1.2 表级别的共享锁、独占锁
    • 三、行锁
      • 3.1 数据准备
      • 3.2 几种常见的行级锁
      • 3.3 行锁升级为表锁

概要

关于MySQL涉及到的锁,大致可以总结如下:
请添加图片描述
MyISAM存储引擎在开发过程中几乎很少使用了,这里主要总结InnoDB存储引擎中的锁。

一、需要解决的问题

数据库中的记录,不可避免地出现并发访问的情况。并发事务,可能会带来以下问题:

  • 脏写
    当两个或多个事务更新同一行记录,会产生更新丢失现象。可以分为回滚覆盖和提交覆盖。
    1)回滚覆盖:一个事务回滚操作,把其他事务已提交的数据给覆盖了
    2)提交覆盖:一个事务提交操作,把其他事务已提交的数据给覆盖了

  • 脏读
    提交覆盖:一个事务提交操作,把其他事务已提交的数据给覆盖了

  • 不可重复读
    提交覆盖:一个事务提交操作,把其他事务已提交的数据给覆盖了

  • 幻读
    一个事务中多次按相同条件查询,结果不一致。后续查询的结果和面前查询结果不同,多了或少了几行记录。

并发事务访问相同记录的操作大致可以划分为3种:

  • 读-读情况:多个事务并发读取同一条记录
    读取操作不会读数据本身造成什么印象,所以这种情况不会存在什么问题

  • 写-写情况:多个事务对同一条记录进行并发修改
    这种情况下会发生脏写的问题,要解决这个问题,其中的一个方法通过锁的方式。如果事务之间涉及到相同的数据项时,会使用排他锁,或叫互斥锁,先进入的事务独占数据项以后,其他事务被阻塞,等待前面的事务释放锁

  • 读-写写-读情况:一个事务进行读取操作,另一个进行改动操作。
    这种情况下可能发生脏读、不可重复读、幻读的问题。
    要解决这些问题,有两种可选方案:
    1)读操作利用多版本并发控制(MVCC),写操作进行加锁
    关于MVCC,可以查看:undo log与mvcc,写操作针对的是最新版本的记录,读记录的历史版本和改动记录的最新版本本身并不冲突,也就是采用MVCC时,读-写操作并不冲突。
    2)读、写操作都采用加锁的方式
    实际开发中,有一些业务场景要求,每次都必须去读取记录的最新版本。比方在银行存款的事务中,需要先把账户余额读出来,操作完后,再写到数据库中。在将账户余额读取出来后,不允许其他事务再修改改账户余额,直到本次存款事务执行完成。这样在读取记录的时候也就需要对其进行加锁,也就意味着操作和操作也像写-写操作那样排队执行。

二、共享锁和独占锁

从操作上对锁进行划分,锁可以分为共享锁和排他锁。

  • 共享锁,英文名:Shared Locks,简称S锁。针对同一份数据,多个读操作可以同时进行而不会互相影响。
  • 排他锁,英文名:Exclusive Locks,简称X锁。当前写操作没有完成前,它会阻断其他写锁和读锁。

顾名思义,共享锁就是,两个或多个事务可以同时获得同一条纪录的S锁。排他锁就是,一个事务先获得了S锁或者是X锁,那么其他事务就不能再获取到该条记录的X锁S锁X锁之间有以下特性:

在这里插入图片描述

1.1 锁定读

数据准备

CREATE TABLE `account` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `name` varchar(32) DEFAULT NULL COMMENT '姓名',
  `balance` int DEFAULT NULL COMMENT '余额',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

mysql> SELECT * FROM account;
+----+--------+---------+
| id | name   | balance |
+----+--------+---------+
|  1 | lilei  |      18 |
|  2 | hanmei |      11 |
|  3 | lucy   |     111 |
|  4 | lilei  |      18 |
+----+--------+---------+
  • 对读取的记录加S锁SELECT ... LOCK IN SHARE MODE;
mysql> begin;

mysql> SELECT * FROM account WHERE id = 1 LOCK IN SHARE MODE;
+----+-------+---------+
| id | name  | balance |
+----+-------+---------+
|  1 | lilei |       1 |
+----+-------+---------+

上面的查询操作,对account表中的id = 1的记录增加了共享锁,其他事务依然可以查到该账户的余额,但是不能对账户余额进行修改,在某种场景下能够满足业务的需求。

  • 对读取记录加X锁SELECT ... FOR UPDATE;
mysql> begin;
Query OK, 0 rows affected (0.01 sec)

mysql> SELECT * FROM account where id = 1 FOR UPDATE;
+----+-------+---------+
| id | name  | balance |
+----+-------+---------+
|  1 | lilei |       1 |
+----+-------+---------+

此时id=1的记录,既不允许别的事务获取S锁,也不允许获取这些记录的X锁(或者直接修改这些记录)。如果别的事务想要获取这些记录的S锁或者X锁,就会阻塞,直到当前事务提交之后释放X锁

这里需要注意,普通的SELECT * FROM account WHERE id = 1;语句是不加锁的。

1.2 表级别的共享锁、独占锁

手动获取InnoDB存储引擎提供的表的S锁或者X锁语法如下:

LOCK TABLES account READInnoDB存储引擎会对表account加表级别的S锁``。

LOCK TABLES S锁 WRITEInnoDB存储引擎会对表S锁加表级别的X锁

在对某表中的记录执行SELECT、INSERT、DELETE、UPDATE语句时,InnoDB存储引擎是不会为这个表添加表级别的S锁或者X锁的。
表级别的S锁X锁有以下特点:

  • 如果一个事务给表加了S锁,那么:
    1)别的事务可以继续获得该表的S锁
    2)别的事务可以继续获得该表中的某些记录的S锁
    3)别的事务不可以继续获得该表的X锁
    4)别的事务不可以继续获得该表中的某些记录的X锁
  • 如果一个事务给表加了X锁(意味着该事务要独占这个表),那么:
    1)别的事务不可以继续获得该表的S锁
    2)别的事务不可以继续获得该表中的某些记录的S锁
    3)别的事务不可以继续获得该表的X锁
    4)别的事务不可以继续获得该表中的某些记录的X锁

在实际开发尽量减少出现表级别的S锁X锁,粒度大,影响访问广,很少有场景使用到。

表级别的IS锁、IX锁

意向共享锁:英文名:Intention Shared Lock,简称IS锁。当事务准备在某条记录上加S锁时,需要先在表级别加一个IS锁
意向独占锁:英文名:Intention Exclusive Lock,简称IX锁。当事务准备在某条记录上加X锁时,需要先在表级别加一个IX锁

IS锁IX锁的提出,只是为了后续在加表级别的S锁X锁判断表中是否有已经被加锁的记录,以避免用遍历的方式来查看表中有没有上锁的记录。

三、行锁

行锁,也称为记录锁,顾名思义,就是作用在表记录上的锁。InnoDB行锁是通过对索引数据页上的记录加锁实现的,主要实现算法有 3 种:Record LockGap LockNext-key Lock

  • Record Lock锁:锁定单个行记录的锁。(记录锁,RC、RR隔离级别都支持)
  • Gap Lock锁:间隙锁,锁定索引记录间隙,确保索引记录的间隙不变。(范围锁,RR隔离级别支持)
  • Next-key Lock 锁:记录锁和间隙锁组合,同时锁住数据,并且锁住数据前后范围。(Record Lock + Gap Lock,RR隔离级别支持)

RR隔离级别,InnoDB对于记录加锁行为都是先采用Next-Key Lock,但是当SQL操作含有唯一索引时,Innodb会对Next-Key Lock进行优化,降级为Record Lock,仅锁住索引本身而非范围。

锁的种类很多(容易晕),划分角度不同,就有不同的叫法;在这里统一总结下,开发过程中常用sql语句涉及到的锁:

  1. select ... from 语句:InnoDB引擎采用MVCC机制实现非阻塞读,所以对于普通的select语句,InnoDB不加锁;
  2. select ... from lock in share mode语句:追加了共享锁,InnoDB会使用Next-Key Lock锁进行处理,如果扫描发现唯一索引,可以降级为Record Lock锁。
  3. select ... from for update语句:追加了排他锁,InnoDB会使用Next-Key Lock锁进行处理,如果扫描发现唯一索引,可以降级为Record Lock锁。
    4)update ... where 语句:InnoDB会使用Next-Key Lock锁进行处理,如果扫描发现唯一索引,可以降级为Record Lock锁。
    5)delete ... where 语句:InnoDB会使用Next-Key Lock锁进行处理,如果扫描发现唯一索引,可以降级为RecordLock锁。
    6)insert语句:一般情况下,新插入一条记录的操作并不加锁。有时候会有插入意向锁

下面以account表操作为例,举例子分析下 InnoDB 对不同索引的加锁行为;

3.1 数据准备

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.27    |
+-----------+
1 row in set (0.00 sec)

mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row in set (0.00 sec)

CREATE TABLE `account` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `code` varchar(32) DEFAULT NULL COMMENT '账号编码',
  `name` varchar(32) DEFAULT NULL COMMENT '姓名',
  `balance` int DEFAULT NULL COMMENT '余额',
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_code` (`code`) USING BTREE COMMENT '账号编码唯一索引',
  KEY `idx_name` (`name`) USING BTREE COMMENT '名称普通索引'
) ENGINE=InnoDB;

mysql> select * from account;
+----+------+--------+---------+
| id | code | name   | balance |
+----+------+--------+---------+
|  1 | aa   | tom    |       1 |
|  3 | dd   | hanmei |      11 |
|  8 | ff   | lucy   |     222 |
| 15 | jj   | jack   |      18 |
| 20 | ll   | ocean  |     400 |
+----+------+--------+---------+

加锁跟索引有关,这里把account表相关的索引结构简化展示如下:

聚簇索引:
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/c025464d55684a348cacc5566460d69e.png

这里只展示了索引中的用户记录信息,同时强调聚簇索引中的记录是按照主键大小排序的。

code列唯一索引:
在这里插入图片描述
name列普通索引:
在这里插入图片描述

3.2 几种常见的行级锁

Record Locks

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update account set balance = 222 where id = 8;
Query OK, 1 row affected (0.00 sec)

通过另外的客户端查看锁情况
执行select * from performance_schema.data_locks\G;
在这里插入图片描述
说明在表层面获取到了IX锁,在数据id=8这条记录加上了LOCK_REC_NOT_GAP锁,也是X锁
在这里插入图片描述

Gap Locks

在普通索引上执行更新

mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> update account set balance= 333 where name='lucy';

查看锁情况

mysql> select * from performance_schema.data_locks\G;
*************************** 1. row ***************************
  -- 边幅原因 这里省略表锁,跟上面一样
*************************** 2. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 139645347953824:226:6:7:139645358804944
ENGINE_TRANSACTION_ID: 65451
            THREAD_ID: 563249
             EVENT_ID: 77
        OBJECT_SCHEMA: fresh
          OBJECT_NAME: account
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: idx_name
OBJECT_INSTANCE_BEGIN: 139645358804944
            LOCK_TYPE: RECORD
            LOCK_MODE: X
          LOCK_STATUS: GRANTED
            LOCK_DATA: 'lucy', 8
*************************** 3. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 139645347953824:226:4:12:139645358805288
ENGINE_TRANSACTION_ID: 65451
            THREAD_ID: 563249
             EVENT_ID: 77
        OBJECT_SCHEMA: fresh
          OBJECT_NAME: account
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 139645358805288
            LOCK_TYPE: RECORD
            LOCK_MODE: X,REC_NOT_GAP
          LOCK_STATUS: GRANTED
            LOCK_DATA: 8
*************************** 4. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 139645347953824:226:6:4:139645358805632
ENGINE_TRANSACTION_ID: 65451
            THREAD_ID: 563249
             EVENT_ID: 77
        OBJECT_SCHEMA: fresh
          OBJECT_NAME: account
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: idx_name
OBJECT_INSTANCE_BEGIN: 139645358805632
            LOCK_TYPE: RECORD
            LOCK_MODE: X,GAP
          LOCK_STATUS: GRANTED
            LOCK_DATA: 'ocean', 20
4 rows in set (0.01 sec)

再执行以下sql时,发现执行阻塞

mysql> insert into account (id,code,name,balance) values(5,'ee','kk',20); -- 阻塞

mysql> insert into account (id,code,name,balance) values(10,'gg','my',20); -- 阻塞

mysql> insert into account (id,code,name,balance) values(10,'gg','pp',20); -- 不会被阻塞
Query OK, 1 row affected (0.00 sec)

加锁分析:
在这里插入图片描述
name字段是普通索引,对满足name='lucy'条件的记录和主键会都加上X锁。同时在字符'jack'-'lucy'之间,'lucy'-'ocean'之间加上了LOCK_GAP锁,所以字符kkmy在插入时会发生阻塞,而字符pp不属于锁的范围,所以能不被阻塞地添加到表中。

gap锁的提出仅仅是为了防止插入幻影记录而提出的,如果对一条记录加了gap锁(不论是共享gap锁还是独占gap锁),并不会限制其他事务对这条记录加Record Locks或者继续加gap锁

对于最后一条记录,GAP锁是如何处理的呢?也就是说给哪条记录加gap锁才能阻止其他事务插入name值在(‘tom’, +∞)这个区间的新记录呢?

mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> update account set balance= 333 where name='tom';  -- 更新普通索引中的最后一条记录

-- 开启另外一个事务
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into account (id,code,name,balance) values(30,'pp','zz',20); -- 想添加到tom后面,发生阻塞
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

Innodb数据页中有两条伪记录:

  • Infimum记录,表示该页面中最小的记录。
  • Supremum记录,表示该页面中最大的记录。

此时,GAP锁如下:

在这里插入图片描述

Next-Key Lock

有时候既想锁住某条记录,又想阻止其他事务在该记录前面的间隙插入新记录,这时候就用到了Next-Key Locks的锁,官方的类型名称为:LOCK_ORDINARY,也可以简称为next-key锁。

在这里插入图片描述
next-key锁的本质就是一个Record Locks和一个gap锁的合体,它既能保护该条记录,又能阻止别的事务将新记录插入被保护记录前面的间隙。

Insert Intention Locks

一个事务在插入一条记录时需要判断插入位置是不是被别的事务加了gap锁next-key锁也包含gap锁),如果有的话,插入操作需要等待,直到持有gap锁的事务释放锁。InnoDB规定事务在等待的时候也需要在内存中生成一个锁结构,表明有事务想在某个间隙中插入新记录,但是现在在等待。这种类型的锁命名为Insert Intention Locks,官方的类型名称LOCK_INSERT_INTENTION,也称为插入意向锁。

mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> update account set balance = 55 where id >3 and id <=8;

-- 开启另外事务
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into account (id,code,name,balance) values(6,'pp','zz',20);

查看锁情况

mysql> select * from performance_schema.data_locks\G;
*************************** 1. row ***************************
   -- 省略表锁
*************************** 2. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 139645347952208:226:4:12:139645358792496
ENGINE_TRANSACTION_ID: 65493
            THREAD_ID: 563275
             EVENT_ID: 90
        OBJECT_SCHEMA: fresh
          OBJECT_NAME: account
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 139645358792496
            LOCK_TYPE: RECORD
            LOCK_MODE: X,GAP,INSERT_INTENTION
          LOCK_STATUS: WAITING
            LOCK_DATA: 8
*************************** 3. row ***************************
 - 省略表锁
*************************** 4. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 139645347953824:226:4:12:139645358804944
ENGINE_TRANSACTION_ID: 65492
            THREAD_ID: 563249
             EVENT_ID: 116
        OBJECT_SCHEMA: fresh
          OBJECT_NAME: account
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 139645358804944
            LOCK_TYPE: RECORD
            LOCK_MODE: X
          LOCK_STATUS: GRANTED
            LOCK_DATA: 8
4 rows in set (0.00 sec)

从上面看出id=8的记录添加了插入意向锁,并且锁的状态为等待。

3.3 行锁升级为表锁

InnoDB引擎锁机制是基于索引实现的记录锁定,当没有索引时,会导致全表锁定

mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> update account set balance = 2 where balance = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

开启另外一个事务

mysql> update account set balance = 5 where id = 3; -- 阻塞

通过查看锁情况,发生每条记录都被加上了X锁

mysql> select * from performance_schema.data_locks\G;
*************************** 1. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 139645347952208:1287:139645358795600
ENGINE_TRANSACTION_ID: 65496
            THREAD_ID: 563275
             EVENT_ID: 94
        OBJECT_SCHEMA: fresh
          OBJECT_NAME: account
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: NULL
OBJECT_INSTANCE_BEGIN: 139645358795600
            LOCK_TYPE: TABLE
            LOCK_MODE: IX
          LOCK_STATUS: GRANTED
            LOCK_DATA: NULL
*************************** 2. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 139645347952208:226:4:13:139645358792496
ENGINE_TRANSACTION_ID: 65496
            THREAD_ID: 563275
             EVENT_ID: 94
        OBJECT_SCHEMA: fresh
          OBJECT_NAME: account
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 139645358792496
            LOCK_TYPE: RECORD
            LOCK_MODE: X,REC_NOT_GAP
          LOCK_STATUS: WAITING
            LOCK_DATA: 3
*************************** 3. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 139645347953824:1287:139645358807936
ENGINE_TRANSACTION_ID: 65495
            THREAD_ID: 563249
             EVENT_ID: 120
        OBJECT_SCHEMA: fresh
          OBJECT_NAME: account
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: NULL
OBJECT_INSTANCE_BEGIN: 139645358807936
            LOCK_TYPE: TABLE
            LOCK_MODE: IX
          LOCK_STATUS: GRANTED
            LOCK_DATA: NULL
*************************** 4. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 139645347953824:226:4:1:139645358804944
ENGINE_TRANSACTION_ID: 65495
            THREAD_ID: 563249
             EVENT_ID: 120
        OBJECT_SCHEMA: fresh
          OBJECT_NAME: account
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 139645358804944
            LOCK_TYPE: RECORD
            LOCK_MODE: X
          LOCK_STATUS: GRANTED
            LOCK_DATA: supremum pseudo-record
*************************** 5. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 139645347953824:226:4:7:139645358804944
ENGINE_TRANSACTION_ID: 65495
            THREAD_ID: 563249
             EVENT_ID: 120
        OBJECT_SCHEMA: fresh
          OBJECT_NAME: account
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 139645358804944
            LOCK_TYPE: RECORD
            LOCK_MODE: X
          LOCK_STATUS: GRANTED
            LOCK_DATA: 1
*************************** 6. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 139645347953824:226:4:8:139645358804944
ENGINE_TRANSACTION_ID: 65495
            THREAD_ID: 563249
             EVENT_ID: 120
        OBJECT_SCHEMA: fresh
          OBJECT_NAME: account
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 139645358804944
            LOCK_TYPE: RECORD
            LOCK_MODE: X
          LOCK_STATUS: GRANTED
            LOCK_DATA: 15
*************************** 7. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 139645347953824:226:4:10:139645358804944
ENGINE_TRANSACTION_ID: 65495
            THREAD_ID: 563249
             EVENT_ID: 120
        OBJECT_SCHEMA: fresh
          OBJECT_NAME: account
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 139645358804944
            LOCK_TYPE: RECORD
            LOCK_MODE: X
          LOCK_STATUS: GRANTED
            LOCK_DATA: 20
*************************** 8. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 139645347953824:226:4:12:139645358804944
ENGINE_TRANSACTION_ID: 65495
            THREAD_ID: 563249
             EVENT_ID: 120
        OBJECT_SCHEMA: fresh
          OBJECT_NAME: account
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 139645358804944
            LOCK_TYPE: RECORD
            LOCK_MODE: X
          LOCK_STATUS: GRANTED
            LOCK_DATA: 8
*************************** 9. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 139645347953824:226:4:13:139645358804944
ENGINE_TRANSACTION_ID: 65495
            THREAD_ID: 563249
             EVENT_ID: 120
        OBJECT_SCHEMA: fresh
          OBJECT_NAME: account
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 139645358804944
            LOCK_TYPE: RECORD
            LOCK_MODE: X
          LOCK_STATUS: GRANTED
            LOCK_DATA: 3
9 rows in set (0.00 sec)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/200668.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【重磅合作】九章云极DataCanvas公司与生态伙伴强强联手,构建人工智能强生态!

11月21日&#xff0c;在「筑基赋能 智向未来」九章云极DataCanvas大模型系列成果发布会上&#xff0c;九章云极DataCanvas公司与人工智能产业链上下游合作伙伴广东民营投资股份有限公司&#xff08;以下简称“粤民投”&#xff09;、西藏赛富合银投资有限公司&#xff08;以下简…

通过流量监控分析某个部门或客户端网络性能

在当今数字化时代&#xff0c;网络已经成为组织和企业不可或缺的基础设施之一。作为信息传输和数据交互的关键载体&#xff0c;网络的性能对于保障业务的稳定运行和提升工作效率至关重要。因此&#xff0c;对某个部门或客户端网络的性能进行分析和评估&#xff0c;有助于了解当…

vue2 el-table 封装

vue2 el-table 封装 在 custom 文件夹下面创建 tableList.vue直接上代码&#xff08;代码比较多&#xff0c;复制可直接用&#xff09; <template><div class"mp-list"><el-tableref"multipleTable"class"mp-custom-table":dat…

解决d3dcompiler_43.dll文件丢失的方法,最详细的d3dcompiler_43.dll修复指南

如果你的电脑出现了d3dcompiler_43.dll文件丢失的问题&#xff0c;你知道要怎么去解决么&#xff1f;其实要解决这个问题还是比较简单的&#xff0c;只要你了解清楚d3dcompiler_43.dll文件&#xff0c;那么就知道有多种不同的方法可以去解决它&#xff0c;下面我们一起来看看吧…

bodymovin:AE动画导出为JSONforMac/win中文版下载

对于动画制作爱好者和专业设计师来说&#xff0c;Adobe After Effects&#xff08;AE&#xff09;是一个强大的工具&#xff0c;可以创造出惊人的动画效果。然而&#xff0c;将这些动画导出为可交互的格式一直是一个挑战。现在&#xff0c;有了bodymovin&#xff0c;你可以轻松…

【C++初阶】:简单的图书管理系统(可保存,完整源代码)

图书管理系统 library.h #include<iostream> #include<string> #include<vector> using namespace std;/****************************************************************公共类**********************************************************************…

element-plus 使用密码输入框的自定义图标

<el-inputv-model"ruleFormPassword.newPassword"placeholder"请输入新密码":type"showPassword ? text : password":style"{ width: 360px }"><template #suffix><span class"input_icon" click"swit…

视频智能分析国标GB28181云平台EasyCVR加密机授权异常是什么原因?

国标GB28181视频汇聚/视频云存储/集中存储/视频监控管理平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;实现视频资源的鉴权管理、按需调阅、全网分发、云存储、智能分析等。 近期有用户选择使用加密机进行EasyCVR授…

在线 SQL 模拟器SQL Fiddle使用简介

在线 SQL 模拟器SQL Fiddle使用简介 本文可作为“SQL语言与SQL在线实验工具的使用” https://blog.csdn.net/cnds123/article/details/115038700 一文的补充。 有时候&#xff0c;我们想去验证 SQL语句&#xff0c;却缺少数据库环境&#xff0c;那该怎么办呢&#xff1f; 这…

【css】调整图片样式-铅笔画-以及其它

[css]调整图片样式-铅笔画-以及其它 在这个网址下有很多实例&#xff0c;尝试了其中几个&#xff0c;成功实现的对半分。使用Micsoft&#xff0c;估计是不支持一些特性导致的。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UT…

微信公众号扫码授权登录源码 / PHP微信扫码关注公众号并授权登录源码

源码简介&#xff1a; 在当今的互联网时代&#xff0c;微信公众号已成为众多企业与用户之间进行交流和沟通的重要工具&#xff0c;其中包括用户的登录认证。通过关注公众号登录&#xff0c;不仅可以为公众号带来流量&#xff0c;还能够实现用户与公众号粉丝之间的一一对应关系…

ubuntu下训练自己的yolov5数据集

参考文档 yolov5-github yolov5-github-训练文档 csdn训练博客 一、配置环境 1.1 安装依赖包 前往清华源官方地址 选择适合自己的版本替换自己的源 # 备份源文件 sudo cp /etc/apt/sources.list /etc/apt/sources.list_bak # 修改源文件 # 更新 sudo apt update &&a…

深度解析Python复合赋值运算符

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在Python中&#xff0c;复合赋值运算符是编程旅程中的得力助手。这些简洁而强大的运算符&#xff0c;如、-、*&#xff0c;不仅让代码更具可读性&#xff0c;而且提高了开发效率。从基础的数值操作到字符串和列表…

网络和Linux网络_6(应用层)HTTPS协议(加密解密+中间人攻击+证书)

目录 1. HTTPS协议介绍 1.1 加密解密和秘钥的概念 1. 2 为什么要加密 2. 对称加密和非对称加密 2.1 只使用对称加密 2.2 只使用非对称加密 2.3 双方都使用非对称加密 2.4 使用非对称加密对称加密 2.5 中间人攻击MITM 3. 证书的概念和HTTPS的通信方式 3.1 CA认证机构…

Redis -- 介绍

1、NoSQL: 指的是非关系型数据库&#xff0c;主要分成四大类&#xff1a;键值存储数据库、列存储数据库、文档型数据库、图形数据库。 2、什么是Redis&#xff1a; Redis是一种基于内存的数据库&#xff0c;一般用于做缓存的中间件。 3、Redis的主要的特点&#xff1a; 1、Rd…

Java LeetCode篇-深入了解关于单链表的经典解法

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 移除链表元素 1.1 使用双指针方法 2.0 反转链表 2.1 递归法 2.2 头插法 3.0 链表中倒数第 k 个节点 3.1 递归法 3.2 快慢指针 4.0 合并两个有序链表 4.1 递归法 …

三季度同道猎聘遇“瓶颈”,破局重点是中高端人才?

古往今来&#xff0c;人才一直是企业“争夺”的对象。随着新兴产业的快速冒头以及AI技术的崛起&#xff0c;新型人才以及中高端人才成为市场上的香饽饽&#xff0c;而这类人才的稀缺性让企业和招聘平台双方都很“头疼”。再加上外部环境的不确定性增加&#xff0c;职场人普遍求…

【工具使用-Audition】如何使用Auditon生成直流信号

一&#xff0c;简介 在工作的过程中需要生成直流信号&#xff0c;测试验证使用。本文主要介绍如何使用Audition生成指定长度的直流信号。 二&#xff0c;操作步骤 这里以Audition 2020&#xff0c;生成一个10s的-6db幅值的立体声文件为例进行介绍。 2.1 新建音频文件&#…

瑞云科技参与《数字孪生世界白皮书》编写,实时云渲染助力数字孪生

为了促进数字孪生技术的发展和应用&#xff0c;易知微与数字孪生世界企业联盟联合众多行业专家以及多家业内企业共同编写了《数字孪生世界白皮书&#xff08;2023&#xff09;》。该白皮书从数字孪生的综述、应用架构、核心技术、新型技术成果和重点行业应用等方面&#xff0c;…

Redis 入门和环境搭建

认识Redis Redis是一种NoSQL数据库&#xff0c;以键值对形式存储数据&#xff0c;支持多种数据结构&#xff0c;包括字符串、哈希、列表、集合、有序集合等&#xff0c;使其适用于多种应用场景。由于所有数据都存储在内存中&#xff0c;Redis的读写性能非常高。同时&#xff0…