您的位置:首页 > 数据库 > MySQL

mysql 学习记录(十九)--Innodb表锁

2015-11-01 10:57 826 查看
一、理论:

1.事务及其acid属性:

a.原子性:事务对数据的修改要么全部执行,要么全部不执行。

b.一致性:在事务开始和完成时,数据必须保证一致状态。

c.隔离性:在事务处理的过程中对外是‘不可见’的。

d.持久性:事务完成之后,但对于数据的修改是永久性的。

2.并发处理的问题:

a.更新丢失

b.脏读:多个事务同时修改同一条记录

c.不可重复读:读过一次数据之后再读相同记录可能此条记录就会改变

d.幻读:一个事务按相同的条件查询之前检索过的数据但与原来执行的结果不同

3.事务隔离级别:

a.在读取数据前对其进行加锁

b.在某时间点生成‘快照’,可以提供数据库的多个版本,叫做‘数据多版本并发控制’

4.iso/ansi sql92定义的4个事务隔离级别:

a.未提交读

b.已提交读

c.可重复读

d.可序列化

5.innodb的行锁模式及加锁方法

a.共享锁:允许一个事务去读一行,阻止其他事务获得相同数据集的排他销

b.排他锁:允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁

6.事务可以如下加共享锁或者排他锁:

a.共享锁:select * from testTable where ... lock in share mode

b.排他锁:select * from testTable where ... for update

7.innodb行锁实现方式:

a.record lock:对索引项加锁

b.gap lock:对索引项之间的间隙加锁

c.next-key lock:对记录及间隙加锁、

8.分析锁冲突时,有时需要检查sql执行计划,以确认是否真正使用了索引。

9.表锁相关:

a.事务需要更新大部分或者全部数据

b.事务涉及多个表可能引起死锁,使得大量事务回滚

c.innodb表锁是'系统级别'锁

10.其它:

a.尽量使用较低的隔离级别

b.精心设计索引并尽可能使用索引访问数据,使锁更精确从而减少锁冲突的机会

c.选择合理的事务大小,小事务发生锁冲突的几率更小

d.给记录集显式加锁时,最好一次性请求足够级别的锁。这样可以避免死锁

e.不同的程序访问一组表时,应尽量约定以相同的顺序访问各表。对一个表而言,尽可能以固定的顺序存取表中的行

f.尽量用相等的条件访问数据,这样可以避免next-key锁对并发插入的影响

g.不要申请超过实际需要的锁级别,除非必须,查询时不要显式加锁

h.对于一些特定的事务,可以使用表锁来提高处理速度或者减少死锁发生的几率
二、实践:

1.
session_1:
mysql> use sakila;
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
mysql> show status like 'innodb_row_lock%';
+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| Innodb_row_lock_current_waits | 0     |
| Innodb_row_lock_time          | 30735 |
| Innodb_row_lock_time_avg      | 2561  |
| Innodb_row_lock_time_max      | 7558  |
| Innodb_row_lock_waits         | 12    |
+-------------------------------+-------+
5 rows in set (0.00 sec)

mysql> use sakila;
Database changed

mysql> select * from information_schema.innodb_locks \G;
Empty set (0.01 sec)

ERROR:
No query specified

mysql> create table innodb_monitor(a int) engine = innodb;
Query OK, 0 rows affected (0.04 sec)

mysql> show engine innodb status \G;
*************************** 1. row ***************************
Type: InnoDB
Name:
Status:
=====================================
151030 22:39:24 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 16 seconds
-----------------
BACKGROUND THREAD
-----------------
srv_master_thread loops: 110 1_second, 110 sleeps, 7 10_second, 42 background, 42 flush
srv_master_thread log flush and writes: 110
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 21, signal count 21
Mutex spin waits 15, rounds 450, OS waits 15
RW-shared spins 6, rounds 180, OS waits 6
RW-excl spins 0, rounds 0, OS waits 0
Spin rounds per wait: 30.00 mutex, 30.00 RW-shared, 0.00 RW-excl
------------
TRANSACTIONS
------------
Trx id counter 910
Purge done for trx's n:o < 904 undo n:o < 0
History list length 101
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0, not started
MySQL thread id 32, OS thread handle 0x7f292436c700, query id 704 localhost root
show engine innodb status
--------
FILE I/O
--------
I/O thread 0 state: waiting for i/o request (insert buffer thread)
I/O thread 1 state: waiting for i/o request (log thread)
I/O thread 2 state: waiting for i/o request (read thread)
I/O thread 3 state: waiting for i/o request (read thread)
I/O thread 4 state: waiting for i/o request (read thread)
I/O thread 5 state: waiting for i/o request (read thread)
I/O thread 6 state: waiting for i/o request (write thread)
I/O thread 7 state: waiting for i/o request (write thread)
I/O thread 8 state: waiting for i/o request (write thread)
I/O thread 9 state: waiting for i/o request (write thread)
Pending normal aio reads: 0 [0, 0, 0, 0] , aio writes: 0 [0, 0, 0, 0] ,
ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0
Pending flushes (fsync) log: 0; buffer pool: 0
574 OS file reads, 45 OS file writes, 30 OS fsyncs
0.00 reads/s, 0 avg bytes/read, 0.75 writes/s, 0.50 fsyncs/s
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 0, seg size 2, 0 merges
merged operations:
insert 0, delete mark 0, delete 0
discarded operations:
insert 0, delete mark 0, delete 0
Hash table size 553229, node heap has 1 buffer(s)
0.00 hash searches/s, 0.44 non-hash searches/s
---
LOG
---
Log sequence number 13464743
Log flushed up to   13464743
Last checkpoint at  13464743
0 pending log writes, 0 pending chkp writes
20 log i/o's done, 0.19 log i/o's/second
----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 274726912; in additional pool allocated 0
Dictionary memory allocated 176080
Buffer pool size   16383
Free buffers       15831
Database pages     551
Old database pages 221
Modified db pages  0
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 0, not young 0
0.00 youngs/s, 0.00 non-youngs/s
Pages read 543, created 8, written 31
0.00 reads/s, 0.25 creates/s, 0.62 writes/s
Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 551, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
--------------
ROW OPERATIONS
--------------
0 queries inside InnoDB, 0 queries in queue
1 read views open inside InnoDB
Main thread process no. 45085, id 139814181046016, state: waiting for server activity
Number of rows inserted 0, updated 0, deleted 0, read 23
0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 0.00 reads/s
----------------------------
END OF INNODB MONITOR OUTPUT
============================

1 row in set (0.01 sec)

ERROR:
No query specified

mysql> drop table innodb_monitor;
Query OK, 0 rows affected (0.01 sec)

mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)

mysql> select actor_id,first_name,last_name from actor where actor_id = 1 lock in share mode;
+----------+------------+-----------+
| actor_id | first_name | last_name |
+----------+------------+-----------+
|        1 | PENELOPE   | GUINESS   |
+----------+------------+-----------+
1 row in set (0.01 sec)

mysql> update actor set last_name = 'lastNameTexst' where actor_id = 1;
^CCtrl-C -- sending "KILL QUERY 32" to server ...
Ctrl-C -- query aborted.
ERROR 1317 (70100): Query execution was interrupted
mysql> update actor set last_name = 'lastNameTexst' where actor_id = 1;
^CCtrl-C -- sending "KILL QUERY 32" to server ...
Ctrl-C -- query aborted.
ERROR 1317 (70100): Query execution was interrupted

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

mysql> update actor set last_name = 'lastNameTexst' where actor_id = 1;
^CCtrl-C -- sending "KILL QUERY 32" to server ...
Ctrl-C -- query aborted.
ERROR 1317 (70100): Query execution was interrupted

session_2:

mysql> use sakila;
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
mysql> select film_id,title from film_text where film_id = 1 for update;
+---------+-------+
| film_id | title |
+---------+-------+
|       1 | test  |
+---------+-------+
1 row in set (0.01 sec)

mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)

mysql> select actor_id,first_name,last_name from actor where actor_id = 1;
+----------+------------+-----------+
| actor_id | first_name | last_name |
+----------+------------+-----------+
|        1 | PENELOPE   | GUINESS   |
+----------+------------+-----------+
1 row in set (0.00 sec)

mysql> select actor_id,first_name,last_name from actor where actor_id = 1 lock in share mode;
+----------+------------+-----------+
| actor_id | first_name | last_name |
+----------+------------+-----------+
|        1 | PENELOPE   | GUINESS   |
+----------+------------+-----------+
1 row in set (0.00 sec)

mysql> update actor set last_name = "test" where actor_id = 1;
^CCtrl-C -- sending "KILL QUERY 33" to server ...
Ctrl-C -- query aborted.
ERROR 1317 (70100): Query execution was interrupted

2.
session_1:

mysql> use sakila;
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
mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)

mysql> select actor_id,first_name,last_name from actor where actor_id = 1;
+----------+------------+-----------+
| actor_id | first_name | last_name |
+----------+------------+-----------+
|        1 | PENELOPE   | GUINESS   |
+----------+------------+-----------+
1 row in set (0.00 sec)

mysql> select actor_id,first_name,last_name from actor where actor_id = 1 for update;
^CCtrl-C -- sending "KILL QUERY 38" to server ...
Ctrl-C -- query aborted.
ERROR 1317 (70100): Query execution was interrupted
mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select actor_id,first_name,last_name from actor where actor_id = 1 for update;
^CCtrl-C -- sending "KILL QUERY 38" to server ...
Ctrl-C -- query aborted.
ERROR 1317 (70100): Query execution was interrupted
mysql> Ctrl-C -- exit!
Aborted

mysql> create table tab_no_index(id int,name varchar(10)) engine = innodb;
Query OK, 0 rows affected (0.03 sec)

mysql> insert into tab_no_index values (1,'1'),(2,'2'),(3,'3'),(4,'4');
Query OK, 4 rows affected (0.01 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from tab_no_index where id = 1;
+------+------+
| id   | name |
+------+------+
|    1 | 1    |
+------+------+
1 row in set (0.01 sec)

mysql> select * from tab_no_index where id = 1 for update;
+------+------+
| id   | name |
+------+------+
|    1 | 1    |
+------+------+
1 row in set (0.00 sec)

session_2:

mysql> use sakila;
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
mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from tab_no_index where id = 2;
+------+------+
| id   | name |
+------+------+
|    2 | 2    |
+------+------+
1 row in set (0.00 sec)

mysql> select * from tab_no_index where id = 2 for update;
^CCtrl-C -- sending "KILL QUERY 42" to server ...
Ctrl-C -- query aborted.
ERROR 1317 (70100): Query execution was interrupted

3.
session_1:

mysql> use sakila;
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
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.00 sec)

mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from actor limit 10;
+----------+------------+--------------+---------------------+
| actor_id | first_name | last_name    | last_update         |
+----------+------------+--------------+---------------------+
|        1 | PENELOPE   | GUINESS      | 2006-02-15 04:34:33 |
|        2 | NICK       | WAHLBERG     | 2006-02-15 04:34:33 |
|        3 | ED         | CHASE        | 2006-02-15 04:34:33 |
|        4 | JENNIFER   | DAVIS        | 2006-02-15 04:34:33 |
|        5 | JOHNNY     | LOLLOBRIGIDA | 2006-02-15 04:34:33 |
|        6 | BETTE      | NICHOLSON    | 2006-02-15 04:34:33 |
|        7 | GRACE      | MOSTEL       | 2006-02-15 04:34:33 |
|        8 | MATTHEW    | JOHANSSON    | 2006-02-15 04:34:33 |
|        9 | JOE        | SWANK        | 2006-02-15 04:34:33 |
|       10 | CHRISTIAN  | GABLE        | 2006-02-15 04:34:33 |
+----------+------------+--------------+---------------------+
10 rows in set (0.00 sec)

mysql> select * from actor where actor_id = 1 for update;
+----------+------------+-----------+---------------------+
| actor_id | first_name | last_name | last_update         |
+----------+------------+-----------+---------------------+
|        1 | PENELOPE   | GUINESS   | 2006-02-15 04:34:33 |
+----------+------------+-----------+---------------------+
1 row in set (0.00 sec)

mysql> select * from actor where actor_id = 30920 for update;
Empty set (0.00 sec)

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

session_2:

mysql> use sakila;
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
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.00 sec)

mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)

mysql> select max(actor_id) from actor;
+---------------+
| max(actor_id) |
+---------------+
|           200 |
+---------------+
1 row in set (0.02 sec)

mysql> insert into actor (actor_id) values (202);
^CCtrl-C -- sending "KILL QUERY 47" to server ...
Ctrl-C -- query aborted.
ERROR 1317 (70100): Query execution was interrupted
mysql> insert into actor (actor_id) values (202);
Query OK, 1 row affected, 2 warnings (0.01 sec)

mysql> select max(actor_id) from actor;
+---------------+
| max(actor_id) |
+---------------+
|           202 |
+---------------+
1 row in set (0.00 sec)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息