数据库复习笔记——事物&并发控制

数据库恢复技术——事务处理和并发控制技术
《数据库系统概论》 

   事物是一系列的数据库操作,是数据库应用程序的基本逻辑单元。 事务处理技术主要包括数据库恢复技术和并发控制技术。

一 .  事物是什么
  
          事务是用户定义的一个数据库操作序列,这些操作要么全做,要么不做,是一个不可分割的工作单位。

事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起,并用形如start transaction和end transaction语句(或函数调用)来界定。

  例如:在关系数据库中,一个事务可以是一条SQL语句,一组SQL语句或整个程序。

  事务和程序是两个概念。一般的讲,一个程序中包含多个事务。


事务可以由用户显式控制。事务由事务开始(start transaction)和事务结束(end transaction)之间执行的全体操作组成。

  SQL中,定义事物的语句一般有三条:

   
   
  1.    Start TRANSACTION; // 事务开始标识
  2.    COMMIT; // 提交事务的所有操作(将事务所有对数据库的更新写回到磁盘上的物理数据库中去)
  3.    ROLLBACK; // 回滚,撤销所有已完成的操作,回到事务开始的状态。
         事物通常是 START TRANSCATION 或 BEGIN 开始,以 COMMIT 或 ROLLBACK结束。  


二. 事物存在的意义之一:事务是用来保证数据操作的安全性。


 三. 事物的ACID特性:

  

  事务应该具有4个属性:原子性、一致性、隔离性、持续性。这四个属性通常称为ACID特性。

  原子性(atomicity[ˌætəmsɪti])。事物是数据库的逻辑工作单位,一个事务是一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做。

  一致性(consistency)。事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。(当前事务必须成功执行)当数据库只包含成功事物提交的结果时,就说数据库处于一致性状态。 一致性与原子性是密切相关的。

  隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部操作使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰

  持久性(durability)。持续性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。持久化。

  

事物的ACID特性遭到破坏的因素有:

 (1)多个事务并行执行时,不同的事务操作交叉执行;

 (2)事务在执行过程中被强行停止;



四. 事务是恢复和并发控制的基本单位。

    保证事物的ACID特性是事务处理的重要任务,而事物的ACID特性可能遭到破坏的原因之一是多个事物对数据库的并发操作造成的。 为了保证事务的隔离性和一致性,数据库管理系统需要对并发操作进行正确的调度。这些就是并发控制机制的责任。
    
    并发操作带来的数据不一致性包括 丢失修改、不可重复度、和 读‘脏’数据。产生这三种数据不一致性的主要原因是 并发操作破坏了事务的隔离性。
          并发控制机制就是要用正确的方式调度并发操作,使一个用户事物的执行不受其他事物的干扰,从而 避免造成数据不一致性型。
            并发控制的主要技术有封锁(locking)、时间戳(timestamp)、乐观控制法(optimistic scheduler)和多版本并发控制(muti-version concurrency control,MVCC)等。
    
五. 封锁

            封锁是实现并发控制的一个非常重要的技术。
    所谓封锁就是事务T在对某个数据对象例如表、记录进行操作之前,先向系统发出请求,对其加锁。加锁后,事务T就对该数据对象有了一定的控制,在事物T释放它的锁之前,其他事务不能更新此数据对象 。
    基本的封锁类型有两种:排它锁(exclusive locks,简称X锁)和共享锁(shared locks,简称S锁)。 
    排它锁又称写锁。  共享锁又称读锁。


      
Mysql 中的事物
    在MySQL中,事务就是一个逻辑工作单元的一系列步骤。事务是用来保证数据操作的安全性。
    MyISAM不支持事物,InnoDB支持事物。
   如果 要让 mysql 支持事物,只需要修改数据引擎.
   
   
  1. alter table testalt Engine=InnoDB; # 5.5 版本以后默认引擎 InnoDB
  2. alter table testalt type=InnoDB; # 5.5 之前的版本

   mysql 使用 start transaction 或 begin 命令开始一个事物,使用  commit 或者rollback 来结束事物.
   事物的结束:除了 commit 或者rollback可以结束外,使用DDL/DCL 语句也会结束事物。
   保存点: 通过保存点机制,用户可以在事物里用 savepoint name 命令设置一些保存点,以后用户在使用rollback to savepoint name 结束事物时,name之前的数据保存,之后的数据不保存。(类似 git 里面的 标签 git tag).
   
   mysql 使用事物的关键字.
    
    
  1.       begin / start transaction   开始一个事物
  2.       commit           提交事务的改变到数据库
  3.       rollback         取消操作,回滚 
  4.       savepoint  name  保存,部分取消,部分提交(打标签)

  
事物实例:

(1)未使用 保存点
    
    
  1. mysql> select * from Student;
  2. +--------+------------------+------+------+-------+
  3. | Sno | Sname | Ssex | Sage | Sdept |
  4. +--------+------------------+------+------+-------+
  5. | 312001 | Ken | fe | 19 | CS |
  6. | 312019 | Linus Travlds | ma | 55 | Linux |
  7. | 312028 | Taylor | fe | 21 | ELE |
  8. | 312088 | Coohx | male | 21 | Linux |
  9. | 31223 | Richard | ma | 23 | IS |
  10. | 319889 | Richard Stallman | male | 88 | Linux |
  11. | 319999 | Dernis Ritchie | male | 88 | Linux |
  12. +--------+------------------+------+------+-------+
  13. 7 rows in set (0.00 sec)
  14. mysql> start transaction;
  15. Query OK, 0 rows affected (0.00 sec)
  16. mysql> delete from Student where Sname='Ken';
  17. Query OK, 1 row affected (0.12 sec)
  18. mysql> select * from Student;
  19. +--------+------------------+------+------+-------+
  20. | Sno | Sname | Ssex | Sage | Sdept |
  21. +--------+------------------+------+------+-------+
  22. | 312019 | Linus Travlds | ma | 55 | Linux |
  23. | 312028 | Taylor | fe | 21 | ELE |
  24. | 312088 | Coohx | male | 21 | Linux |
  25. | 31223 | Richard | ma | 23 | IS |
  26. | 319889 | Richard Stallman | male | 88 | Linux |
  27. | 319999 | Dernis Ritchie | male | 88 | Linux |
  28. +--------+------------------+------+------+-------+
  29. 6 rows in set (0.00 sec)
  30. mysql> rollback;
  31. Query OK, 0 rows affected (0.00 sec)
  32. mysql> select * from Student;
  33. +--------+------------------+------+------+-------+
  34. | Sno | Sname | Ssex | Sage | Sdept |
  35. +--------+------------------+------+------+-------+
  36. | 312001 | Ken | fe | 19 | CS |
  37. | 312019 | Linus Travlds | ma | 55 | Linux |
  38. | 312028 | Taylor | fe | 21 | ELE |
  39. | 312088 | Coohx | male | 21 | Linux |
  40. | 31223 | Richard | ma | 23 | IS |
  41. | 319889 | Richard Stallman | male | 88 | Linux |
  42. | 319999 | Dernis Ritchie | male | 88 | Linux |
  43. +--------+------------------+------+------+-------+
  44. 7 rows in set (0.00 sec)
  45. mysql> commit;
  46. Query OK, 0 rows affected (0.00 sec)
  47. mysql> select * from Student;
  48. +--------+------------------+------+------+-------+
  49. | Sno | Sname | Ssex | Sage | Sdept |
  50. +--------+------------------+------+------+-------+
  51. | 312001 | Ken | fe | 19 | CS |
  52. | 312019 | Linus Travlds | ma | 55 | Linux |
  53. | 312028 | Taylor | fe | 21 | ELE |
  54. | 312088 | Coohx | male | 21 | Linux |
  55. | 31223 | Richard | ma | 23 | IS |
  56. | 319889 | Richard Stallman | male | 88 | Linux |
  57. | 319999 | Dernis Ritchie | male | 88 | Linux |
  58. +--------+------------------+------+------+-------+
  59. 7 rows in set (0.00 sec)

(2) 使用保存点
    
    
  1. mysql> begin;
  2. Query OK, 0 rows affected (0.00 sec)
  3. mysql> insert into Student values('311010','IEEE','organization','88','Linux');
  4. Query OK, 1 row affected, 1 warning (0.04 sec)
  5. mysql> select * from Student;
  6. +--------+------------------+------------+------+-------+
  7. | Sno | Sname | Ssex | Sage | Sdept |
  8. +--------+------------------+------------+------+-------+
  9. | 311010 | IEEE | organizati | 88 | Linux |
  10. | 312001 | Ken | fe | 19 | CS |
  11. | 312019 | Linus Travlds | ma | 55 | Linux |
  12. | 312028 | Taylor | fe | 21 | ELE |
  13. | 312088 | Coohx | male | 21 | Linux |
  14. | 31223 | Richard | ma | 23 | IS |
  15. | 319889 | Richard Stallman | male | 88 | Linux |
  16. | 319999 | Dernis Ritchie | male | 88 | Linux |
  17. +--------+------------------+------------+------+-------+
  18. 8 rows in set (0.01 sec)
  19. mysql> savepoint p1;
  20. Query OK, 0 rows affected (0.00 sec)
  21. mysql> delete from Student where Sname='Ken';
  22. Query OK, 1 row affected (0.00 sec)
  23. mysql> select * from Student;
  24. +--------+------------------+------------+------+-------+
  25. | Sno | Sname | Ssex | Sage | Sdept |
  26. +--------+------------------+------------+------+-------+
  27. | 311010 | IEEE | organizati | 88 | Linux |
  28. | 312019 | Linus Travlds | ma | 55 | Linux |
  29. | 312028 | Taylor | fe | 21 | ELE |
  30. | 312088 | Coohx | male | 21 | Linux |
  31. | 31223 | Richard | ma | 23 | IS |
  32. | 319889 | Richard Stallman | male | 88 | Linux |
  33. | 319999 | Dernis Ritchie | male | 88 | Linux |
  34. +--------+------------------+------------+------+-------+
  35. 7 rows in set (0.00 sec)
  36. mysql> rollback to savepoint p1;
  37. Query OK, 0 rows affected (0.00 sec)
  38. mysql> commit;
  39. Query OK, 0 rows affected (0.01 sec)
  40. mysql> select * from Student;
  41. +--------+------------------+------------+------+-------+
  42. | Sno | Sname | Ssex | Sage | Sdept |
  43. +--------+------------------+------------+------+-------+
  44. | 311010 | IEEE | organizati | 88 | Linux |
  45. | 312001 | Ken | fe | 19 | CS |
  46. | 312019 | Linus Travlds | ma | 55 | Linux |
  47. | 312028 | Taylor | fe | 21 | ELE |
  48. | 312088 | Coohx | male | 21 | Linux |
  49. | 31223 | Richard | ma | 23 | IS |
  50. | 319889 | Richard Stallman | male | 88 | Linux |
  51. | 319999 | Dernis Ritchie | male | 88 | Linux |
  52. +--------+------------------+------------+------+-------+
  53. 8 rows in set (0.00 sec)


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

六.  在mysql中怎样开始或回滚一个事务呢?

1、显示开始,START TRANSACTION WITH CONSISTENT SNAPSHOT;  BEGIN; 

2、隐士开始,BEGIN / START TRANSACTION / SET AUTOCOMMIT = 1 / 其他非事务语句(DDL/DCL)会导致之前没提交的事务提交。

3、显示回滚,ROLLBACK

4、隐士回滚,连接断开 / 超时

 

在修改事务隔离级别时需要注意set global  xxx;这时只针对新连接生效,当前连接不生效(如果有连接池的话就麻烦了,连接池都是长连接)

复制代码
mysql> set global transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)

mysql> show session variables like "tx_isolation";
+---------------+-----------------+| Variable_name | Value           |+---------------+-----------------+| tx_isolation  | REPEATABLE-READ |+---------------+-----------------+1 row in set (0.00 sec)
复制代码

在修改事物隔离级别时不加global和session,下一个事物才开始生效。set session xxx;直接生效。(mysql中默认是RR隔离级别)

 

七. 并发控制带来的数据不一致性

   如果没有事物控制的话,那么并发读写数据库会有什么隐患? 


   脏读:一个事物按相同的查询条件读取以前检索过的数据,却发现其他事物更新后达到了满足其查询条件的旧数据(此时它还未提交),这种现象称为“脏读”

   不可重复读:一个事物按相同的查询条件读取以前检索过的数据,却发现其他事物更新后达到了满足其查询条件的旧数据(此时它已被提交),这种现象称为“不可重复读”

   幻读:一个事物按相同的查询条件读取以前检索过的数据,却发现其他事物插入了满足其查询条件的新数据(此时它已被提交),这种现象称为“幻读”

    脏读,在一个事物里面读取到其他事物未提交的数据:


   R()代表读数据; W()代表写数据;

                                            


不可重复读,在一个事物里面读取到其他事物已经提交的修改的数据:

                                                




幻读,在一个事物里面读取到其他事物已经提交新增的数据:

                                                                                   


八.  封锁协议(隔离级别)


mysql的4种隔离级别:


1. read uncommitted  隔离级别最低,允许脏读,允许事物查看其它事物所进行的未提交更改(读未提交时,读事务直接读取主记录,无论更新事务是否完成)

2.read committed    允许幻读,允许事物查看其它事物所进行的已提交更改(读提交时,读事务每次都读取undo log中最近的版本,因此两次对同一字段的读可能读到不同的数据(幻读),但能保证每次都读到最新的数据。)

3.repeatable read     消除了脏读、不可重复读、幻读保证了事物一致性(每次都读取指定的版本,这样保证不会产生幻读,但可能读不到最新的数据

4.serializable         串行化读,每次读都需要获得表级别共享锁,读写间互相都会阻塞(锁表,读写相互阻塞,使用较少。)


例如有t1表:

复制代码
mysql> show create table t1\G
*************************** 1. row ***************************Table: t1
Create Table: CREATE TABLE `t1` (
  `c1` int(11) NOT NULL,
  `c2` int(11) DEFAULT NULL,
  `c3` int(11) DEFAULT NULL,
  PRIMARY KEY (`c1`),
  KEY `c2` (`c2`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql> select * from t1;
+----+------+------+| c1 | c2   | c3   |+----+------+------+|  0 |    0 |    0 ||  1 |    1 |    1 ||  2 |    2 |    2 ||  3 |    3 |    3 |+----+------+------+4 rows in set (0.00 sec)
复制代码


1.读未提交,read uncommitted,RU

                                                 

                                        


2. 读已提交,read committed,RC

                                                      


3. RC下的幻读:(此处加for update 表示即便是 RC隔离级别,但是可以读取当前数据的最新版本)


                                 


4.  可重复读,repeatable read,RR

                                      



5.  在RR隔离级别下,没有幻读。

       innodb在RR级别下引入了gap lock(间隙锁)来解决幻读,例如:select * from t1 where c2 =2 for update;这样会将索引记录上面1-3(不包括1和3)这个范围的gap全锁定来避免幻读:

                                         


6. 串行,serializable

                                    


可通过innodb_lock_waits查看发生锁等待信息:

复制代码
mysql> select * from information_schema.innodb_lock_waits;
+-------------------+------------------------+-----------------+------------------+| requesting_trx_id | requested_lock_id      | blocking_trx_id | blocking_lock_id |+-------------------+------------------------+-----------------+------------------+| 421424334461664   | 421424334461664:31:3:4 | 4910            | 4910:31:3:4      |+-------------------+------------------------+-----------------+------------------+1 row in set, 1 warning (0.00 sec)
复制代码

 

  最后我们再说下 InnoDB semi-consitent read,innodb的 半一致性读,在innodb特殊实现的机制,主要目的是提升并发效率。update语句如果读到一行已经加锁的记录,此时InnoDB返回该记录最新版本,再次判断此版本是否满足update的where条件,若满足(需要更新),则MySQL会重新发起一次读操作,此时会读取行的最新版本(并加锁)   

这种情况只发生在RC或 RR+innodb_locks_susafe_for_binlog=1环境下,所以说 RR+innodb_locks_susafe_for_binlog=1时存在幻读可能。

可以这样理解:假设这个表有10万行数据,对一个表进行更新,没有索引,正常情况下会把所有数据全部锁定,但是另一个会话想要对这个表update 更新,这个update 可能只影响两行数据,这时候这个update可以被执行,不受全表锁限制,仅仅只针对update生效,其他SQL不会生效。

          
















































  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值