MySql事务
1. 事务的ACID属性(事务的特点)
-
原子性
- 事务是不可分割的,事务中的操作要么都发生,要么都不发生。
-
一致性
- 事在事务开始之前和事务结束以后,数据库的完整性没有被破坏。
-
隔离性
- 数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
-
持久性
- 事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
2. 事务控制语句
- BEGIN 或 START TRANSACTION 显式地开启一个事务;
- COMMIT 也可以使用 COMMIT WORK,不过二者是等价的。COMMIT 会提交事务,并使已对数据库进行的所有修改成为永久性的;
- ROLLBACK 也可以使用 ROLLBACK WORK,不过二者是等价的。回滚会结束用户的事务,并撤销正在进行的所有未提交的修改;
- SAVEPOINT identifier,SAVEPOINT 允许在事务中创建一个保存点,一个事务中可以有多个 SAVEPOINT;
- RELEASE SAVEPOINT identifier 删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常;
- ROLLBACK TO identifier 把事务回滚到标记点;
- SET TRANSACTION 用来设置事务的隔离级别。InnoDB 存储引擎提供事务的隔离级别有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ 和 SERIALIZABLE。
3. 事务并发时如果没有采取隔离机制,会造成以下问题
- 脏读
- 对于两个事务A,B,如果A读取了已经被B更新但是没有提交的数据后,此时B再回滚事务,A读取的数据就是临时且无效的。
- 不可重复读
- A,B读取同一个字段,如果B更新了这个字段,那么A再读取这个字段的时候,数据就不同了。
- 幻读
- A读从表里读了4个字段,B更新后新插入了一个字段,A再读这个表就发现字段从4个变成了5个。
- 更新丢失
- 两个事务同时选择同一行进行更新。
4. 事务隔离性的隔离级别
-
读未提交(Read uncommitted)
- 能够读取到没有被提交的数据,所以很明显这个级别的隔离机制无法解决脏读、不可重复读、幻读中的任何一种,因此很少使用
-
读已提交(read committed)
- 能够读到那些已经提交的数据,自然能够防止脏读,但是无法限制不可重复读和幻读
-
可重复读(repeatable read)
- 在数据读出来之后加锁,类似"select * from XXX for update",明确数据读取出来就是为了更新用的,所以要加一把锁,防止别人修改它。REPEATABLE_READ的意思也类似,读取了一条数据,这个事务不结束,别的事务就不可以改这条记录,这样就解决了脏读、不可重复读的问题,但是幻读的问题还是无法解决
-
串行化(Serializable)
- 最高的事务隔离级别,不管多少事务,挨个运行完一个事务的所有子事务之后才可以执行另外一个事务里面的所有子事务,这样就解决了脏读、不可重复读和幻读的问题了
#查看当前隔离级别
SELECT @@transaction_isolation;
#设置隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
注意:不是事务隔离级别设置得越高越好,事务隔离级别设置得越高,意味着势必要花手段去加锁用以保证事务的正确性,那么效率就要降低,因此实际开发中往往要在效率和并发正确性之间做一个取舍,一般情况下会设置为READ_COMMITED,此时避免了脏读,并发性也还不错,之后再通过一些别的手段去解决不可重复读和幻读的问题就好了