MySQL锁:全局锁、表级锁和行锁

2023-05-16

事务的实现离不开MySQL数据库的锁机制,设计锁的目的也是为了处理并发访问问题,本文简单介绍MySQL 里面的全局锁、表级锁和行锁三类锁。

目录

  • 全局锁
  • 表级锁
    • 表锁
      • 1、读锁实例
      • 2、写锁实例
    • 元数据锁
  • 行锁
    • 行锁简介
    • 行锁实例
    • 死锁
  • 总结

按对数据操作的类型可分为读锁(read lock)和写锁(write lock)。

  • 读锁也叫共享锁(S锁),加了读锁后,加锁的当前会话以及其它会话只能进行读操作,并且多个读操作可以同时进行。
  • 写锁也称为排他锁, X锁, exclusive 的缩写,因为加了写锁之后其它会话不能进行读写操作。

从对数据操作的颗粒度来分,锁可以分为全局锁、表级锁和行锁,下面分别对他们进行介绍。

全局锁

全局锁是对整个数据库加锁,数据库被加上全局锁后所有数据表会处于只读状态,修改数据表的DDL语句,数据更新语句(增删改)等操作会被阻塞。

全局锁的命令是:FLUSH TABLES WITH READ LOCK; , 简称FTWRL,解锁命令:UNLOCK TABLES;

窗口A加全局锁:

mysql> FLUSH TABLES WITH READ LOCK;
Query OK, 0 rows affected (0.00 sec)

窗口A插入数据会报错:

mysql> insert into department (name) values ('测试');
ERROR 1223 (HY000): Can't execute the query because you have a conflicting read lock

窗口B查询:

mysql> select * from department;
+----+------+
| id | name |
+----+------+
|  1 | 开发 |
|  2 | 产品 |
|  5 | 测试 |
+----+------+
3 rows in set (0.04 sec)

窗口B插入数据会被阻塞:

mysql> insert into department (name) values ('测试');

窗口A解锁:

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

窗口B插入语句执行成功:

mysql> insert into department (name) values ('测试');
Query OK, 1 row affected (2 min 44.85 sec)

mysql> select * from department;
+----+------+
| id | name |
+----+------+
|  1 | 开发 |
|  2 | 产品 |
|  5 | 测试 |
|  6 | 测试 |
+----+------+
4 rows in set (0.00 sec)

全局锁的一个使用场景是做全库逻辑备份(mysqldump),加了全局锁后,在备份过程中整个库处于只读状态。如果备份主库,备份期间更新相关业务都无法执行;如果是备份从库,备份期间从库就不能执行主库同步过来的 binlog,会导致主从延迟。

支持事务的引擎InnoDB可以不使用FTWRL,使用mysqldump命令备份时可以使用参数 --single-transaction 来获取一致性备份,它会在开始备份前启动一个事务(可重复读隔离级别),利用了MVCC技术(可参考文章MySQL事务:事务隔离),确保拿到一致性视图,备份过程可以正常更新数据。

而不支持事务的引擎MyISAM就无法使用 --single-transaction参数了,它不支持事务隔离,所以使用MyISAM引擎的数据库备份需要使用FTWRL命令。

表级锁

表级锁是对整张表加锁,MyISAM、InnoDB、BDB和MEMOR都支持表级锁。

MySQL 表级锁包括两种:表锁和元数据锁(meta data lock,MDL)。

表锁

表锁包括读锁(read lock)和写锁(write lock)。

lock table 表名 read;  -- 读锁 
lock table 表名 write; -- 写锁
unlock tables; -- 释放表锁,连接断开时会自动释放表锁

以MyISAM引擎为例演示一下表锁的作用效果:

创建一个以MyISAM为引擎的表,并插入一条记录:

create table table_lock_test(
    id int not null auto_increment primary key,
    name char(30) not null) ENGINE=MyISAM DEFAULT CHARSET=utf8;
    
insert into table_lock_test (name) values ('zhangsan');    

1、读锁实例

窗口A给table_lock_test表加读锁:

mysql> lock table table_lock_test read;
Query OK, 0 rows affected (0.04 sec)

mysql> select * from table_lock_test;
+----+----------+
| id | name     |
+----+----------+
|  1 | zhangsan |
+----+----------+
1 row in set (0.00 sec)

查看被锁定的表:

mysql> show open tables where In_use > 0;
+----------+-----------------+--------+-------------+
| Database | Table           | In_use | Name_locked |
+----------+-----------------+--------+-------------+
| testdb   | table_lock_test |      1 |           0 |
+----------+-----------------+--------+-------------+
1 row in set (0.00 sec)

窗口A执行更新、插入操作:

mysql> update table_lock_test set name='lishi' where id=1;
ERROR 1099 (HY000): Table 'table_lock_test' was locked with a READ lock and can't be updated

mysql> insert into table_lock_test (name) values ('lishi');
ERROR 1099 (HY000): Table 'table_lock_test' was locked with a READ lock and can't be updated

窗口A读其它表:

mysql> select * from department;
ERROR 1100 (HY000): Table 'department' was not locked with LOCK TABLES

未解锁前不能操作其它表。

窗口B查询:

mysql> select * from table_lock_test;
+----+----------+
| id | name     |
+----+----------+
|  1 | zhangsan |
+----+----------+
1 row in set (0.00 sec)

窗口B执行更新操作:

mysql> update table_lock_test set name='lishi' where id=1;

更新操作会被阻塞,因为读锁没有被释放,只能查询不能更新。到窗口A将锁释放:

unlock tables;

解锁后,窗口B更新操作成功:

mysql> update table_lock_test set name='lishi' where id=1;
Query OK, 1 row affected (3 min 22.88 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from table_lock_test;
+----+-------+
| id | name  |
+----+-------+
|  1 | lishi |
+----+-------+
1 row in set (0.00 sec)

2、写锁实例

窗口A给table_lock_test表加写锁:

mysql> lock table table_lock_test write;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from table_lock_test;
+----+-------+
| id | name  |
+----+-------+
|  1 | lishi |
+----+-------+
1 row in set (0.00 sec)

窗口A执行更新、插入操作:

mysql> update table_lock_test set name='zhangsan' where id=1;
Query OK, 1 row affected (0.05 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> insert into table_lock_test (name) values ('lishi');
Query OK, 1 row affected (0.05 sec)

mysql> select * from table_lock_test;
+----+----------+
| id | name     |
+----+----------+
|  1 | zhangsan |
|  2 | lishi    |
+----+----------+
2 rows in set (0.00 sec)

窗口A读其它表:

mysql> select * from department;
ERROR 1100 (HY000): Table 'department' was not locked with LOCK TABLES

和读锁一样,未解锁前不能其它表进行CRUD操作。

窗口B查询:

mysql> select * from table_lock_test;

被阻塞了,因为写锁为排它锁,其它连接不能对table_lock_test表进行读写操作。

到窗口A将锁释放:

unlock tables;

解锁后,窗口B查询成功:

mysql> select * from table_lock_test;
+----+----------+
| id | name     |
+----+----------+
|  1 | zhangsan |
|  2 | lishi    |
+----+----------+
2 rows in set (3 min 10.99 sec)

元数据锁

在 MySQL 5.5 以后的版本中,访问一个表的时候会自动加上 MDL(metadata lock),作用是保证读写的正确性。比如在RR隔离级别下,当前事务A在操作一个表的过程中,另外一个事务B对表执行DDL操作(表结构变更),如果没有MDL,会导致事务A 两次查询结果不一样。要实现可重复度,就需要使用到MDL。

当对一个表做DML操作(增删改查)时,加 MDL 读锁,当其它事务对表进行DDL操作时,需要先获得MDL 读锁才能对表结构进行修改;当要对表做DDL操作(表结构变更)时,会加 MDL 写锁。

  • 读锁之间不互斥,多事务同时对一张表进行DML操作不会阻塞。 注意:实际进行增删改查时可能会看到锁等待,这是InnoDB的行锁导致的。
  • 读写锁之间互斥,也就是对同一表进行的DML和DDL操作会相互阻塞。
  • 写锁之间互斥,多事务同时对一张表进行DDL操作会阻塞,其中一个要等另一个执行完才能开始执行。

MDL锁在语句开始执行时申请,在事务提交后释放。如果事务A对表T加了一个MDL读锁,且未提交。事务B对数据表执行DDL操作,此时事务B会被锁住(Waiting for table metadata lock),因为事务A 的 MDL 读锁没有释放,而事务B需要 MDL 写锁,因此会被阻塞。而后续对表T的任何操作都会被阻塞,此时表T完全不可读写了。MDL 锁的这一机制需要特别注意。

在窗口A启动一个事务:

mysql> select * from performance_schema.metadata_locks;
+-------------+--------------------+----------------+-------------+-----------------------+-------------+---------------+-------------+-------------------+-----------------+----------------+
| OBJECT_TYPE | OBJECT_SCHEMA      | OBJECT_NAME    | COLUMN_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE   | LOCK_DURATION | LOCK_STATUS | SOURCE            | OWNER_THREAD_ID | OWNER_EVENT_ID |
+-------------+--------------------+----------------+-------------+-----------------------+-------------+---------------+-------------+-------------------+-----------------+----------------+
| TABLE       | performance_schema | metadata_locks | NULL        |         1883582562928 | SHARED_READ | TRANSACTION   | GRANTED     | sql_parse.cc:5929 |              75 |              4 |
+-------------+--------------------+----------------+-------------+-----------------------+-------------+---------------+-------------+-------------------+-----------------+----------------+
1 row in set (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.04 sec)

mysql> select * from table_lock_test;
+----+----------+
| id | name     |
+----+----------+
|  1 | zhangsan |
|  2 | lishi    |
+----+----------+
2 rows in set (0.14 sec)

mysql> select * from performance_schema.metadata_locks;
+-------------+--------------------+-----------------+-------------+-----------------------+-------------+---------------+-------------+-------------------+-----------------+----------------+
| OBJECT_TYPE | OBJECT_SCHEMA      | OBJECT_NAME     | COLUMN_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE   | LOCK_DURATION | LOCK_STATUS | SOURCE            | OWNER_THREAD_ID | OWNER_EVENT_ID |
+-------------+--------------------+-----------------+-------------+-----------------------+-------------+---------------+-------------+-------------------+-----------------+----------------+
| TABLE       | testdb             | table_lock_test | NULL        |         1883582562928 | SHARED_READ | TRANSACTION   | GRANTED     | sql_parse.cc:5929 |              75 |              7 |
| TABLE       | performance_schema | metadata_locks  | NULL        |         1883583662656 | SHARED_READ | TRANSACTION   | GRANTED     | sql_parse.cc:5929 |              75 |              8 |
+-------------+--------------------+-----------------+-------------+-----------------------+-------------+---------------+-------------+-------------------+-----------------+----------------+
2 rows in set (0.00 sec)

mysql>


事务A启动后,metadata_locks表新增了一条table_lock_test表的加锁记录。

窗口B执行一个修改表结构的DDL操作:

mysql> show processlist;
+----+-----------------+-----------------+--------+---------+---------+---------------------------------+---------------------------------------------+
| Id | User            | Host            | db     | Command | Time    | State                           | Info                                        |
+----+-----------------+-----------------+--------+---------+---------+---------------------------------+---------------------------------------------+
|  4 | event_scheduler | localhost       | NULL   | Daemon  | 1693591 | Waiting on empty queue          | NULL                                        |
| 36 | root            | localhost:61623 | testdb | Query   |       0 | starting                        | show processlist                            |
| 37 | root            | localhost:55438 | testdb | Query   |      93 | Waiting for table metadata lock | ALTER TABLE table_lock_test ADD age TINYINT |
+----+-----------------+-----------------+--------+---------+---------+---------------------------------+---------------------------------------------+
3 rows in set (0.05 sec)


可以发现线程37在等待MDL锁。

接着窗口C执行查询操作:

mysql> select * from table_lock_test;

也被阻塞了,后续对表table_lock_test的任何操作都会被阻塞掉。

到窗口A提交事务

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

B和C执行成功。查询表,字段添加成功:

mysql> select * from table_lock_test;
+----+----------+------+
| id | name     | age  |
+----+----------+------+
|  1 | zhangsan | NULL |
|  2 | lishi    | NULL |
+----+----------+------+
2 rows in set (0.00 sec)

查询table_lock_test表的加锁记录,表table_lock_test消失:

mysql> select * from performance_schema.metadata_locks;
+-------------+--------------------+----------------+-------------+-----------------------+-------------+---------------+-------------+-------------------+-----------------+----------------+
| OBJECT_TYPE | OBJECT_SCHEMA      | OBJECT_NAME    | COLUMN_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE   | LOCK_DURATION | LOCK_STATUS | SOURCE            | OWNER_THREAD_ID | OWNER_EVENT_ID |
+-------------+--------------------+----------------+-------------+-----------------------+-------------+---------------+-------------+-------------------+-----------------+----------------+
| TABLE       | performance_schema | metadata_locks | NULL        |         1883583665248 | SHARED_READ | TRANSACTION   | GRANTED     | sql_parse.cc:5929 |              75 |             13 |
+-------------+--------------------+----------------+-------------+-----------------------+-------------+---------------+-------------+-------------------+-----------------+----------------+
1 row in set (0.00 sec)

行锁

行锁简介

行锁是对数据行加锁,是在引擎层实现的,MyISAM 引擎不支持行锁,而 InnoDB 引擎是支持行锁的,因此相比MyISAM 引擎,InnoDB可以提供良好的并发控制。

当然行锁也包括读锁(read lock)和写锁(write lock)。

  • 读锁也叫共享锁,S锁,加了读锁后,加锁的当前会话以及其它会话只能进行读操作,并且多个读操作可以同时进行。
  • 写锁也称为排他锁,X锁, exclusive 的缩写,因为加了写锁之后其它会话不能进行读写操作。

当前读都会加行锁:

select * from account lock in share mode; # 添加读锁(S 锁,共享锁)
select * from account for update; # 添加写锁(X 锁,排他锁)
insert语句
update语句
delete语句

InnoDB 引擎的行锁会自动加上,比如在更新数据时会自动加上行锁,其它事务对相同行数据进行更新时就会被阻塞,直到锁被释放才能更新。

行锁不是在数据更新完行之后就立马解锁,而是在事务提交(commit)或者回滚(rollback)之后才会解锁。这称为两阶段锁协议,包括加锁和解锁两个阶段。

行锁实例

下面看一个例子:

先创建一个表,使用InnoDB引擎:

create table table_row_lock(
    id int not null auto_increment primary key COMMENT 'ID',
    name char(30) not null COMMENT '名称') ENGINE=InnoDB 
	DEFAULT CHARSET=utf8
	comment = '行锁测试'; 	

事务隔离级别为可重复读(RR)。

插入数据:

mysql> insert into table_row_lock (name) values ('张三');
Query OK, 1 row affected (0.07 sec)

mysql> insert into table_row_lock (name) values ('李四');
Query OK, 1 row affected (0.09 sec)

mysql> select * from table_row_lock;
+----+------+
| id | name |
+----+------+
|  1 | 张三 |
|  2 | 李四 |
+----+------+
2 rows in set (0.00 sec)

窗口A启动一个事务,并更新数据:

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

mysql> update table_row_lock set name="王二" where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from table_row_lock;
+----+------+
| id | name |
+----+------+
|  1 | 王二 |
|  2 | 李四 |
+----+------+
2 rows in set (0.00 sec)

窗口B更新相同行的记录,会被阻塞:

mysql> update table_row_lock set name="张三" where id=1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

行锁等待时间可以执行 SHOW VARIABLES LIKE 'innodb_lock_wait_timeout'; 命令查看:

mysql> SHOW VARIABLES LIKE 'innodb_lock_wait_timeout';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 50    |
+--------------------------+-------+
1 row in set, 1 warning (0.01 sec)

窗口B更新其它行记录:

mysql> update table_row_lock set name="王五" where id=2;
Query OK, 1 row affected (0.07 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from table_row_lock;
+----+------+
| id | name |
+----+------+
|  1 | 张三 |
|  2 | 王五 |
+----+------+
2 rows in set (0.00 sec)

id=2行数据没有被加写锁,所以可以对它进行更新操作。

窗口A提交事务:

mysql> commit;
Query OK, 0 rows affected (0.07 sec)

此时窗口B就可以更新id=1那行数据了。

mysql> update table_row_lock set name="张三" where id=1;
Query OK, 1 row affected (0.06 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from table_row_lock;
+----+------+
| id | name |
+----+------+
|  1 | 张三 |
|  2 | 王五 |
+----+------+
2 rows in set (0.00 sec)

死锁

真实业务中通常对数据库进行并发控制,多个事务可能会依赖相同的资源,如果都在等待其它事务释放锁时,这会导致这几个事务进入无限等待的状态,也就是出现死锁。

比如下图就会出现死锁,事务 A 在等待事务 B 释放 id=2 的行锁,而事务 B 在等待事务 A 释放 id=1 的行锁。

image

出现死锁后,有两种策略来解决:

  1. 等待锁超时。默认超时等待时间为50s,可通过innodb_lock_wait_timeout参数来设置,具体等待时间需要根据自己的实际业务来设置。
  2. 死锁检测。设置参数innodb_deadlock_detect = on,开启后,系统会自动检测死锁的事务并回滚某一个事务,让其他可以事务继续执行。

总结

本文简单介绍了全局锁、表级锁和行锁,全局锁主要用于全库逻辑备份。如果数据库引擎使用的是 InnoDB,可以使用 -–single-transaction 参数。

表锁是对整张表加锁,访问一个表的时候会自动加上元数据锁(MDL),MDL锁在语句开始执行时申请,在事务提交后释放。如果表T的MDL锁没有释放,后续对表T的任何操作都会被阻塞。

行锁是对数据行加锁,MyISAM引擎不支持行锁,它一般使用的是表级锁。InnoDB 引擎支持行锁,因此它可以实现更好的并发控制。另外使用行锁要注意尽量减少死锁对数据库的影响。

另外要注意的是,加锁是要消耗资源的,对锁的各种操作会增加系统的开销,相比MyISAM引擎,InnoDB 引擎的行锁会导致占用更大的数据空间。

--THE END--

凡是对自己有一点利益就会选择相信。有时候即使毫无可能,人们也会顽冥不化。
——艾萨克·阿西莫夫《神们自己》

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MySQL锁:全局锁、表级锁和行锁 的相关文章

  • Debian .bashrc以及.profile的区别 以及修改history记录的历史命令

    etc profile 系统环境变量 对每个用户都会生效 用户第一次登录时 该文件被执行并且从 etc profile d 目录的配置文件中收集shell设置 所以修改了之后需要重启或者执行 source etc profile 才会生效
  • Debian10 如何设置关闭屏幕和设置锁屏时间

  • 如何解决vs中无法使用utf8文件的问题 请将该文件保存为 Unicode 格式以防止数据丢失

    在深入理解c 43 43 11一书中有说两个字符集 xff0c 一个源码字符集 xff0c 一个编码字符集 xff08 在msvc编译器文档里面叫做执行字符集 xff09 一个是文件的保存格式 一个是编译器在编译过程中如何编码字符串 文件用
  • ffmpeg透明贴图

    lt span style 61 34 font family monospace white space pre background color rgb 240 240 240 34 gt 读取视频每帧的AVFrame xff0c 和图
  • 更换Ubuntu源

    图形界面配置 xff08 新手推荐 xff09 依次打开 xff1a 系统设置 xff0c 软件和更新 在 下载自 中选择 其他站点 xff0c 然后在中国的条目下选择 mirrors ustc edu cn 下面是 Ubuntu 16 0
  • Ubuntu20安装详细步骤,用于嵌入式开发

    不知不觉安装安装Ubuntu20已经一年了 xff0c 其实才半个来月 xff0c O O哈哈 xff0c 今天分享给大家整个安装过程 xff0c 让那些虚拟机界面非常小的知道如何安装 xff0c 好的 一 首先我们需要一个虚拟机 xff0
  • Debian8.8开发环境(四)个人设置之bashrc

    个人的一些命令在 xff5e bashrc中配置 xff0c 设置的好可以为工作带来极大的方便 xff0c 下面是贴出的个人的一部分设置 xff0c 仅供参考 基本就是使用alias去设置一些快捷的使用方式和查找一些个人的工作目录 span
  • Debian9.4.0win10上双系统U盘安装教程

    一 镜像下载 Debian一直是本人最喜欢的桌面操作系统 xff0c 所以也分享下windows10下双系统安装的过程 xff0c 至于虚拟机安装则就更简单了 xff0c 在此不做赘述 相比虚拟机本人更喜欢完全抛弃win而在linux un
  • win10系统如何开启/安装ubuntu子系统

    注 xff1a 此教程仅对windows 10家庭中文版做过测试 第一步 开启linux子系统选项 控制面板 gt 程序 gt 程序和功能 gt 启用或关闭Windows功能 gt 适用于Linux的Windows子系统 gt 确定 xff
  • maven日常问题

    问题1 jdk配置打包报错问题 maven打包报错如下 dependencyManagement dependencies dependency systemPath span class token keyword for span jd
  • 穿山甲广告对接

    一 清除其他sdk影响 二 接入穿山甲SDK 1 注册登录 广告对接的第三方的穿山甲 需要先在穿山甲注册好自己的账号链接 https www pangle cn 创建项目应用和代码位 xff0c 获取ID 2 导入sdk包 下载SDK ht
  • jdbc连接mysql8.x踩坑

    问题描述 使用jdbc连接数据库报错密码错误 xff0c 提示检查编码 Caused by java sql SQLException Access denied for user 39 root 39 64 39 localhost 39
  • 面向对象一"类与对象"的概念与特性

    面向对象程序设计 Object oriented programming OOP 一 类与对象 类 class 对一类具有相同 属性的对象的 抽象 类的定义包含了数据的形式以及 对数据的操作 对象 object 类的实例 每个对象都是其类中
  • 使用sql语句解析json字符串

    发现当前数据库对字符串的解析都是使用存储过程 xff0c 但是大部分公司不建议使用存过 xff0c 无奈之下写了如下的解析方式 xff1a 原始数据如下图 xff1a 经过数据分析发现 xff0c 每个键值对的分隔符是 34 34 xff0
  • nginx+tomcat负载均衡配置,实现流量切换

    Nginx负载均衡流量切换 实现方法有两种第一步 xff1a 在Servlet配置第二步 xff1a 配置nginx第三步 xff1a 动态配置开发 目前在用的方案是 xff1a 使用Nginx 43 Tomcat配置负载均衡 xff0c
  • 超分辨率相关资源大列表-2

    本文收藏自Github xff0c 仅供学习交流所用 Video Super Resolution A collection of state of the art video or single image super resolutio
  • 12-判断字符串是否以指定字符开头(数据验证)

    StringUtil java package com lh bean public class StringUtil 指定开头的字符串 private String startStr 被判断的字符串 private String str
  • repo init失败的几种解决方法

    试了几天 xff0c 终于解决了同步repo init失败的问题 谨此记录一下 希望对读者有用 由于每个人的情况都不一样 所以我这里会列举我尝试的所有方法 注意repo sync的问题不在本文讨论的范围内 环境说明 xff1a mac xf
  • 分享中国天气网的接口

    http m weather com cn data 101010100 html 注意 xff1a 1 101010100是北京的代号 xff0c 想查询你的城市 xff0c 请看更改城市代号 xff0c 网上百度一大堆 2 不要丢掉 h
  • mybatis的4种分页方式

    原文见 xff1a https blog csdn net chenbaige article details 70846902 今天我们就来进行基于mybatis和MySql进行分页功能的实现 常见的数据分页有哪几种实现 xff1f xf

随机推荐

  • pve模板制作cloud-init

    ubuntu 33 wget http cloud images ubuntu com releases focal release ubuntu 20 04 server cloudimg amd64 img 37 qm create 9
  • vnc viewer最新版,vnc viewer最新版工具有哪些

    现在 市面上有着各种各样的vnc viewer工具 xff0c 在日常工作中 xff0c 你会选择哪一款呢 xff1f 你所了解的vnc viewer最新版工具又有哪些呢 xff1f 今天就和大家聊聊我所了解的超级好用的几款vnc view
  • tableview为空的时候显示空视图

    参考链接 xff1a http stackoverflow com questions 3660313 present a default view instead of tableview if datasource is empty 关
  • QT中textBrowser每行显示不同颜色

    ui gt tbMessage gt append 34 lt font color 61 34 FF0000 34 gt 34 43 strMsg 43 34 lt font gt 34 加上颜色显示之后 xff0c n就没了 这里加上
  • source insight 4.x挂死(win10 21H1)

    问题 点击 34 Add and Remove Project Files 34 在 34 File Name 34 下面的输入框中输入任意内容 Source insight挂死 解决方案 设置 gt 时间和语言 gt 语言 xff0c 如
  • 内核调试小结

    文章目录 1 网络相关1 1 IP地址字符串转 be321 2 打印数值类型的IP地址 2 模块相关2 1 uboot给模块传递参数 1 网络相关 1 1 IP地址字符串转 be32 span class token keyword ext
  • Linux shell常用方法

    目录 1 文件操作1 1 查找文件并执行1 2 hexdump mtd的内容 1 文件操作 1 1 查找文件并执行 span class token function find span span class token builtin c
  • Ubuntu搭建dhcpv4服务器(Kea DHCP Server)

    1 安装kea dhcp服务器 1 1 apt安装 我还没有试过 span class token function sudo span span class token function apt span span class token
  • ubuntu IPv4 pppoe服务器搭建

    1 安装pppoe服务器 sudo apt get install pppoe 2 配置pppoe服务器 1 修改 etc ppp chap secrets xff0c 增加拨号用户名 xff0c 密码 xff1a 增加一行 xff1a 3
  • mac地址老化时间配置

    1 查看老化时间 cat proc sys net ipv4 neigh br0 base reachable time 2 配置老化时间 echo 300 gt proc sys net ipv4 neigh br0 base reach
  • ubuntu 18.04 编译openwrt 18.06

    sudo apt install y gitsudo apt install y makesudo apt install y gcc g 43 43 sudo apt install y libncurses5 devsudo apt i
  • vnc连接树莓派,4步轻松实现vnc连接树莓派

    在使用vnc时 xff0c 作为一个新手小白 xff0c 是不是很苦恼不会vnc连接树莓派 xff1f 没关系 xff0c 之前小编也不会 xff0c 今天看完我这篇文章 xff0c 你一定会有所收获的 xff0c 接下来 xff0c 让我
  • windows10+vs2019下 安装cuda10.1

    已有环境 xff1a windows10专业版 43 vs2019 准备工作 参考链接 xff1a xff08 前言部分 xff09 https www cnblogs com xiamuzi p 13470890 html 1 查看NVI
  • openwrt 18.06修改lan ip之后,自动跳转到新的ip

    feeds luci modules luci base luasrc view footer htm xff0c 强制修改为不需要回滚 xff0c 应该还有更好的方法 uci apply true 43 uci apply false f
  • 开源代码网站集合

    USB ModeSwitch xff1a http www draisberghof de usb modeswitch LWIP xff1a https savannah nongnu org projects lwip cJSON xf
  • adb.exe无法运行,提示0xc000007b错误

    运行android studio xff0c 提示adb server无法运行 xff0c 在命令行下进入C Users Administrator AppData Local Android Sdk platform tools xff0
  • 【Flutter入门到进阶】Dart进阶篇---进阶用法

    1 Dart对象扩展 1 1 extension 1 1 1 介绍 可以在不更改类或创建子类的情况下 xff0c 向类添加扩展功能的一种方式 灵活使用 extension 对基础类进行扩展 xff0c 对开发效率有显著提升 1 1 2 需求
  • 中国天气网API(最新接口)

    一 产品概述 SmartWeatherAPI 接口 简称 SWA 接口 是中国气象局面向 网络媒体 手机厂商 第三方气象服务机构等用户 xff0c 通过 web 方 式提供数据气象服务的官方载体 二 使用说明 该数据主要包括预警 实况 指数
  • MySQL事务:事务隔离

    对数据进行并发操作时 xff0c 事务可以确保数据的完整性 xff0c 在银行 证券交易等业务场景需要用到它 xff0c 本文将介绍MySQL事务是如何保证数据的一致性的 目录 事务特性事务启动与提交事务回滚 什么是事务隔离事务隔离级别 事
  • MySQL锁:全局锁、表级锁和行锁

    事务的实现离不开MySQL数据库的锁机制 xff0c 设计锁的目的也是为了处理并发访问问题 xff0c 本文简单介绍MySQL 里面的全局锁 表级锁和行锁三类锁 目录 全局锁表级锁表锁1 读锁实例2 写锁实例 元数据锁 行锁行锁简介行锁实例