第7章 事务
MySQL事务是一组数据库操作的执行单元,它确保了数据的完整性和一致性
7.1 提交/回滚事务
开启事务:start transaction;
提交事务:commit;
回滚事务:rollback;
(回滚永远都是只能回滚到上一次的提交点!)
事务对应的英语单词是:transaction
测试一下,在mysql当中默认的事务行为是怎样的
mysql默认情况下是支持自动提交事务的。(自动提交)
自动提交:每执行一条DML语句,则提交一次!
这种自动提交实际上是不符合我们的开发习惯,因为一个业务通常是需要多条DML语句共同执行才能完成的,为了保证数据的安全,必须要求同时成功之后再提交,所以不能执行一条就提交一条。
怎么将mysql的自动提交机制关闭掉呢
先执行这个命令:start transaction;
回滚事务
mysql> select * from dept_bak; Empty set (0.00 sec) mysql> start transaction; //关闭自动提交机制 Query OK, 0 rows affected (0.00 sec) mysql> insert into dept_bak values(10,'abc', 'tj'); Query OK, 1 row affected (0.00 sec) mysql> insert into dept_bak values(10,'abc', 'tj'); Query OK, 1 row affected (0.00 sec) mysql> select * from dept_bak; +--------+-------+------+ | DEPTNO | DNAME | LOC | +--------+-------+------+ | 10 | abc | tj | | 10 | abc | tj | +--------+-------+------+ 2 rows in set (0.00 sec) mysql> rollback; Query OK, 0 rows affected (0.00 sec) mysql> select * from dept_bak; Empty set (0.00 sec)
提交事务
mysql> select * from dept_bak; Empty set (0.00 sec) mysql> insert into dept_bak values(10,'abc','tj'); Query OK, 1 row affected (0.00 sec) mysql> insert into dept_bak values(20,'abc','tj'); Query OK, 1 row affected (0.00 sec) mysql> commit; Query OK, 0 rows affected (0.00 sec) mysql> select * from dept_bak; +--------+-------+------+ | DEPTNO | DNAME | LOC | +--------+-------+------+ | 10 | abc | tj | | 10 | abc | tj | +--------+-------+------+ 2 rows in set (0.00 sec) mysql> rollback; Query OK, 0 rows affected (0.00 sec) mysql> select * from dept_bak; +--------+-------+------+ | DEPTNO | DNAME | LOC | +--------+-------+------+ | 10 | abc | tj | | 10 | abc | tj | +--------+-------+------+ 2 rows in set (0.00 sec)
7.2 事务四大特性
事务四大特性ACID:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)
- 原子性:事务是最小的执行单位,不允许分割;意味着事务中的操作要么全部完成,要么完全不起作用。
- 一致性:事务必须使数据库从一个一致性状态转变为另外一个一致的状态。例如转账业务中,无论事务是否成功,转账者和收款人总金额是不变的。
- 隔离性:多个事务并发执行,不会互相干扰。
- 持久性:事务一旦被提交,对数据库的修改是永久性的。
注意:AID是手段,C是目的
7.3 四种隔离性
A教室和B教室中间有一道墙,这道墙可以很厚,也可以很薄。这就是事务的隔离级别。这道墙越厚,表示隔离级别就越高。
事务和事务之间的隔离级别有哪些呢?
(1)读未提交:read uncommitted
(最低的隔离级别)《没有提交就读到了》
事务A可以读取到事务B未提交的数据。
这种隔离级别存在的问题就是:
脏读现象!(Dirty Read)
这种隔离级别一般都是理论上的,大多数的数据库隔离级别都是二档起步!
(2)读已提交:read committed
提交之后才能读到
事务A只能读取到事务B提交之后的数据。
解决了什么问题?: 解决了脏读的现象。
存在什么问题?: 不可重复读取数据。
不可重复读取数据指:在事务开启之后,第一次读到的数据是3条,当前事务还没有结束,可能第二次再读取的时候,读到的数据是4条,3不等于4称为不可重复读取。
这种隔离级别是比较真实的数据,每一次读到的数据是绝对的真实。
oracle数据库默认的隔离级别是:read committed
(3)可重复读:repeatable read
《提交之后也读不到,永远读取的都是刚开启事务时的数据》
可重复读:事务A开启之后,不管是多久,每一次在事务A中读取到的数据都是一致的。即使事务B将数据已经修改,并且提交了,事务A读取到的数据还是没有发生改变。
读解决了什么问题?:解决了不可重复读取数据。
存在的问题是什么?:可以会出现幻影读。
每一次读取到的数据都是幻象。不够真实!
早晨9点开始开启了事务,只要事务不结束,到晚上9点,读到的数据还是那样!
读到的是假象。不够绝对的真实。
mysql中默认的事务隔离级别就是这个!
(4)序列化/串行化:serializable
这是最高隔离级别,效率最低。解决了所有的问题。
这种隔离级别表示事务排队,不能并发!
synchronized,线程同步(事务同步)
每一次读取到的数据都是最真实的,并且效率是最低的。
7.4 验证各种隔离级别
查看隔离界别:
mysql> SELECT @@tx_isolation; +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | //mysql默认的隔离级别 +-----------------+ 1 row in set (0.00 sec)
验证:read uncommited
mysql> set global transaction isolation level read uncommitted; 事务A 事务B -------------------------------------------------------------------------------- use bjpowernode; use bjpowernode; start transaction; select * from t_user; start transaction; u select * from t_user;
验证:read commited
mysql> set global transaction isolation level read committed; 事务A 事务B -------------------------------------------------------------------------------- use bjpowernode; use bjpowernode; start transaction; start transaction; select * from t_user; insert into t_user values('zhangsan'); select * from t_user; commit; select * from t_user;
验证:repeatable read
mysql> set global transaction isolation level repeatable read; 事务A 事务B -------------------------------------------------------------------------------- use bjpowernode; use bjpowernode; start transaction; start transaction; select * from t_user; insert into t_user values('lisi'); insert into t_user values('wangwu'); commit; select * from t_user;
验证:serializable
mysql> set global transaction isolation level serializable; 事务A 事务B -------------------------------------------------------------------------------- use bjpowernode; use bjpowernode; start transaction; start transaction; select * from t_user; insert into t_user values('abc'); select * from t_user; commit;