事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有操作作为一个整体一起向系统提交或者撤销操作请求,即这些操作要么同时成功,要么同时失败。mysql的事务默认是自动提交的,也就是说,当执行一条DML语句,Mysql会立即隐式的提交事务
2.1 查看事务提交方式
select@@autocommit;
2.2 设置事务提交方式
set @@autocommit=0;
说明:如果值为1,就是自动提交,为0就是手动提交
2.3 提交事务
commit;
2.4 回滚事务
rollback;
2.5 开启事务
start transaction 或者 begin
select @@transaction_isolation;
set [session|global] transaction isolation level {read uncimmitted | read committed | repeatable read | serializable};
说明1:session :设置仅对当前对话起作用
说明2:global :设置对全局都有用
mysql> select * from account; +----+--------+-------+ | id | name | money | +----+--------+-------+ | 1 | 张三 | 2000 | | 2 | 李四 | 2000 | +----+--------+-------+ 2 rows in set (0.00 sec)
需求1:模拟转账业务创建一个account表,里面有张三、李四两个人,初始金额都有两千元,现在需求让张三转账1000元给李四
第一步:张三的账户余额减1000
mysql> update account set money = money - 1000 where name="张三"; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0
查询张三、李四的账户余额,验证现在余额的变化
mysql> select * from account; +----+--------+-------+ | id | name | money | +----+--------+-------+ | 1 | 张三 | 1000 | | 2 | 李四 | 2000 | +----+--------+-------+ 2 rows in set (0.00 sec)
说明:此时张三的账户已经减去1000了,但是李四的账户还没有增加1000
第二步:李四的账户余额加1000
mysql> update account set money = money + 1000 where name="李四"; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0
查询张三、李四的账户余额,验证现在余额的变化
mysql> select * from account; +----+--------+-------+ | id | name | money | +----+--------+-------+ | 1 | 张三 | 1000 | | 2 | 李四 | 3000 | +----+--------+-------+ 2 rows in set (0.00 sec)
说明:这个时候李四的账户上也已经增加了1000元,所以这个转账分为了两步实现。
异常案例展示:异常说明,如果这个时候在执行完第一步,张三的账户已经减少了1000元,但是系统出问题了,李四的账户上并没有增加1000,这样就出现了异常。
在进行异常展示之前,先把数据恢复成各自2000的余额
mysql> update account set money=2000; Query OK, 2 rows affected (0.02 sec) Rows matched: 2 Changed: 2 Warnings: 0 mysql> select * from account; +----+--------+-------+ | id | name | money | +----+--------+-------+ | 1 | 张三 | 2000 | | 2 | 李四 | 2000 | +----+--------+-------+ 2 rows in set (0.00 sec)
执行异常语句
再来查询张三和李四的余额
mysql> select * from account; +----+--------+-------+ | id | name | money | +----+--------+-------+ | 1 | 张三 | 1000 | | 2 | 李四 | 2000 | +----+--------+-------+ 2 rows in set (0.00 sec)
说明:这时候张三的余额已经减去1000,但是李四的账户上却没有增加1000,这在显示中是绝对不允许的。
使用事务完成,首先同样也是先还原数据,每个人的余额都是2000元
mysql> select * from account; +----+--------+-------+ | id | name | money | +----+--------+-------+ | 1 | 张三 | 2000 | | 2 | 李四 | 2000 | +----+--------+-------+ 2 rows in set (0.02 sec)
执行事务
在验证这时张三和李四的余额
mysql> select * from account; +----+--------+-------+ | id | name | money | +----+--------+-------+ | 1 | 张三 | 2000 | | 2 | 李四 | 2000 | +----+--------+-------+ 2 rows in set (0.00 sec)
说明1:在使用了事务后,会保证事务的原子性,即该事务内的语句要成功够成功,要失败在全部返回,不会存在部分sql执行成功的情况
说明1:首先将模拟客户端改为read uncommitted 模式
说明2:客户端1和客户端2同时开启一个事务
说明3:在客户端2中修改account表中数据,但并不提交事务
说明4:在客户端1中读到了客户端2未提交的事务数据,即read uncommitted 模式下会出现脏读。
说明1:在read committed的隔离模式下
说明2:客户端1和客户端2,同时开启一个事务
说明3:客户端2修改张三余额数据,客户端1未查询到客户端2未提交的修改,因为查询到就是脏读了
说明4:客户端2提交修改余额的事务,客户端1查询,此时查询到张三的余额数据已经修改,及在一个事务中可以查询到其他已经提交事务对数据的修改,而导致在一次事务中对不同数据查询到的值不一致这就是不可重复读。
说明5:在一个事务中查询到其他未提交的事务修改的数据叫脏读,查询到其他已经提交的事务修改的数据叫不可重复读
说明1:多个事务并发时,一个事务新增了数据,并提交,在另外一个事务中查询不到,但是却也不能新增同样的数据,这就是幻读