深入理解 MySQL—锁、事务与并发控制

本文对 MySQL 数据库中有关锁、事务及并发控制的知识及其原理做了系统化的介绍和总结,希望帮助读者能更加深刻地理解 MySQL 中的锁和事务,从而在业务系统开发过程中可以更好地优化与数据库的交互。

1. MySQL 服务器逻辑架构


(图片来源MySQL官网)

每个连接都会在 MySQL 服务端产生一个线程(内部通过线程池管理线程),比如一个 select 语句进入,MySQL 首先会在查询缓存中查找是否缓存了这个 select 的结果集,如果没有则继续执行解析、优化、执行的过程;否则会之间从缓存中获取结果集。

2. MySQL锁

2.1、Shared and Exclusive Locks (共享锁与排他锁)

它们都是标准的行级锁

  • 共享锁(S) 共享锁也称为读锁,读锁允许多个连接可以同一时刻并发的读取同一资源,互不干扰;
  • 排他锁(X) 排他锁也称为写锁,一个写锁会阻塞其他的写锁或读锁,保证同一时刻只有一个连接可以写入数据,同时防止其他用户对这个数据的读写。

注意:所谓共享锁、排他锁其实均是锁机制本身的策略,通过这两种策略对锁做了区分。

2.2、Intention Locks(意向锁)

InnoDB 支持多粒度锁(锁粒度可分为行锁和表锁),允许行锁和表锁共存。例如,一个语句,例如 LOCK TABLES…WRITE 接受指定表上的独占锁。为了实现多粒度级别的锁定,InnoDB 使用了意图锁。

意向锁:表级别的锁。先提前声明一个意向,并获取表级别的意向锁(共享意向锁 IS 或排他意向锁 IX),如果获取成功,则稍后将要或正在(才被允许),对该表的某些行加锁(S或X)了。(除了 LOCK TABLES … WRITE,会锁住表中所有行,其他场景意向锁实际不锁住任何行)

举例来说:

SELECT … LOCK IN SHARE MODE,要获取IS锁;An intention shared lock (IS)

SELECT … FOR UPDATE ,要获取IX锁;An intention exclusive lock (IX) i

意向锁协议 在事务能够获取表中的行上的共享锁之前,它必须首先获取表上的IS锁或更强的锁。在事务能够获取表中的行上的独占锁之前,它必须首先获取表上的IX锁。

前文说了,意向锁实现的背景是多粒度锁的并存场景。如下兼容性的汇总:

意向锁仅表意向,是一种较弱的锁,意向锁之间兼容并行(IS、IX 之间关系兼容并行)。X与IS\IX互斥;S与IX互斥。可以体会到,意向锁是比X\S更弱的锁,存在一种预判的意义!先获取更弱的IX\IS锁,如果获取失败就不必要再花费跟大开销获取更强的X\S锁 … …

2.3、Record Locks (索引行锁)

record lock 是一个在索引行记录的锁。

比如,SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE,如果c1 上的索引被使用到。防止任何其他事务变动 c1 = 10 的行。

record lock 总是会在索引行上加锁。即使一个表并没有设置任何索引,这种时候 innoDB 会创建一个隐式的聚集索引(primary Key),然后在这个聚集索引上加锁。

当查询字段没有索引时,比如 update table set columnA=”A” where columnB=“B”.如果 columnB 字段不存在索引(或者不是组合索引前缀),这条语句会锁住所有记录也就是锁表。如果语句的执行能够执行一个 columnB 字段的索引,那么仅会锁住满足 where 的行(RecordLock)。

锁出现查看示例:

(使用 show engine innodb status 命令查看):

```范围查询RECORD LOCKS space id 58 page no 3 n bits 72 index `PRIMARY` of table `test`.`t` trx id 10078 lock_mode X locks rec but not gapRecord lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 0: len 4; hex 8000000a; asc     ;; 1: len 6; hex 00000000274f; asc     'O;; 2: len 7; hex b60000019d0110; asc        ;;

2.4、Gap locks(间隙锁)

Gap Locks: 锁定索引记录之间的间隙([2]),或者锁定一个索引记录之前的间隙([1]),或者锁定一个索引记录之后的间隙([3])。

示例:如图[1]、[2]、[3]部分。一般作用于我们的范围筛选查询> 、< 、between……

例如, SELECT userId FROM t1 WHERE userId BETWEEN 1 and 4 FOR UPDATE; 阻止其他事务将值3插入到列 userId 中。因为该范围内所有现有值之间的间隙都是锁定的。

  • 对于使用唯一索引来搜索唯一行的语句 select a from ,不产生间隙锁定。(不包含组合唯一索引,也就是说 gapLock 不作用于单列唯一索引)

例如,如果id列有唯一的索引,下面的语句只对id值为100的行使用索引记录锁,其他会话是否在前一个间隙中插入行并不重要:

“` SELECT * FROM t1 WHERE id = 100;

“`如果id**没有索引或具有非惟一索引,则语句将锁定前面的间隙**。

  • 间隙可以跨越单个索引值、多个索引值(如上图2,3),甚至是空的。
  • 间隙锁是性能和并发性之间权衡的一种折衷,用于某些特定的事务隔离级别,如RC级别(RC级别:REPEATABLE READ,我司为了减少死锁,关闭了gap锁,使用RR级别)。
  • 在重叠的间隙中(或者说重叠的行记录)中允许gap共存比如同一个 gap 中,允许一个事务持有 gap X-Lock(gap 写锁\排他锁),同时另一个事务在这个 gap 中持有(gap 写锁\排他锁)
CREATE TABLE `new_table` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `a` int(11) DEFAULT NULL,  `b` varchar(45) DEFAULT NULL,  PRIMARY KEY (`id`),  KEY `idx_new_table_a` (`a`),  KEY `idx_new_table_b` (`b`)) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8INSERT INTO `new_table` VALUES (1,1,'1'),(2,3,'2'),(3,5,'3'),(4,8,'4'),(5,11,'5'),(6,2,'6'),(7,2,'7'),(8,2,'8'),(9,4,'9'),(10,4,'10');######## 事务一 ########START TRANSACTION;SELECT * FROM new_table WHERE a between 5 and 8 FOR UPDATE;##暂不commit######## 事务二 ########SELECT * FROM new_table WHERE a = 4 FOR UPDATE;##顺利执行!因为gap锁可以共存;######## 事务三 ######## SELECT * FROM new_table WHERE b = 3 FOR UPDATE;##获取锁超时,失败。因为事务一的gap锁定了 b=3的数据。

2.5、next-key lock

next-key lock 是 record lock 与 gap lock 的组合。

比如 存在一个查询匹配 b=3 的行(b上有个非唯一索引),那么所谓 NextLock 就是:在b=3 的行加了 RecordLock 并且使用 GapLock 锁定了 b=3 之前(“之前”:索引排序)的所有行记录。

MySQL 查询时执行 行级锁策略,会对扫描过程中匹配的行进行加锁(X 或 S),也就是加Record Lock,同时会对这个记录之前的所有行加 GapLock 锁。假设一个索引包含值10、11、13和20。该索引可能的NexKey Lock锁定以下区间:

(negative infinity, 10](10, 11](11, 13](13, 20](20, positive infinity)

另外,值得一提的是 :innodb 中默认隔离级别(RR)下,next key Lock 自动开启。 (很好理解,因为 gap 作用于RR,如果是 RC,gapLock 不会生效,那么 next key lock 自然也不会)

锁出现查看示例: (使用 show engine innodb status 命令查看):

RECORD LOCKS space id 58 page no 3 n bits 72 index `PRIMARY` of table `test`.`t` trx id 10080 lock_mode XRecord lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0 0: len 8; hex 73757072656d756d; asc supremum;;Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 0: len 4; hex 8000000a; asc     ;; 1: len 6; hex 00000000274f; asc     'O;; 2: len 7; hex b60000019d0110; asc        ;;

2.6、Insert Intention Locks(插入意向锁)

一个 insert intention lock 是一种发生在 insert 插入语句时的 gap lock 间隙锁,锁定插入行之前的所有行。

这个锁以这样一种方式表明插入的意图,如果插入到同一索引间隙中的多个事务没有插入到该间隙中的相同位置,则它们不需要等待对方。

假设存在值为4和7的索引记录。尝试分别插入值为5和6的独立事务,在获得所插入行上的独占锁之前,每个事务使用 insert intention lock 锁定4和7之间的间隙,但不会阻塞彼此,因为这些行不冲突。

示例:

mysql> CREATE TABLE child (id int(11) NOT NULL, PRIMARY KEY(id)) ENGINE=InnoDB;mysql> INSERT INTO child (id) values (90),(102);##事务一mysql> START TRANSACTION;mysql> SELECT * FROM child WHERE id > 100 FOR UPDATE;+-----+| id  |+-----+| 102 |+-----+
##事务二mysql> START TRANSACTION;mysql> INSERT INTO child (id) VALUES (101);##失败,已被锁定mysql> SHOW ENGINE INNODB STATUSRECORD LOCKS space id 31 page no 3 n bits 72 index `PRIMARY` of table `test`.`child`trx id 8731 lock_mode X locks gap before rec insert intention waitingRecord lock, heap no 3 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 0: len 4; hex 80000066; asc    f;; 1: len 6; hex 000000002215; asc     " ;; 2: len 7; hex 9000000172011c; asc     r  ;;...

2.7、 AUTO-INC Locks

AUTO-INC 锁是一种特殊的表级锁,产生于这样的场景:事务插入(inserting into )到具有 AUTO_INCREMENT 列的表中。

在最简单的情况下,如果一个事务正在向表中插入值,那么其他任何事务必须等待向该表中插入它们自己的值,以便由第一个事务插入的行接收连续的主键值。

2.8 Predicate Locks for Spatial Indexes 空间索引的谓词锁

3. 事务

事务就是一组原子性的 sql,或者说一个独立的工作单元。事务就是说,要么 MySQL 引擎会全部执行这一组sql语句,要么全部都不执行(比如其中一条语句失败的话)。

  • 自动提交(AutoCommit,MySQL 默认)
show variables like "autocommit";set autocommit=0; //0表示AutoCommit关闭set autocommit=1; //1表示AutoCommit开启

MySQL 默认采用 AutoCommit 模式,也就是每个 sql 都是一个事务,并不需要显示的执行事务。如果 autoCommit 关闭,那么每个 sql 都默认开启一个事务,只有显式的执行“commit”后这个事务才会被提交。

  • 示事务 (START TRANSACTION…COMMIT)

比如,tim 要给 bill 转账100块钱:

1.检查 tim 的账户余额是否大于100块;

2.tim 的账户减少100块;

3.bill 的账户增加100块;

这三个操作就是一个事务,必须打包执行,要么全部成功, 要么全部不执行,其中任何一个操作的失败都会导致所有三个操作“不执行”——回滚。

CREATE DATABASE IF NOT EXISTS employees;USE employees;CREATE TABLE `employees`.`account` (  `id` BIGINT (11) NOT NULL AUTO_INCREMENT,  `p_name` VARCHAR (4),  `p_money` DECIMAL (10, 2) NOT NULL DEFAULT 0,  PRIMARY KEY (`id`)) ;INSERT INTO `employees`.`account` (`id`, `p_name`, `p_money`) VALUES ('1', 'tim', '200'); INSERT INTO `employees`.`account` (`id`, `p_name`, `p_money`) VALUES ('2', 'bill', '200'); START TRANSACTION;SELECT p_money FROM account WHERE p_name="tim";-- step1UPDATE account SET p_money=p_money-100 WHERE p_name="tim";-- step2UPDATE account SET p_money=p_money+100 WHERE p_name="bill";-- step3COMMIT;

一个良好的事务系统,必须满足ACID特点:

3.1、事务的ACID:

  • A:atomiciy 原子性:一个事务必须保证其中的操作要么全部执行,要么全部回滚,不可能存在只执行了一部分这种情况出现。
  • C:consistency 一致性:数据必须保证从一种一致性的状态转换为另一种一致性状态。 比如上一个事务中执行了第二步时系统崩溃了,数据也不会出现 bill 的账户少了100块,但是 tim 的账户没变的情况。要么维持原装(全部回滚),要么 bill 少了100块同时 tim 多了100块,只有这两种一致性状态的。
  • I:isolation 隔离性:在一个事务未执行完毕时,通常会保证其他 Session 无法看到这个事务的执行结果。
  • D:durability 持久性:事务一旦 commit,则数据就会保存下来,即使提交完之后系统崩溃,数据也不会丢失。

4. 隔离级别

查看系统隔离级别:select @@global.tx_isolation;查看当前会话隔离级别select @@tx_isolation;设置当前会话隔离级别SET session TRANSACTION ISOLATION LEVEL serializable;设置全局系统隔离级别SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

4.1、 READ UNCOMMITTED (未提交读,可脏读)

事务中的修改,即使没有提交,对其他会话也是可见的。可以读取未提交的数据——脏读。脏读会导致很多问题,一般不适用这个隔离级别。实例:

-- ------------------------- read-uncommitted实例 -------------------------------- 设置全局系统隔离级别SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;-- Session ASTART TRANSACTION;SELECT * FROM USER;UPDATE USER SET NAME="READ UNCOMMITTED";-- commit;-- Session BSELECT * FROM USER;//SessionB Console 可以看到Session A未提交的事物处理,在另一个Session 中也看到了,这就是所谓的脏读id    name2    READ UNCOMMITTED34    READ UNCOMMITTED

4.2、READ COMMITTED (提交读或不可重复读,幻读)

一般数据库都默认使用这个隔离级别(MySQL 不是), 这个隔离级别保证了一个事务如果没有完全成功(commit 执行完),事务中的操作对其他会话是不可见的。

-- ------------------------- read-cmmitted实例 -------------------------------- 设置全局系统隔离级别SET GLOBAL TRANSACTION ISOLATION LEVEL READ  COMMITTED;-- Session ASTART TRANSACTION;SELECT * FROM USER;UPDATE USER SET NAME="READ COMMITTED";-- COMMIT;-- Session BSELECT * FROM USER;//Console OUTPUT:id    name2    READ UNCOMMITTED34    READ UNCOMMITTED----------------------------------------------------- 当 Session  A执行了commit,Session B得到如下结果:id    name2    READ COMMITTED34    READ COMMITTED

也就验证了 read committed 级别在事物未完成 commit 操作之前修改的数据对其他 Session 不可见,执行了 commit 之后才会对其他 Session 可见。我们可以看到 Session B 两次查询得到了不同的数据。

read committed 隔离级别解决了脏读的问题,但是会对其他 Session 产生两次不一致的读取结果(因为另一个 Session 执行了事务,一致性变化)。

4.3、 REPEATABLE READ (可重复读)

一个事务中多次执行统一读 SQL,返回结果一样。这个隔离级别解决了脏读的问题,幻读问题。这里指的是 innodb 的 rr 级别,innodb 中使用 next-key 锁对”当前读”进行加锁,锁住行以及可能产生幻读的插入位置,阻止新的数据插入产生幻行。下文中详细分析。具体请参考 MySQL 手册:

https://dev.mysql.com/doc/refman/5.7/en/innodb-storage-engine.html

4.4、 SERIALIZABLE (可串行化)

最强的隔离级别,通过给事务中每次读取的行加锁,写加写锁,保证不产生幻读问题,但是会导致大量超时以及锁争用问题。

5. 并发控制 与 MVCC

MVCC (multiple-version-concurrency-control)

它是个行级锁的变种, 在普通读情况下避免了加锁操作,因此开销更低。虽然实现不同,但通常都是实现非阻塞读,对于写操作只锁定必要的行。

  • 一致性读 (就是读取快照)select * from table ….
  • 当前读(就是读取实际的持久化的数据)特殊的读操作,插入/更新/删除操作,属于当前读,处理的都是当前的数据,需要加锁。select * from table where ? lock in share mode; select * from table where ? for update; insert; update ; delete;

注意:select …… from where…… (没有额外加锁后缀)使用MVCC,保证了读快照(MySQL 称为 consistent read),所谓一致性读或者读快照就是读取当前事务开始之前的数据快照,在这个事务开始之后的更新不会被读到。详细情况下文 select 的详述。

对于加锁读 SELECT with FOR UPDATE (排他锁) or LOCK IN SHARE MODE (享锁)、 update、delete语句,要考虑是否是唯一索引的等值查询。

INNODB 的 MVCC 通常是通过在每行数据后边保存两个隐藏的列来实现(其实是三列,第三列是用于事务回滚,此处略去),一个保存了行的创建版本号,另一个保存了行的更新版本号(上一次被更新数据的版本号) 这个版本号是每个事务的版本号,递增的。这样保证了 innodb 对读操作不需要加锁也能保证正确读取数据。

5.1、MVCC select无锁操作 与 维护版本号

下边在 MySQL 默认的 Repeatable Read 隔离级别下,具体看看 MVCC 操作:

  • Select(快照读,所谓读快照就是读取当前事务之前的数据。):a.InnoDB 只 select 查找版本号早于当前版本号的数据行,这样保证了读取的数据要么是在这个事务开始之前就已经 commit 了的(早于当前版本号),要么是在这个事务自身中执行创建操作的数据(等于当前版本号)。b.查找行的更新版本号要么未定义,要么大于当前的版本号(为了保证事务可以读到老数据),这样保证了事务读取到在当前事务开始之后未被更新的数据。注意:这里的 select 不能有 for update、lock in share 语句。总之要只返回满足以下条件的行数据,达到了快照读的效果:
(行创建版本号< =当前版本号 && (行更新版本号==null or 行更新版本号>当前版本号 ) )
  • InsertInnoDB为这个事务中新插入的行,保存当前事务版本号的行作为行的行创建版本号。
  • Delete InnoDB 为每一个删除的行保存当前事务版本号,作为行的删除标记。
  • Update将存在两条数据,保持当前版本号作为更新后的数据的新增版本号,同时保存当前版本号作为老数据行的更新版本号。
当前版本号—写—>新数据行创建版本号 && 当前版本号—写—>老数据更新版本号();

5.2、脏读 vs 幻读 vs 不可重复读

脏读:一事务未提交的中间状态的更新数据 被其他会话读取到。

当一个事务正在访问数据,并且对数据进行了修改, 而这种修改还没有 提交到数据库中(commit 未执行), 这时,另外会话也访问这个数据,因为这个数据是还没有提交, 那么另外一个会话读到的这个数据是脏数据,依据脏数据所做的操作也可能是不正确的。

不可重复读:简单来说就是在一个事务中读取的数据可能产生变化,ReadCommitted 也称为不可重复读。

在同一事务中,多次读取同一数据返回的结果有所不同。换句话说就是,后续读取可以读到另一会话事务已提交的更新数据。相反,“可重复读”在同一事务中多次读取数据时,能够保证所读数据一样, 也就是,后续读取不能读到另一会话事务已提交的更新数据。

幻读:会话T1事务中执行一次查询,然后会话T2新插入一行记录,这行记录恰好可以满足T1所使用的查询的条件。然后T1又使用相同 的查询再次对表进行检索,但是此时却看到了事务T2刚才插入的新行。这个新行就称为“幻像”,因为对T1来说这一行就像突然 出现的一样。innoDB 的 RR 级别无法做到完全避免幻读,下文详细分析。

5.3、 如何保证 rr 级别绝对不产生幻读?

在使用的 select …where 语句中加入 for update (排他锁) 或者 lock in share mode (共享锁)语句来实现。其实就是锁住了可能造成幻读的数据,阻止数据的写入操作。

其实是因为数据的写入操作(insert 、update)需要先获取写锁,由于可能产生幻读的部分,已经获取到了某种锁,所以要在另外一个会话中获取写锁的前提是当前会话中释放所有因加锁语句产生的锁。

5.4、 从另一个角度看锁:显式锁、隐式锁

隐式锁:我们上文说的锁都属于不需要额外语句加锁的隐式锁。

显示锁:

SELECT ... LOCK IN SHARE MODE(加共享锁);SELECT ... FOR UPDATE(加排他锁);

详情上文已经说过。

5.5、查看锁情况

通过如下 sql 可以查看等待锁的情况

select * from information_schema.innodb_trx where trx_state="lock wait";或show engine innodb status;

6、MySQL 死锁问题

死锁,就是产生了循环等待链条,我等待你的资源,你却等待我的资源,我们都相互等待,谁也不释放自己占有的资源,导致无线等待下去。比如:

//Session ASTART TRANSACTION;UPDATE account SET p_money=p_money-100 WHERE p_name="tim";UPDATE account SET p_money=p_money+100 WHERE p_name="bill";COMMIT;//Thread BSTART TRANSACTION;UPDATE account SET p_money=p_money+100 WHERE p_name="bill";UPDATE account SET p_money=p_money-100 WHERE p_name="tim";COMMIT;

当线程A执行到第一条语句UPDATE account SET p_money=p_money-100 WHERE p_name=”tim”;锁定了p_name=”tim” 的行数据;并且试图获取p_name=”bill” 的数据;

此时,恰好,线程B也执行到第一条语句:UPDATE account SET p_money=p_money+100 WHERE p_name=”bill”;锁定了 p_name=”bill” 的数据,同时试图获取 p_name=”tim” 的数据;

此时,两个线程就进入了死锁,谁也无法获取自己想要获取的资源,进入无线等待中,直到超时!

innodb_lock_wait_timeout  等待锁超时回滚事务:

直观方法是在两个事务相互等待时,当一个等待时间超过设置的某一阀值时,对其中一个事务进行回滚,另一个事务就能继续执行。

这种方法简单有效,在i nnodb 中,参数 innodb_lock_wait_timeout 用来设置超时时间。

wait-for graph 算法来主动进行死锁检测:innodb 还提供了 wait-for graph 算法来主动进行死锁检测,每当加锁请求无法立即满足需要并进入等待时,wait-for graph 算法都会被触发。

6.1、如何尽可能避免死锁

  • 以固定的顺序访问表和行。比如两个更新数据的事务,事务A 更新数据的顺序 为1,2;事务B更新数据的顺序为2,1。这样更可能会造成死锁;
  • 大事务拆小。大事务更倾向于死锁,如果业务允许,将大事务拆小;
  • 在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁概率;
  • 降低隔离级别。如果业务允许,将隔离级别调低也是较好的选择,比如将隔离级别从RR调整为RC,可以避免掉很多因为gap锁造成的死锁。(我司 MySQL 规范做法);
  • 为表添加合理的索引。可以看到如果不走索引将会为表的每一行记录添加上锁,死锁的概率大大增大。

本文转载自“vivo 互联网技术”

Image placeholder
卫沧澜
未设置
  42人点赞

没有讨论,发表一下自己的看法吧

推荐文章
Java并发编程,深入理解ReentrantLock

ReentrantLock简介ReentrantLock重入锁, 是实现Lock接口的一个类 ,也是在实际编程中使用频率很高的一个锁,支持重入性,表示能够对共享资源能够重复加锁,即当前线程获取该锁再次

【Golang+MySQL】记一次 MySQL 数据库迁移(一)

【Golang+mysql】记一次mysql数据库迁移(一)文章地址:https://github.com/stayfoo/stayfoo-hub一、准备目标: 腾讯云CVM自建mysql数据迁移到腾

老司机带你深入理解 Laravel 之 Facade

前言 时间真的过的很快啊,今天都2019年12月2号了,准确的说,写这篇博客的时间是晚上21点40分,刚从公司加班回来,洗完澡就坐下来写这篇文章了,不知不觉除这篇博客外,我已经写了11篇了,要讲的东西

阿里大佬带你,深入理解线程池底层原理

为什么要使用线程池在实际使用中,线程是很占用系统资源的,如果对线程管理不善很容易导致系统问题。因此,在大多数并发框架中都会使用线程池来管理线程,使用线程池管理线程主要有如下好处:(1)降低资源消耗。通

深入理解JVM - 内存溢出实战

Java堆溢出Java堆用于存储对象实例,只要不断地创建对象,当对象数量到达最大堆的容量限制后就会产生内存溢出异常。最常见的内存溢出就是存在大的容器,而没法回收,比如:Map,List等。出现下面信息

聊一聊 MySQL 中的事务及其实现原理

说到数据库,那就一定会聊到事务,事务也是面试中常问的问题,我们先来一个面试场景:面试官:"事务的四大特性是什么?" 我:"ACID,即原子性(Atomicity)、隔离性(Isolation)、持久性

MySQL 性能优化:8 种常见 SQL 错误用法!

1、LIMIT语句分页查询是最常用的场景之一,但也通常也是最容易出问题的地方。比如对于下面简单的语句,一般DBA想到的办法是在type,name,create_time字段上加组合索引。这样条件排序都

Oracle/云MySQL/MsSQL“大迁移”真相及最优方案

最近一段时间碰到一些数据迁移的项目,如:Oracle迁移到MySQL,MsSQL迁移到MySQL,云MySQL迁移到本地MySQL。对于这方面做了系统的整理。包括:迁移方案的选择、如何跳出迁移遇到的坑

一条SQL语句在MySQL中如何执行的

前两天发了一条SQL慢的原因有哪些,在那篇文章我没有说到优化器之类的,我觉得如果配合一条SQL是如何执行的,会更好,所以特地找了一篇。来源:JavaGuide  |作者:木木匠本篇文章会分析一个sql

mysql 进行update时,要更新的字段中有单引号或者双引号导致不能批量生成sql的问题

前言将数据从一张表迁移到另外一张表的过程中,通过mysql的concat方法批量生成sql时遇到了一个问题,即进行UPDATE更新操作时如果原表中的字段中包含单引号'或者双引号",那么就会生成不正确的

深入探究 RocketMQ 事务机制的实现流程,为什么它能做到发送消息零丢失?

1、解决消息丢失的第一个问题:订单系统推送消息领丢失既然我们已经明确了消息在基于MQ传输的过程中可能丢失的几个地方,那么我们接着就得一步一步考虑如何去解决各个环节丢失消息的问题,首先要解决的第一个问题

【搞定 Java 并发面试】面试最常问的 Java 并发基础常见面试题总结!

Java并发基础常见面试题总结 1.什么是线程和进程? 1.1.何为进程? 进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。

MySQL 中 JSON 字段的使用技巧

mysql5.7.8之后开始原生支持json.在类似mongodb这种nosql数据库中,json存储数据是非常自然的,在mysql中合理的使用json,能够带来极大的便利 Json字段的使用场景 在

Ubuntu18.04 安装 MySQL 以及设置远程访问

安装MySQL sudoapt-getinstallmysql-server sudoaptisntallmysql-client sudoaptinstalllibmysqlclient-dev

基础信息:MySQL 特性

MySQL数据库的优缺点: 关系型数据库管理系统(RDBMS):MySQL是一个典型的关系型数据库管理系统。 易用:MySQL很容易上手。只要你掌握一些简单的SQL知识,就可以构建SQL语句与My

基础信息:什么是 MySQL?

MySQL是一个开源的深受欢迎的关系型数据库管理系统(简称RDBMS)。目前排名第二,仅次于Oracle数据库。 MySQL可以免费下载,但是,还提供了几个付费版本,这些版本提供了附加功能。 顾名思义

MySQL 数据库操作:创建和查看数据库

数据库是数据的集合。MySQL允许我们高效地存储和检索数据库中的数据。在MySQL中,我们可以使用CREATEDATABASE语句创建数据库。但是,如果数据库已经存在,则会引发错误。为了避免该错误,我

MySQL 表结构生成 Markdown 文档 | 工具篇

背景 在实施软件工程的时候,当要将某一版本归档时,需要汇总的文档要求还是比较高的、各类文档齐全,包括项目架构、项目安装、接口等文档,而数据库表结构说明文档亦属于其一。记得很早之前想找一个可以导出MyS

MySQL 数据库操作:删除数据库

使用MySQL的DROPDATABASE命令可以很容易的删除一个数据库。数据库删除的同时,所属的数据表将一起被删除。如果删除的数据库不存在,则会引发错误。为了避免错误的发生,可以在DROPDATABA

MySQL 定时备份

1设置好crontab定时任务备份 #每天备份三次数据库 05,15,22***sh/data/script/alldatabase_back.sh&>/dev/null #每天2点备份 02***s

Laravel-Binlog 扩展(用于实时监听 MySQL 数据变更、数据同步等场景)

Laravel-Binlogv0.2.1 (该扩展当前用于我司测试环境实时同步Mysql数据变更到ElasticSearch,稳定性待测试!!哈哈哈)我司正式环境走的阿里云DTS数据订阅 基于Sw

MySQL 读后总结

一条SQL查询语句是如何执行的? Mysql基本架构示意图Mysql分为Server层和存储引擎层两部分 Server层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖MySQL的大多数核心服务

MySQL 优化笔记

优化方向 SQL优化 sql优化分析 索引优化 优化数据库对象 优化表的数据类型 表拆分(水平、垂直) 反范式 使用中间表 优化mysqlserver mysql内存管理优化 log机制及优化

MySQL 优化笔记

优化方向 SQL优化 sql优化分析 索引优化 优化数据库对象 优化表的数据类型 表拆分(水平、垂直) 反范式 使用中间表 优化mysqlserver mysql内存管理优化 log机制及优化

pymysql fetchone () , fetchall () , fetchmany ()

最近在用python操作mysql数据库时,碰到了下面这两个函数,标记一下: 1.定义 1.1fetchone(): 返回单个的元组,也就是一条记录(row),如果没有结果则返回None 1.2fet