MySQL学习笔记第5课(共10课)

 27、阻塞

当一个资源已被一个事务占有时,另一个事务执行mutex_enter函数会发生等待,这个就是阻塞。阻塞并不是一件坏事,阻塞是为了保证事务可以并发且正常运行。

 

在InnoDB存储引擎中,参数innodb_lock_wait_timeout用来控制等待的时间(默认是50s)。

mysql> select@@innodb_lock_wait_timeout;

+----------------------------+

|@@innodb_lock_wait_timeout |

+----------------------------+

|                         50 |

+----------------------------+

 

innodb_rollback_on_timeout参数用来设定是否在等待超时时对进行中的事务进行回滚操作(默认是OFF,代表不回滚)。参数innodb_lock_wait_timeout是动态的,可以在MySQL数据库运行时进行调整,而innodb_rollback_on_timeout是静态的,不可在启动时进行修改。

mysql> set@@innodb_lock_wait_timeout=60;

Query OK, 0 rowsaffected (0.00 sec)

mysql> set@@innodb_rollback_on_timeout=on;

ERROR 1238(HY000): Variable 'innodb_rollback_on_timeout' is a read only variable

 

举例:

SessionA

mysql> begin;

Query OK, 0 rowsaffected (0.01 sec)

 

mysql> select* from t for update;

+----+---------+

| id | account |

+----+---------+

|  1 |   1000 |

|  2 |   2000 |

+----+---------+

Session B

mysql> begin;

Query OK, 0 rowsaffected (0.00 sec)

mysql> insertinto t select 2,3000;

ERROR 1205(HY000): Lock wait timeout exceeded; try restarting transaction

如果超过默认50s时,就出现上面的超时。

 

需要牢记的是:默认情况下InnoDB存储引擎不会回滚超时引发的错误异常。其实InnoDB存储引擎在大部分情况下都不会对异常进行回滚,但是会对死锁进行回滚,下面会介绍。

如果在上面的Session A中,

mysql> select* from t where id < 6 for update;

则在Session B中,

mysql> insert intot select 9,5000;

Query OK, 1 rowaffected (0.00 sec)

Records: 1  Duplicates: 0 Warnings: 0

 

mysql> insertinto t select 4,5000;

插入id为4时,会被阻塞。

但是在超时后,我们选择select会发现,9这个记录并没有回滚,但是既没有commit,也没有rollback,这会十分危险的,用户必须判断是需要commit还是需要rollback,然后再进行下一步操作。


发现死锁后,InnoDB存储引擎会马上回滚一个事务,这点是需要注意的。如果在应用程序中捕获到1213这个错误,其实并不需要对其进行回滚。

Oracle数据库中产生死锁的常见原因是没有对外键添加索引,而InnoDB存储引擎会自动对其进行添加,因为可以很好地避免这种问题的发生,人为地删除外键上的索引数据库会抛出一个异常。

 

mysql> createtable p (a int ,primary key(a));

Query OK, 0 rowsaffected (0.38 sec)

 

mysql> createtable c (b int,foreign key(b) references p(a))engine=innodb;

Query OK, 0 rowsaffected (0.12 sec)

 

mysql> showindex from c\G

***************************1. row ***************************

        Table: c

   Non_unique: 1

     Key_name: b

 Seq_in_index: 1

  Column_name: b

    Collation: A

  Cardinality: 0

     Sub_part: NULL

       Packed: NULL

         Null: YES

   Index_type: BTREE

      Comment:

Index_comment:

1 row in set(0.00 sec)

可以看到,虽然在建立子表时指定了外键,但是InnoDB存储引擎还是自动再外键列上建立了索引b,而人为删除这个列却是不允许的。

mysql> dropindex b on c;

ERROR 1553(HY000): Cannot drop index 'b': needed in a foreign key constraint

 

29、锁升级

InnoDB存储引擎不存在锁升级的问题。在InnoDB存储引擎中,1个锁的开销与1000000个锁是一样的,都没有开销。这一点和Oracle数据比较类似。

 

 

30、事务

事务会把数据库从一种状态转换为另一种一致状态。保证数据库的完整性,要么都做修改,要么什么都不做。

 

InnoDB存储引擎中的事务完全符合ACID的特性。ACID是:

1)原子性整个数据库事务是不可分割的工作单位。

2)一致性事务将数据库从一种状态转换为下一种一致状态

3)隔离性一个事务的影响在该事务提交前对其他事务都不可见-通过锁实现。其他三个包括原子性,一致性,持久性是通过数据库的redoundo实现的。

4)持久性事务一旦提交,其结果就是永久性的。

30.1 redo

在InnoDB存储引擎中,事务日志通过重做日志文件和InnoDB存储引擎的日志缓冲来实现。

当开始一个事务时,会记录该事务的一个LSN(Log SequenceNumber,日志序列号)

当事务执行时,会往InnoDB存储引擎的日志缓冲里插入事务日志

当事务提交时,必须将InnoDB存储引擎的日志缓冲写入磁盘(默认的实现方式:innodb_flush_log_at_trx_commit=1)。也就是在数据前,需要先写日志。这种方式称为预写日志方式(WAL,Write-AheadLogging)

 

InnoDB存储引擎通过预写日志的方式来保证事务的完整性。在内存缓冲中页的修改,先是写入重做日志文件,然后再写入磁盘,因此是一种异步的方式。通过命令show engine innodb status来观察当前磁盘和日志的差别。

mysql> showengine innodb status\G

***************************1. row ***************************

  Type: InnoDB

  Name:

Status:

=====================================

120907 17:17:59 INNODB MONITOR OUTPUT

Per secondaverages calculated from the last 2 seconds

-----------------

BACKGROUND THREAD

-----------------

srv_master_threadloops: 2421 1_second, 2421 sleeps, 220 10_second, 221 background, 221 flush

srv_master_threadlog flush and writes: 2424

---

LOG

---

Log sequencenumber 3383730717  -----表示当前的LSN

Log flushed upto   3383730717  -------表示刷新到重做日志文件的LSN

Last checkpointat  3383730717  --------表示刷新到磁盘的LSN

0 pending logwrites, 0 pending chkp writes

24 log i/o'sdone, 0.00 log i/o's/second

 

mysql> callload_test(10000);

Query OK, 0 rowsaffected (0.64 sec)

mysql> showengine innodb status\G

***************************1. row ***************************

  Type: InnoDB

  Name:

Status:

=====================================

120907 17:42:13INNODB MONITOR OUTPUT

=====================================

Per secondaverages calculated from the last 19 seconds

-----------------

BACKGROUND THREAD

-----------------

srv_master_threadloops: 2705 1_second, 2704 sleeps, 245 10_second, 248 background, 248 flush

srv_master_threadlog flush and writes: 2707

……………..

---

LOG

---

Log sequence number 3384239781

Log flushed up to   3384239781

Last checkpoint at  3383735233

0 pending logwrites, 0 pending chkp writes

34 log i/o'sdone, 0.16 log i/o's/second

 

注:可以将Log flushed up toLast checkpoint at的差值504548~492.7K)理解为重做日志产生的增量(以字节为单位)

其实Log sequence numberLog flushed up to在实际的生产环境中,该值有可能不同的。

 

30.2  undo

undo存放在数据库内部的一个特殊段中,这称为undo段,undo段位于共享表空间内。

 

30.3 事务控制语句

在MySQL命令行的默认设置下,事务都是自动提交的。因此开始一个事务,必须使用BEGIN、Start Transaction,或者执行set autocommit=0,以禁止用当前会话的自动提交。



COMMIT和COMMIT WORK语句基本是一致的,都是用来提交事务的。不同之处在于,COMMITWORK用来控制事务结束后的行为,是CHAIN还是RELEASE的。可以通过参数completion_type来进行控制,默认情况下该参数为0,表示没有任何操作。在这种设置下,COMMIT和COMMIT WORK是完全等价的。当参数completion_type的值为1时,COMMIT WORK等同于COMMIT AND CHAIN,表示马上自动开启一个相同隔离级别的事务,

举例:

mysql> createtable t (a int,primary key(a)) engine=innodb;

Query OK, 0 rowsaffected (0.07 sec)

 

mysql> select@@autocommit;

+--------------+

| @@autocommit |

+--------------+

|            1 |

+--------------+

1 row in set(0.00 sec)

 

mysql> set@@completion_type=1;

Query OK, 0 rowsaffected (0.00 sec)

 

mysql> select@@completion_type;

+-------------------+

|@@completion_type |

+-------------------+

| CHAIN             |

+-------------------+

1 row in set(0.00 sec)

 

mysql> begin;

Query OK, 0 rowsaffected (0.00 sec)

 

mysql> insertinto t select 1;

Query OK, 1 rowaffected (0.00 sec)

Records: 1  Duplicates: 0 Warnings: 0

 

mysql> commitwork;

Query OK, 0 rowsaffected (0.00 sec)

 

mysql> insertinto t select 2;

Query OK, 1 rowaffected (0.00 sec)

Records: 1  Duplicates: 0 Warnings: 0

 

mysql> insertinto t select 2;

ERROR 1062(23000): Duplicate entry '2' for key 'PRIMARY'

mysql>rollback;

Query OK, 0 rowsaffected (0.00 sec)

 

mysql> select * from t;

+---+

| a |

+---+

| 1 |

+---+

当参数completion_type的值为1时,COMMIT WORK会自动开启一个事务。

 

当参数completion_type的值为2时,COMMIT WORK等同于COMMIT AND RELEASE。当事务提交后会自动断开与服务器的连接,如:

mysql> set@@completion_type=2;

Query OK, 0 rowsaffected (0.00 sec)

 

mysql> select@@completion_type;

+-------------------+

|@@completion_type |

+-------------------+

| RELEASE           |

+-------------------+

1 row in set(0.00 sec)

 

mysql> begin;

Query OK, 0 rowsaffected (0.00 sec)

 

mysql> insertinto t select 3;

Query OK, 1 rowaffected (0.00 sec)

Records: 1  Duplicates: 0 Warnings: 0

 

mysql> commitwork;

Query OK, 0 rowsaffected (0.00 sec)

 

mysql> select@@version\G

ERROR 2006(HY000): MySQL server has gone away

No connection.Trying to reconnect...

Connectionid:    118436

Current database:test

 

***************************1. row ***************************

@@version:5.5.17-enterprise-commercial-advanced-log

1 row in set(0.00 sec)

 

Rollback和Rollback work与COMMIT和COMMIT WORK的工作一样。

 

savepoint 记录了一个保存点,可以通过rollback to savepoint回滚到某个保存点,但是如果回滚到一个不存在的保存点,则会抛出异常。

rollback tosavepoint并不是一个真正地结束一个事务,即时执行了rollback to savepoint,之后也需要显示地运行commit或者rollback命令。


评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值