1.存储引擎的使用
2.为什么用事务
3.事务的特点
4.脏读,幻读,可重复读和不可重复读
5.隔离级别
6.事务的控制语句
1.存储引擎的使用:
mysql 中,存储引擎使用 InnoDB,对事务有良好的支持(mysql默认的引擎就是InnoDB)
查看表是什么引擎:SHOW TABLE STATUS WHERE name = ‘table_name’ \G;
mysql> show table status where name='zje'\G;
*************************** 1. row ***************************
Name: zje
Engine: InnoDB
Version: 10
Row_format: Dynamic
Rows: 8
Avg_row_length: 2048
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: NULL
Create_time: 2017-02-13 14:26:22
Update_time: 2017-02-13 18:07:18
Check_time: NULL
Collation: latin1_swedish_ci
Checksum: NULL
Create_options:
Comment:
1 row in set (0.02 sec)
上面可以看到引擎为InnoDB
创建表时把表设置为 InnoDB引擎:create table aaa(id int)engine = innodb; //创建aaa表,引擎设置为innodb
2.为什么用事务:
事务是应用多个用户使用数据库的情况的。以银行为例。
有用户A要把500块钱转给用户B,那就存在几个步骤:
1.检查A的账户是否多于500块钱。
2.A的账户减少500块钱。
3.B的账户增加500块钱
但万一 A扣钱之后,B加钱之前,系统崩溃了,那就会造成500块无端端没了。这就需要用到事务。
3.事务的特点:
事务必须拥有 4个特性,分别是:ACID
A(原子性):表示一个事务里面的操作要么全部执行成功,要么全部回滚,不可以只成功执行一部分。
C(一致性):一个事务的执行不应该破坏数据库的完整性约束。
I(隔离性):不同事务之间的行为互不影响,但实际上不同事务也会有一定的影响,影响的程度在于隔离级别,隔级别度等等说。
D(持久性):事务提交后的数据,即使系统崩溃,也不会丢失。
4.脏读,幻读,可重复读和不可重复读
脏读:表示一个事务读取了另一个未提交的事务修改的数据,而这个数据是有可能回滚的。
幻读:表示当某个事务在读取某个范围的值时,有另一事务在这个范围内插入一个新记录时,之前的事务再次读取这个范围的值,会读到插入的新纪录。
然后mysql的InnoDB引擎的间隙锁已经解决了幻读问题。
不可重复读:当事务A在查看id为1的score数据(select score from table where id = 1),例如score = 100,事务A暂时还没提交,若此时事务B对id=1的,score数据进行修改(update table set score=0 where id =1),把score修改为0(提交),此时事务A若再次读取score数据,读到的不是100,而是会显示0。
可重复读:与不可重复读相反,当事务A读取数据时,事务B修改了数据,事务A再读,还是会是原本的数,绝不会读到被修改的数据。但若是事务B把一个数据的id改为1,
事务A虽看不到变化,但如果事务A插入新数据,并把id号设置为1,则会发生错误,因为id=1的数据已经存在。
5.隔离级别
隔离级别是对应事务的隔离性,一共有4个隔离级别,分别表示不同的隔离程度:
1.READ UNCOMMITTED(未提交读)
2.READ COMMITTED(提交读)
3.REPEATABLE READ(重复读)
4.SERIALIZABLE(可串行化)
1.READ UNCOMMITTED(未提交读)
容易发生脏读,属于隔离级别比较低的,一般不常用
2.READ COMMITTED(提交读)
不会出现脏读。事务A在读数据时,恰巧事务B在修改数据,但必须先等到事务B提交后,事务A才能读到被B修改的数据。但这就形成了不可重复读。
3.REPEATABLE READ(可重复读)
此隔离级别解决了不可重复读的问题。变成可重复读。这是mysql默认的隔离级别。
4.SERIALIZABLE(可串行)
此隔离级别是隔离程度最高的。事务在执行中的时候,就不能读数据。唯有没有任何事务处理数据时,用户才能读数据。
注意:隔离级别越高,并发效果越低。可串行隔离级别是没有并发的。
6.事务的控制语句
autocommit:
autocommit是mysql中的一个全局变量,用于控制事务是否自动提交。默认情况给下autocommit=1,表示是自动提交执行,即会自动加上commit语句。
例如 select * from zje; 回车后,就会自动加上commit提交。而我们要写拥有多个SQL语句的事务,就要显式地开始一个事务。或设置autocommit=0 表示事务要手动加上commit才会提交执行。
在autocommit=0的情况下,对数据的修改,只要不commit,那么数据的修改自己看到,当commit了之后,才会对数据库的数据进行真正的修改。
查看 autocommit 的值: select @@autocommit;
修改 autocommit的值:set @@autocommit = 0; //或set @@autocommit = 1;
显式开始事务:
四个重要语句:
START TRANSACTION; 或 BEGIN; //开始事务
ROLLBACK; //回滚事务
SAVEPOINT p1; //设置一个断点,名为p1,可以用ROLLBACK TO savepoint p1;来回滚到p1处。
COMMIT; //提交事务
在mysql命令行默认的形式是,提交一个SQL语句,就会自动执行commit,相当于一个SQL语句就是一个事务,因为默认下 autocommit = 1;如果我们需要开始一个由多条SQL语句组成的事务,则要显示地开始事务。如果是autocommit=0,则不需要START TRANSATION /BEGIN ,在输入commit之前,全部的SQL语句都是一个事务。
下面给出当 autocommit=1的情况下事务的使用:
mysql> select * from eva;
Empty set (0.03 sec)
mysql> begin;
Query OK, 0 rows affected (0.01 sec)
mysql> insert eva(id,value) values(1,100);
Query OK, 1 row affected (0.01 sec)
mysql> rollback;
Query OK, 0 rows affected (0.03 sec)
mysql> commit;
Query OK, 0 rows affected (0.01 sec)
mysql> select * from eva;
Empty set (0.01 sec)
上面的代码在执行事务时,往eva表插入了一个数据,但是又执行了rollback,所以再次select eva表时,还是空表
mysql> select * from eva;
Empty set (0.01 sec)
mysql> begin;
Query OK, 0 rows affected (0.01 sec)
mysql> insert into eva(id,value) values(1,100);
Query OK, 1 row affected (0.01 sec)
mysql> insert into eva(id,value) values(2,200);
Query OK, 1 row affected (0.01 sec)
mysql> commit;
Query OK, 0 rows affected (0.03 sec)
mysql> select * from eva;
+------+-------+
| id | value |
+------+-------+
| 1 | 100 |
| 2 | 200 |
+------+-------+
2 rows in set (0.01 sec)
上面的代码并没有用rollback回滚,所以当commit提交事务时,就会把修改提交到mysql,进行真正的数据插入。
mysql> select * from eva;
+------+-------+
| id | value |
+------+-------+
| 1 | 100 |
| 2 | 200 |
+------+-------+
2 rows in set (0.01 sec)
mysql> begin;
Query OK, 0 rows affected (0.02 sec)
mysql> delete from eva where id = 1;
Query OK, 1 row affected (0.01 sec)
mysql> savepoint p1;
Query OK, 0 rows affected (0.01 sec)
mysql> delete from eva where id=2;
Query OK, 1 row affected (0.02 sec)
mysql> rollback to savepoint p1;
Query OK, 0 rows affected (0.01 sec)
mysql> commit;
Query OK, 0 rows affected (0.03 sec)
mysql> select * from eva;
+------+-------+
| id | value |
+------+-------+
| 2 | 200 |
+------+-------+
1 row in set (0.02 sec)
上面的代码展示了 savepoint 的使用,由代码可以看出,eva表一开始是有2组数据的,分别是id=1和id=2的数据。
而随后删除id=1的数据后,我们加入了一个断点p1,然后再删除id=2的数据,然后回滚到p1处,可以看出最后commit后查看eva表,只删除了id=1的数据。