MySQL存储引擎、事务日志并发访问以及隔离级别

2018-10-20  本文已影响0人  Net夜风

MySQL存储引擎

1. InnoDB存储引擎

InnoDB存储引擎,把数据存储在一个文件中,是个黑盒,根varnish是一样,varnish中的数据缓存都存储在一个文件中,但其内部完全有自组织有序的结果从外部看来就是一个文件,内部可以有自己的元数据,数据是构建在文件系统之上的文件系统;而InnoDB也是这样,默认情况下可以将n张表放在一个表空间里,在外部看来就是一个表,其内部存放了n张表甚至存放了n张表的索引;不过把n张表的索引放在同一表中很难实现高级功能;比如像单表导入导出等;因此,这就是为什么在安装MariaDB时,都要求使用innodb_file_per_table这表示每张表使用一个表空间;

InnoDB的表空间为了能跨文件系统(分区),InnoDB的表空间背后所对应的文件 可以不止一个,而且还可以自动增长;表空间刚创建时,就占用固定大小的空间,如果再许愿空间时,就又占用固定大小的空间,用不用都占用;可理解为是基于步进的方式进行划分;InnoDB将所有的表和索引放在一个表空间中;

如果所有表和数据都存储在一个表空间中时,表空间文件是存储在datadir定义的目录中的;
如果每张表单独存储在一个表空间中,则表空间文件是放置在数据库目录下,而不是数据目录下;例如有一个数据库叫mydb就相当于在数据库目录下创建一个mydb的目录而已;
当然数据库目录有可能在数据目录下的子目录;

MariaDB [(none)]> SHOW ENGINES\G;
...
*************************** 6. row ***************************
      Engine: InnoDB
     Support: DEFAULT
     Comment: Percona-XtraDB, Supports transactions, row-level locking, and foreign keys
Transactions: YES
          XA: YES
  Savepoints: YES

注意:级别越高事务发生冲突性越小,事务安全性越高但并发性能就越低;

注:MVCC,multi version concurrency control:多版本并发访问控制,它就是类似于lvm的快照功能;也就意味着,当启动n个事务时,每一个事务,都针对于mysql当中的InnoDB存储引擎现有数据做一个快照; 每一个快照,通过快照过去访问时间点是一致的,所以现在要启动一个事务,就对InnoDB数据集做个快照,就在快照基础上做操作;因此有50个事务为了彼此间不受影响,每个事务启动一次做一个快照。
但是,这病不意味着就没有冲突,想象以下,如果第一个快照和第二个也快照了,两个操作同一个数据集,一个删了一行,而第二个事务把这个行改了,此时就会出现问题,所以,必须有隔离机制来实现所谓的事务隔离;
而事务隔离中最核心组件就是锁;这么一来事务也没法并发了,既然锁了,看上去事务同时启动,但是还得等待一个个完成;所以,隔离级别至关重要了;


另:percona公司对mysql做了二次开发,服务器版本为percona-server,把InnoDB改进为XtraDB存储引擎,mariadb使用了XtraDB引擎,但是名称依然叫InnoDB

总结InnoDB引擎的特性:

SHOW ENGINE INNODB STATUS;

2. MyISAM存储引擎

MyISAM内部的复杂机制很少,特别适应于读多写少的应用;但是,mysql自己的表,内部的元数据的库还是使用的MyISAM存储引擎;
MyISAM存储引擎最大特性是支持全文索引,全文索引指的是全文中的每一个关键字都可以被搜索;
MyISAM在崩溃后无法安全恢复,有可能会导致某些数据丢失,比如要插入一行数据,刚插入一般数据库崩溃,只能把刚插入的半行删了,保证数据是一致性的;解决办法是使用MyISAM表修复工具,会对全表扫描,一行行扫描,看哪一行中的数据不是完整的给它删了,所以这就是崩溃后的恢复,如果表要大的话,恢复时间会非常长;索引说可以接受较长时间的修复操作才能使用MyISAM;这个较长时间还是指的较小的表,如果表答可能修复一天都有可能。
MariaDB虽然支持MyISAM存储引擎但是,默认对于MyISAM而言使用的是Aria存储引擎,其实就是MyISAM的增强版,支持崩溃后的安全恢复;
MyISAM存储引擎的文件,表和索引是独立存放的;索引可看出来使用的是非聚集索引;因此,每一个索引的叶子节点,都是个指针,指向了真正数据所在的位置;这就类似于书中的目录和后面正文的关系;

对于InnoDB,每张表使用两个文件一个是用来存储数据和索引的.ibd文件,一个是用来存储表格式的.frm格式的文件;而对于MyISAM,每张表有三个文件且都放在数据库目录下而不是datadir=指定的目录下,也就是说的datadir指定的目录下的子目录里;

MariaDB [(none)]> SHOW ENGINES\G;
*************************** 5. row ***************************
      Engine: MyISAM
     Support: YES
     Comment: MyISAM storage engine
Transactions: NO
          XA: NO
  Savepoints: NO
总结MyISAM存储引擎特性:
行格式:

{DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT}

态还是固定行取决于表中字段的类型,例如字段的类型是varchar类型长度是可变的,如果某一字段使用varchar类型,每行可以不同的长度;行长度不一样管理很麻烦,性能比较低;行的长度一样只需根据距离来判断下一行在什么位置就可以了;

以上InnoDB和MyISAM是mysql中最为经典的两种存储引擎;

MariaDB [hellodb]> SHOW ENGINES;  #查看所有支持的存储引擎
+--------------------+---------+----------------------------------------------------------------------------+--------------+------+------------+
| Engine             | Support | Comment                                                                    | Transactions | XA   | Savepoints |
+--------------------+---------+----------------------------------------------------------------------------+--------------+------+------------+
| MEMORY             | YES     | Hash based, stored in memory, useful for temporary tables                  | NO           | NO   | NO         |
| MRG_MYISAM         | YES     | Collection of identical MyISAM tables                                      | NO           | NO   | NO         |
| CSV                | YES     | CSV storage engine                                                         | NO           | NO   | NO         |
| BLACKHOLE          | YES     | /dev/null storage engine (anything you write to it disappears)             | NO           | NO   | NO         |
| MyISAM             | YES     | MyISAM storage engine                                                      | NO           | NO   | NO         |
| InnoDB             | DEFAULT | Percona-XtraDB, Supports transactions, row-level locking, and foreign keys | YES          | YES  | YES        |
| ARCHIVE            | YES     | Archive storage engine                                                     | NO           | NO   | NO         |
| FEDERATED          | YES     | FederatedX pluggable storage engine                                        | 


MariaDB [hellodb]> SHOW GLOBAL VARIABLES LIKE '%STORAGE%';  #查看默认存储引擎
+------------------------+--------+
| Variable_name          | Value  |
+------------------------+--------+
| default_storage_engine | InnoDB |
| storage_engine         | InnoDB |
+------------------------+--------+

3. 其他存储引擎

4. MariaDB支持的其他存储引擎

MySQL事务

并发控制:

锁是mysql实现并发访问控制的重要组件;


示例:
    MariaDB [(none)]> CREATE DATABASE testdb; #创建数据库
    Query OK, 1 row affected (0.01 sec)
    
    MariaDB [(none)]> USE testdb
    Database changed
    MariaDB [testdb]> CREATE TABLE tbl;  #创建表
    ERROR 1113 (42000): A table must have at least 1 column
    MariaDB [testdb]> CREATE TABLE tbl (id INT NOT NULL ,name VARCHAR(50));  #插入数据
    Query OK, 0 rows affected (0.05 sec)
    
    MariaDB [testdb]> INSERT INTO tbl (id,name) VALUE (1,'TOM');
    Query OK, 1 row affected (0.01 sec)
    
    MariaDB [testdb]> SELECT * FROM tbl; 
    +----+------+
    | id | name |
    +----+------+
    |  1 | TOM  |
    +----+------+
    1 row in set (0.01 sec)
    
    MariaDB [testdb]> LOCK TABLE tbl READ; #施加读锁
    Query OK, 0 rows affected (0.00 sec)

    另外启动一个线程:
    MariaDB [(none)]> use testdb;
    Reading table information for completion of table and column names
    You can turn off this feature to get a quicker startup with -A
    
    Database changed
    MariaDB [testdb]> SELECT * FROM tbl;  
    +----+------+
    | id | name |
    +----+------+
    |  1 | TOM  |
    +----+------+
    1 row in set (0.00 sec)
    
    MariaDB [testdb]> INSERT INTO tbl (id,name) VALUE (2,‘JERRY’);  #插入数据被阻塞
    
    线程1释放锁:
    MariaDB [testdb]> UNLOCK TABLES;
    Query OK, 0 rows affected (0.00 sec)
    线程2插入数据成功:
    MariaDB [testdb]> INSERT INTO tbl (id,name) VALUE (2,'JERRY');
    Query OK, 1 row affected (0.01 sec)
事务日志:

事务日志就是mysql数据文件之外的另外一个存储区域,这个存储区域带来的作用是:当一个事务型存储引擎在运行过程中,需要启动一个事务并完成数据修改时,所有的修改操作(由多个sql语句组成),每一次的操作所涉及到的数据修改,这个修改的操作要转换成底层存储引擎所支持的相关操作的操作过程,它会把每一次的sql语句所涉及的操作步骤,具体的过程记录在事务日志文件中。
注意,事务日志记录的是每一步的具体操作;例如,插入一行的数据是什么、插入什么位置、什么时候插入得等都记录下来;再例如,如果是修改几行,先修改哪行后修改哪行、几点开始修改、几点结束等等都记录下来;而且这个日志要能够重现操作就叫做事务日志。
一个事务型存储引擎它的操作借助于事务日志来保证其对应的事务特性;所以,任何事务型存储引擎的相关操作,默认不会直接写在数据库文件上,而是先写在事务日志中,并且事务日志为保证足够可靠,基本上很少在内存中缓冲,写完建基本比较差,都会先写在内存上,然后等过一会再同步到磁盘上;事务日志也有这段缓冲区,但这个缓冲区不能太大时间也不能太久,因为如果允许缓存5秒钟,系统崩溃最大会丢失5秒的数据,所以建议这个时间要足够短,一般为1秒钟同步到磁盘上一次;但是,同步越频繁性能就越差,数据可靠性就越高。
事务日志的每一步在记录时,还会把修改之前的原始数据内容也记录下来,这是为了支持undo和redo机制而记录的;即当记录的是修改数据时会把又该的数据之前的数据记录下来。假如,操作进行到一半服务器崩溃了,把修改的操作日志撤销了即可,因为还没有同步到磁盘上;如为例如保证数据的稳定性,一个大事务中间有可能事务还没完成,已经在事务日志记录了30个,再记录事务日志会先把一部分信息往磁盘上同步,开始真正修改原始数据了,这时如果崩溃,则只能把已经同步到表中的数据撤销,这就是undo机制;
还有一种情况是,比如一个事务有60个sql语句都写完了且都记录在事务日志中了,但只有气筒30个同步到了磁盘上,如果此时崩溃,则此时数据是不一致的;因为有些事务已经提交,但是没有存储到磁盘上,这样就必须把事务日志中为完成的语句同步到磁盘上,这就是redo机制;
同步的要做提交,没能完成的要做回滚,这就是崩溃后恢复。
如果日志文件非常大,恰好写满了崩溃,下次启动mysql时,必须把里面的所有语句统统同步到磁盘才能正常启动,;如果事务日志文件大道2G,为了能够把2G的语句同步到磁盘上,有可能mysql服务器启动半小时,所以为了避免崩溃后启动时间太长,把日志文件设置小一点;但是,有事会出现日志填满了,但是日志内容还没来的急同步到磁盘上,还有新的日志需要写进来,那么久在启动一个文件;也就是说日志文件一般启动2个或3个是轮转使用的,所谓轮转指的是第一个日志文件填满了就用第二个,同时把第一个日志文件同步到磁盘上,等第二个日志写满了就可以再使用第一个了,这样轮转使用,由多个事务日志文件组成的叫做事务日志组,日志组内至少应该有2个文件,但是多了同样不好。
事务日志文件和数据文件不应该放在同一磁盘上,因为会对磁盘写IO操作带来很大压力,影响其性能;分开存放比较理想,但是有些场景又要必须放在一起,例如基于逻辑卷操作时;
如果事务日志所在磁盘崩溃,则数据库数据无法保持一致;所以,要把事务日志磁盘做镜像;建议使用raid1;数据文件也很重要建议使用raid10;

注意:MyISAM存储引擎是不支持事务的,InnoDB支持事务,所以要想使用事务得确保使用的是InnoDB等支持事务的存储引擎;


示例:
     查看是否开启自动提交:
     MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE '%commit%';
    +-------------------------------------------+-------+
    | Variable_name                             | Value |
    +-------------------------------------------+-------+
    | aria_group_commit                         | none  |
    | aria_group_commit_interval                | 0     |
    | autocommit                                | ON    |
    | innodb_commit_concurrency                 | 0     |
    | innodb_flush_log_at_trx_commit            | 1     |
    | innodb_use_global_flush_log_at_trx_commit | ON    |
    +-------------------------------------------+-------+

    autocommit=ON:自动提交,把每一个执行的语句当做一个事务,执行语句就提交,因为每一次事务提交都会导致数据要从事务日志缓冲区写到事务日志,随后还要从事务日志写到数据文件;这很可能会影响性能,而且很多时候多个语句才是一个事务;
    因此可以使用set修改变量,关闭自动提交功能;
    MariaDB [(none)]> SET @@SESSION.autocommit=OFF;  #修改session级别的参数,关闭自动提交
    Query OK, 0 rows affected (0.00 sec)
    MariaDB [(none)]> SHOW VARIABLES LIKE 'autocommit';
    +---------------+-------+
    | Variable_name | Value |
    +---------------+-------+
    | autocommit    | OFF   |
    +---------------+-------+

    示例:
        手动启动事务:
        MariaDB [(none)]> START TRANSACTION;
        MariaDB [(none)]> use testdb;   
        
        Database changed
        MariaDB [testdb]> SELECT * FROM tbl;
        +----+-------+
        | id | name  |
        +----+-------+
        |  1 | TOM   |
        |  2 | JERRY |
        +----+-------+
        2 rows in set (0.00 sec)
        
        MariaDB [testdb]> INSERT INTO tbl (id,name) VALUE (3,'LUCY');
        Query OK, 1 row affected (0.01 sec)
        
        MariaDB [testdb]> UPDATE tbl SET name='guojing' WHERE id=1;
        Query OK, 1 row affected (0.00 sec)
        Rows matched: 1  Changed: 1  Warnings: 0
        
        MariaDB [testdb]> SELECT * FROM tbl;
        +----+---------+
        | id | name    |
        +----+---------+
        |  1 | guojing |
        |  2 | JERRY   |
        |  3 | LUCY    |
        +----+---------+
        3 rows in set (0.00 sec)
        
        MariaDB [testdb]> ROLLBACK; #手动回滚,结束事务
        Query OK, 0 rows affected (0.01 sec)
        
        MariaDB [testdb]> SELECT * FROM tbl;
        +----+-------+
        | id | name  |
        +----+-------+
        |  1 | TOM   |
        |  2 | JERRY |
        +----+-------+
        2 rows in set (0.00 sec)

    示例2:
        MariaDB [testdb]> START TRANSACTION;
        Query OK, 0 rows affected (0.00 sec)
        
        MariaDB [testdb]> INSERT INTO tbl VALUE (3,'LUCK'),(4,'MURNN');
        Query OK, 2 rows affected (0.02 sec)
        Records: 2  Duplicates: 0  Warnings: 0
        
        MariaDB [testdb]> SELECT * FROM tbl;
        +----+-------+
        | id | name  |
        +----+-------+
        |  1 | TOM   |
        |  2 | JERRY |
        |  3 | LUCK  |
        |  4 | MURNN |
        +----+-------+
        4 rows in set (0.00 sec)
        
        MariaDB [testdb]> SAVEPOINT first;   #做时间点,名称为first
        Query OK, 0 rows affected (0.00 sec)
        
        MariaDB [testdb]> UPDATE tbl SET name='guojing' WHERE id=1;
        Query OK, 1 row affected (0.00 sec)
        Rows matched: 1  Changed: 1  Warnings: 0
        
        MariaDB [testdb]> SAVEPOINT second;  #做第二个时间保存点,名称为second
        Query OK, 0 rows affected (0.00 sec)            
        
        MariaDB [testdb]> INSERT INTO tbl VALUE (5,'HAHA');
        Query OK, 1 row affected (0.00 sec)
        
        MariaDB [testdb]> SELECT * FROM tbl;
        +----+---------+
        | id | name    |
        +----+---------+
        |  1 | guojing |
        |  2 | JERRY   |
        |  3 | LUCK    |
        |  4 | MURNN   |
        |  5 | HAHA    |
        +----+---------+
        5 rows in set (0.00 sec)

        MariaDB [testdb]> ROLLBACK TO second;  #回滚到第二个保存点
        Query OK, 0 rows affected (0.00 sec)
        
        MariaDB [testdb]> SELECT * FROM tbl;
        +----+---------+
        | id | name    |
        +----+---------+
        |  1 | guojing |
        |  2 | JERRY   |
        |  3 | LUCK    |
        |  4 | MURNN   |
        +----+---------+
        4 rows in set (0.00 sec)
        
        MariaDB [testdb]> ROLLBACK TO first;  #回滚到第一个保存点
        Query OK, 0 rows affected (0.00 sec)
        
        MariaDB [testdb]> SELECT * FROM tbl;
        +----+-------+
        | id | name  |
        +----+-------+
        |  1 | TOM   |
        |  2 | JERRY |
        |  3 | LUCK  |
        |  4 | MURNN |
        +----+-------+
        4 rows in set (0.00 sec)
        
        MariaDB [testdb]> COMMIT; 手动提交,结束事务
        Query OK, 0 rows affected (0.01 sec)

建议:手动显示请求和提交事务,不要使用自动提交功能

事务的隔离级别:

由低到高,分为4个级别:

MySQL是通过MVCC机制来实现事务隔离级别控制的;为什么启动2个事务,基于PREPEATABLE-READ 隔离级别修改数据但还能看到之前的数据,就是因为自己启动了一个快照,而快照功能的创建,删除等等都是由事务功能mysql服务器自动在服务器级别进行管理的

    示例:两个线程,分别验证各个事务隔离级别的效果
    (1)演示读未提交,两个线程控制台均设置事务隔离级别为读未提交,并关闭事务自动提交功能     
    MariaDB [testdb]> SET @@SESSION.tx_isolation='READ-UNCOMMITTED';
    Query OK, 0 rows affected (0.00 sec)
    
    MariaDB [(none)]> SET @@SESSION.autocommit=OFF;
    Query OK, 0 rows affected (0.00 sec)
    
    两边同时启动事务:
    MariaDB [(none)]> START TRANSACTION;
    
    线程1查看:
    MariaDB [testdb]> SELECT * FROM tbl;
    +----+-------+
    | id | name  |
    +----+-------+
    |  1 | TOM   |
    |  2 | JERRY |
    |  3 | LUCK  |
    |  4 | MURNN |
    +----+-------+
    4 rows in set (0.00 sec)
    
    线程2插入数据:
    MariaDB [testdb]> INSERT INTO tbl VALUE (5,'haha');
    Query OK, 1 row affected (0.00 sec)
    
    线程1再查看:
    MariaDB [testdb]> SELECT * FROM tbl;
    +----+-------+
    | id | name  |
    +----+-------+
    |  1 | TOM   |
    |  2 | JERRY |
    |  3 | LUCK  |
    |  4 | MURNN |
    |  5 | haha  |
    +----+-------+
    5 rows in set (0.00 sec)
    
    线程2:回滚,结束事务:
    MariaDB [testdb]> ROLLBACK;
    Query OK, 0 rows affected (0.01 sec)
    
    线程1再查看:
    MariaDB [testdb]> SELECT * FROM tbl;
    +----+-------+
    | id | name  |
    +----+-------+
    |  1 | TOM   |
    |  2 | JERRY |
    |  3 | LUCK  |
    |  4 | MURNN |
    +----+-------+
    4 rows in set (0.00 sec)
    MariaDB [testdb]> COMMIT;   #提交结束事务
    Query OK, 0 rows affected (0.00 sec)

示例:演示读提交
    两个线程都改为读提交,并启动事务:
    MariaDB [testdb]> SET @@SESSION.tx_isolation='READ-COMMITTED';
    MariaDB [testdb]> START TRANSACTION;
    
    线程1启动查询:
    MariaDB [testdb]> SELECT * FROM tbl;
    +----+-------+
    | id | name  |
    +----+-------+
    |  1 | TOM   |
    |  2 | JERRY |
    |  3 | LUCK  |
    |  4 | MURNN |
    +----+-------+
    4 rows in set (0.01 sec)
    
    线程2插入数据未提交:
    MariaDB [testdb]> INSERT INTO tbl VALUE (5,'haha');
    Query OK, 1 row affected (0.02 sec)
    
    线程1再查看数据未变化:
    MariaDB [testdb]> SELECT * FROM tbl;
    +----+-------+
    | id | name  |
    +----+-------+
    |  1 | TOM   |
    |  2 | JERRY |
    |  3 | LUCK  |
    |  4 | MURNN |
    +----+-------+
    4 rows in set (0.00 sec)
    
    线程2提交事务:
    MariaDB [testdb]> COMMIT;
    Query OK, 0 rows affected (0.02 sec)
    
    线程1再查看,数据发生变化
    MariaDB [testdb]> SELECT * FROM tbl;
    +----+-------+
    | id | name  |
    +----+-------+
    |  1 | TOM   |
    |  2 | JERRY |
    |  3 | LUCK  |
    |  4 | MURNN |
    |  5 | haha  |
    +----+-------+
    5 rows in set (0.00 sec)
    MariaDB [testdb]> COMMIT;  #提交事务

示例:演示幻读,可重复读
    两个线程都修改事务级别为可重复读,并启动事务:
    mysql> SHOW GLOBAL VARIABLES LIKE '%iso%';
    +-----------------------+-----------------+
    | Variable_name         | Value           |
    +-----------------------+-----------------+
    | transaction_isolation | REPEATABLE-READ |
    +-----------------------+-----------------+
    1 row in set (0.00 sec)
    mysql> SET @@SESSION.autocommit=OFF;
    Query OK, 0 rows affected (0.02 sec)
    
    线程1查看:
    mysql> SELECT * FROM tbl;
    +----+-------+
    | id | name  |
    +----+-------+
    |  1 | TOM   |
    |  2 | JERRY |
    |  3 | LUCK  |
    |  4 | HAHA  |
    +----+-------+
    4 rows in set (0.00 sec)
    
    线程2删除1行(未提交):
    mysql> DELETE FROM tbl WHERE id=2;
    Query OK, 1 row affected (0.01 sec)
    
    mysql> SELECT * FROM tbl;
    +----+------+
    | id | name |
    +----+------+
    |  1 | TOM  |
    |  3 | LUCK |
    |  4 | HAHA |
    +----+------+
    3 rows in set (0.00 sec)
    
    线程1查看,未发生变化:
    mysql> SELECT * FROM tbl;
    +----+-------+
    | id | name  |
    +----+-------+
    |  1 | TOM   |
    |  2 | JERRY |
    |  3 | LUCK  |
    |  4 | HAHA  |
    +----+-------+
    4 rows in set (0.00 sec)
    
    线程2提交:
    mysql> COMMIT;
    Query OK, 0 rows affected (0.07 sec)
    
    线程1再查看,扔然未变化:
    mysql> SELECT * FROM tbl;
    +----+-------+
    | id | name  |
    +----+-------+
    |  1 | TOM   |
    |  2 | JERRY |
    |  3 | LUCK  |
    |  4 | HAHA  |
    +----+-------+
    4 rows in set (0.00 sec)
    
    线程1提交事务后再查看数据发生变化:
    mysql> COMMIT;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT * FROM tbl;
    +----+------+
    | id | name |
    +----+------+
    |  1 | TOM  |
    |  3 | LUCK |
    |  4 | HAHA |
    +----+------+
    3 rows in set (0.00 sec)

示例:演示可串行化
    2个线程都设置事务隔离级别可串行化:
    mysql> SET @@SESSION.transaction_isolation='SERIALIZABLE';
    线程1查看:
    mysql> SELECT * FROM tbl;
    +----+-------+
    | id | name  |
    +----+-------+
    |  1 | TOM   |
    |  3 | LUCK  |
    |  4 | HAHA  |
    |  2 | JERRY |
    +----+-------+
    4 rows in set (0.00 sec)
    
    线程2启动事务,并插入数据:
    mysql> START TRANSACTION;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> INSERT INTO tbl VALUE (5,'HUANG RONG');
    Query OK, 1 row affected (18.31 sec)
    
    线程1启动事务并查看,被阻塞:
    mysql> START TRANSACTION;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT * FROM tbl;
    线程2提交事务:
    mysql> COMMIT;
    Query OK, 0 rows affected (0.03 sec)
    
    线程1查看:
    mysql> SELECT * FROM tbl;
    ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
    mysql> SELECT * FROM tbl;
    +----+------------+
    | id | name       |
    +----+------------+
    |  1 | TOM        |
    |  3 | LUCK       |
    |  4 | HAHA       |
    |  2 | JERRY      |
    |  5 | HUANG RONG |
    +----+------------+
    5 rows in set (0.00 sec)
    mysql> commit;
    Query OK, 0 rows affected (0.00 sec)
上一篇下一篇

猜你喜欢

热点阅读