十、MySQL事务 一、事务的四大特性(ACID) 二、设置回滚点 三、并发事务

  MySQL用 begin, rollback, commit来实现事务。

    • begin 开始一个事务
    • rollback 事务回滚
    • commit 事务确认。
  • 原子性(Atomicity):所有操作是不可再分割的原子单位。

  • 一致性(Consistency):业务规则保持一致。

  • 隔离性(Isolation):并发操作中,不同事务之间应该隔离开来,

  • 持久性(Durability):事务中所有的数据操作都必须被持久化到数据库中。

 

  下面演示zhangsan给lisi转账1000元的示例:

-- 建表
CREATE TABLE  account(
    id BIGINT PRIMARY KEY,
    balance BIGINT COMMENT '余额'
)ENGINE='InnoDB',CHARSET='utf8' 

-- 插入数据
INSERT INTO `account` (`id`,`balance`) VALUES ('1','10'),('2','10');
-- 放弃事务,转账失败:
   START  TRANSACTION;
         UPDATE account SET balance=balance-10 WHERE id=1;
         UPDATE account SET balance=balance+10 WHERE id=2;
   ROLLBACK;

-- 提交事务,转账成功:
   START TRANSACTION;
        UPDATE account SET balance=balance-10 WHERE id=1;
        UPDATE account SET balance=balance+10 WHERE id=2;
   COMMIT;

二、设置回滚点

  如下,第二条update语句失效后,便COMMIT,提交了事务。

--回到回滚点rol_01,此次是只执行第一条update语句
START TRANSACTION;
    UPDATE account SET balance=balance-1000 WHERE id=1;
SAVEPOINT  rol_01;
    UPDATE account SET balance=balance+1000 WHERE id=2;
ROLLBACK  TO  SAVEPOINT  rol_01;
COMMIT

三、并发事务

3.1、事务的并发问题是如何发生的?

  多个线程的事务同时操作同一个数据库的相同数据时。

3.2、并发问题都有哪些?

  并发访问数据库会引起脏读、幻读、虚读。

  • 脏读:一个线程的事务读取了其他事务还没有提交的数据,读到的是其他事务“更新”的数据。

  • 不可重复读(虚读)在一个事务内,多次读同一个数据。在这个事务还没有结束时,另 一个事务也访问该同一数据。

  • 幻读:一个事务读取了其他事务还没有提交的数据,只是读到的是 其他事务“插入”的数据。

不可重复读(虚读):是指在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。这是由于查询时系统中其他事务修改的提交而引起的。比如事务T1读取某一数据,事务T2读取并修改了该数据,T1为了对读取值进行检验而再次读取该数据,便得到了不同的结果。

一种更易理解的说法是:在一个事务内,多次读同一个数据。在这个事务还没有结束时,另 一个事务也访问该同一数据。那么,在第一个事务的两次读数据之间。由于第二个事务的修改,那么第一个事务读到的数据可能不一样,这样就发生了在一个事务内 两次读到的数据是不一样的,因此称为不可重复读,即原始读取不可重复。

幻读:是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,比如这种修改涉及到表中的“全部数据行”。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入“一行新数据”。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一 样.一般解决幻读的方法是增加范围锁,锁定检锁范围为只读,这样就避免了幻读。简单来说,幻读是由插入或者删除引起的

  大致的区别在于不可重复读是由于另一个事务对数据的更改所造成的,而幻读是由于另一个事务插入或删除引起的。不可重复读需要锁住满足条件的记录,幻读要锁住满足条件及其相近的记录

3.3、如何解决并发问题

  通过设置隔离级别来解决并发问题

3.4、事务隔离级别

  • Read Uncommitted(读取未提交内容)
    在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)

  • Read Committed(读取提交内容)
    这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。

  • Repeatable Read(可重读)
    这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题

  • Serializable(可串行化)
    这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争