1、事务管理
1.1 事务的概念
所谓事务就是针对数据库的一组操作,它可以由一条或多条 SQL 语句组成,同一个事务的操作具备同步的特点,也就是说,事务中的语句要么都执行,要么都不执行。
在数据库中使用事务时,必须先开启事务,语句:start transaction;
事务开启后就可以执行 SQL 语句,SQL 语句执行成功后,需要使用相应语句提交事务,提交事务语句:commit;
,取消事务(也叫回滚)语句:rollback;
rollback语句只针对未提交的事务执行回滚操作。
实例:首先创建数据库,并在数据库中创建一个 account 表,插入相应的数据。
开启一个事务,然后通过 update 语句将 a 账户的200元钱转给 b 账户,最后提交事务。
语句:
start transaction;
update account set money = money - 200 where name = 'a' ;
update account set money = money + 200 where name = 'b' ;
commit;
事务必须同时满足4个特性,即原子性、一致性、隔离性、持久性。
(1) 原子性
是指一个事务必须被视为一个不可分割的最小工作单元,只有事务中的所有的数据库操作都执行成功,才算整个事务执行成功。
(2)一致性
是指事务将数据库从一种状态转变为下一种一致的状态。
(3)隔离性(并发控制、可串行化、锁等)
当多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
(4)持久性
事务一旦提交,所做的修改就会永久保存到数据库中。
1.2 事务的隔离级别
数据库是多线程并发访问的,所以很容易出现多个线程同时开启事务的情况,这就会出现脏读、重复读和幻读的情况,为了避免这种情况的发生,就需要为事务设置隔离级别。
1.2.1 脏读(read uncommitted)
脏读是指一个事务读取了另一个事务未提交的数据。
(1)首先开启两个命令行窗口(相当于开启两个)
(2)设置 b 账户中事务的隔离级别:
(3)演示脏读
b 账户:首先在 b 账户中开启一个事务,并在该事务中查询当前账户的余额信息
a 账户:在 a 账户中开启一个事务,并在当前窗口执行转账功能,具体语句如下:
start transaction;
update account set money = money - 100 where name = 'a';
update account set money = money + 100 where name = 'b';
b 账户:a 账户执行完转账语句后,b 账户查询当前账户
1.2.2 不可重复读(non-repeatable read)
不可重复读是指事务中两次查询的结果不一致,原因是在查询的过程中其他事务做了更新的操作。不可重复读是在事务内重复读取了别的线程已提交的数据。
(1)演示不可重复读
b 账户:首先在 b 账户中开启一个事务,并在该事务中查询当前账户的余额信息
a 账户:update account set money = money - 100 where name = 'a';
b 账户:当 a 账户中的更新操作执行成功后,在 b 账户中再次查询各账户的余额。
(2)设置 b 账户中事务的隔离级别
b 账户:set session transaction isolation level repeatable read;
(3)验证是否出现不可重复读
b 账户:首先在 b 账户中开启一个事务,并在该事务中查询当前账户的余额信息
a 账户:update account set money = money - 100 where name = 'a';
b 账户:当 a 账户中的更新操作执行成功后,在 b 账户中再次查询各账户的余额。
1.2.3 幻读(phantom read)
幻读也称虚读,是指在一个事务内两次查询中数据条数不一致,幻读是由于其他事务做了插入记录的操作,导致记录数有所增加。演示幻读的具体步骤跟上面的类似。
1.2.4 可串行化(serializable)
可串行化是事务的最高隔离级别,它在每个读的数据上加上锁,使之不能相互冲突,但会导致大量的超时现象。
(1)设置 b 账户中事务的隔离级别
b 账户:set session transaction isolation level serializable;
(2)演示可串行化
b 账户:
a 账户:
start transaction;
insert into account (name,money) values('e',1000);
(3)提交事务
b 账户:commit;
a 账户输出Query OK,1 row affected (4.81 sec)