数据库事务

事务

什么是事务?

  • Transaction 一个__最小__的,__不可再分__的工作单元。

  • 通常一个事务对应的是一个完整的业务。 例如银行转账语句

  • 而一个完整的业务需要批量的DML语句共同联合完成。

  • 事务只和DML语句有关系、或者说只有DML语句才有事务(insert 、update、delete)

  • 业务逻辑不同DML语句的个数也不同,具体多少条和具体的业务逻辑有关(可以是一条)。

以银行转账为例,A->B转账时,需要两条update语句,在转账时需要保证这两条语句具有一致的成功性或者失败性,所以需要将这两条语句捆绑完成。此时需要用到事务。

关于银行转账

账务转账是一个完整的业务,最小的单元,不可再分。也就是说银行账户转账是一个事务。

执行转账操作

update t_act set balance=40000 where actno=‘act1’;

update t_act set balance=20000 where actno=‘act2’;

以上两条DML语句要求必须同时成功或者同时失败,最小单元,不可再分。

当第一条DML语句执行成功之后,不能将底层数据库中第一个账户的数据修改,只是将操作记录一下,这个记录是在内存中完成的,当第二条DML语句执行成功之后,和底层数据库文件中的数据完成同步。若第二条DML语句执行失败,清空所有的历史操作记录,要完成以上功能,必须借助事务。

事务的四大特性 ACID

  1. 原子性A
    • 事务是最小的工作单元不可再分,要么同时成功,要么同时失败
  2. 一致性C
    • 事务使得系统从一个一致的状态转换到另外一个一致的状态,可以说AID是保证事务一致性的方法
  3. 隔离性I
    • 事务A和B之间具有隔离性,并发执行的事务之间不会互相影响
  4. 持久性D
    • 事务提交后,对数据库中数据的改变将是永久的

关于一些术语

  1. 开启事务: start transaction
  2. 事务结束:end transaction
  3. 提交事务:commit transaction
  4. 回滚事务:rollback transaction

和事务有关的两条重要SQL语句(TCL)

commit;提交

rollback;回滚

事务开启的标志和结束的标志

  1. 开启的标志:
    • 任何一条DML语句开始执行
  2. 结束的标志:
    • 提交或者回滚
      • 提交:成功的结束,将所有DML语句操作历史纪录和底层硬盘文件中的数据来一次同步(也会清空历史纪录)
      • 回滚:失败的结束,将所有DML语句历史记录全部清空

重点

在事务进行过程中,未结束之前DML语句是不会更改底层数据库文件中的数据。只是将历史操作记录一下,在内存中完成记录。只有在事务结束的时候,而且是成功的结束的时候才会修改底层硬盘文件中的数据。

在mysql数据库管理系统中,事务的提交和回滚演示

  1. 在mysql数据库管理系统中,事务是自动提交的(执行一条DML语句就是一个事务的的开启),即只要执行一条DML语句,就表示开启了事务,并且提交了事务。

  2. 这种自动提交机制是可以关闭的:关闭的第一种方式,也是一种进行事务的方式,默认情况下自动提交是不能完成多条DML语句捆绑的。

    • start transaction; 手动开启事务
    • 执行DML语句(可以是多条)
    • commit;手动提交事务(事务成功的结束)
    • start transaction; 手动开启事务
    • 执行DML语句(可以是多条)
    • rollback;手动回滚事务(事务失败的结束)
  3. 关闭自动提交的第二种方式

    set autocommit = off;关闭

    set session autocommit = off;关闭

    set autocommit = on;打开

    set session autocommit = on;打开

    以上打开和关闭只对当前会话有效

    show variables like ‘%commit%’;可以查看是否开启关闭

  4. 注意,当在mysql种执行一条DML语句时,执行完毕后,如果是默认自动提交,那么会写到磁盘文件中,如果不是自动提交则只是在内存中更新了这条记录,只有执行了提交才会写到磁盘中,需要注意的是如果在内存中更新了记录,那么在当前会话是可以查询到变化的,但是在其他会话中查询不到

事务的四个特性之一:隔离性

  1. 事务A和B之间有一定的隔离性

  2. 隔离性有隔离级别(4个),背英语单词

    • 读未提交 read uncommitted

      • 事务A和B,事务A未提交的数据,事务B可以读取到。
      • 这里读取到的数据可以叫做脏数据或者叫做Dirty Read
      • 这种隔离级别是最低级别,这种级别一般都是在理论上存在的,数据库默认的隔离级别一般都是高于该隔离级别的。
    • 读已提交 committed

      • 事务A和B,事务A提交的数据,事务B才能读取到。
      • 这种隔离级别高于上面的读未提交
      • 换句话说:对方事务提交之后的数据,我当前事务才能读取到。
      • 这种隔离级别可以避免脏数据
      • 这种隔离级别会导致__不可重复读取__,不同时间B事务(A已经结束了,B还没有结束)读取到的数据不同,即在同一个事务中两次读取同一个数据读取到的值是不同的,即A事务开始后先读取了某个数据,但是此时B事务开启后修改了这个数据,此时B提交后,A再次读取该数据读取到的值是不同的,从而导致的幻象读
    • 可重复读 repeatable read,,即使A提交了数据,B也读取不到

      • 事务A和B,事务A提交之后的数据,B读取不到。
      • 事务B是可重复读取数据的。
      • 这种隔离级别高于读已提交。
      • 换句话说:对方提交之后的数据我还是读取不到。
      • 这种隔离级别可以避免脏读、不可重复读取,达到可重复读取。(即事务B开始读取的时候,和之后读取的数据是一样的,此时是将第一次读取的数据放到了内存中)
      • mysql数据库管理系统默认的隔离级别是可重复读。
      • 虽然可以达到可重复读的效果,但是会导致__幻象读__
      • 即在A事务开始时,会保存记录快照,在事务结束前其访问到的都是快照
    • 串行化 serializable

      • 事务A和事务B,事务A在操作数据库表中数据的时候,事务B只能排队等待。
      • 这种事务隔离级别,一般很少使用,吞吐量太低,用户体验不好。
      • 这种隔离级别可以避免幻象读,每一次读取的都是数据库表中真实的记录(读取的磁盘,而不是内存)
      • 事务A和B串行,不再并发。

    事务的四个隔离级别所导致的问题

    1. 脏读,即其他事务读取到了当前事务未提交的数据
    2. 不可重复读,即A事务读取到了B事务修改后的已经提交的事务
    3. 幻读:当某个事务在读取某个范围的数据之后,此时另外一个事务再次插入了一行数据,当该事务再次读取时会发现多了一行,即产生了幻行,或者说A事务开启后查询某条记录不存在,但是此时B事务插入了该记录并提交,当A再次插入时会报错(加入插入的是主键)

幻读:幻读不是两次读取到的数据不同,而是某次查询的结果所表征的数据状态无法支撑后序操作,例如查询某个记录显示不存在(但是实际已经存在),如果在查询事务中插入则会报错

设置事务的隔离级别

1.修改my.ini配置文件

在[mysqld]下加

transaction-isolation = READ UNCOMMITTED/READ COMMITTED/REPEATABLE READ/SERIALIZABLE

2.使用命令的方式设置事务的隔离级别

可选值 READ UNCOMMITTED/READ COMMITTED/REPEATABLE READ/SERIALIZABLE

命令格式

set [无/session/global] transaction isolation level <可选值>

无/session为会话级的设置,仅当前会话有效

global为全局级,全局有效

3.查看隔离级别

select @@tx_isolation;

select @@session.tx_isolation;

select @@global.tx_isolation;

你可能感兴趣的:(数据库事务)