1.事务的概念:
事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起,并用形如事务开始和事务结束之类的语句来界定。事务由事务开始和事务结束之间执行的全体操作组成。
2.事务的特性ACID:
Automicity:原子性,事务所引起的数据库操作,要么都完成,要么都不执行;
事务必须始终保持系统处于一致的状态,不管在任何给定的时间并发事务有多少。
如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。
Durability:一旦事务成功完成,系统必须保证任何故障都不会引起事务表示出不一致性;
3.隔离级别说明:
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE
read uncommitted, read committed, repeatable read,serializable 这4种隔离级别的不同特点。
1. Read uncommitted(未提交读)
所谓Read uncommitted ,就是指可以读取未提交的数据。两个事务T1和T2,T1执行的操作在事务未提交前,对T2是可见的。
2. Read committed(已提交读)
所谓Read committed ,就是指只能读取提交后的数据。两个事务T1和T2,T1执行的操作在未提交前对T2是不可见的,提交后数据库的变化,对T2事务是可见的。
3. Repeatable read(可重复读)
可重复读可以防止脏读和不可重复读的发生,但仍然会出现幻象。两个事务T1和T2,T1执行的操作,在T1未提交和T2未提交是均不可见的。在两者都提交后,T2可以查看到T1对数据库的修改。这是mysql默认的隔离级别。
4. serializable(可串行化)
所谓serializable,就是指不允许多个事务同时进行。 如有两个事务T1,T2,如果T1在操作表的话,T2不可以对标进行查询等操作,直到T1提交事务才会释放掉锁。
4.隔离级别实验
mysql> show variables like 'tx_%'
-> ;
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation |REPEATABLE-READ |
+---------------+-----------------+
1 row in set (0.00 sec)
另开启一个终端,现在有终端1和终端2;在终端1终端2分别执行下列语句。
隔离级别为read-uncommitted,未提及时就可以读取到数据。
mysql> set tx_isolation='read-uncommitted';
Query OK, 0 rows affected (0.00 sec)
mysql> select @@tx_isolation;
+------------------+
| @@tx_isolation |
+------------------+
| READ-UNCOMMITTED |
+------------------+
1 row in set (0.00 sec)
mysql> select * from tb;
+------+------+
| id | age |
+------+------+
| 1 | 20 |
| 2 | 30 |
+------+------+
2 rows in set (0.00 sec)
在两个终端同时开启事务。
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
开启事务之后的操作有所不同了。下面分别指明终端1终端2的操作。
终端1
update tb set age=19 where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed:1 Warnings: 0
mysql> select * from tb;
+------+------+
| id | age |
+------+------+
| 1 | 19 |
| 2 | 30 |
+------+------+
2 rows in set (0.00 sec)
终端2
mysql> select * from tb;
+------+------+
| id | age |
+------+------+
| 1 | 19 |
| 2 | 30 |
+------+------+
2 rows in set (0.00 sec)
可以看出,在同一个事务中,看到的却是修改后的数据。
终端1和2都提交以结束事务
mysql> commit
-> ;
Query OK, 0 rows affected (0.00 sec)
一样,在终端1和终端2上修改隔离级别位read-committed(只有提交后才可以读取)
mysql> set tx_isolation='Read-committed';
Query OK, 0 rows affected (0.00 sec)
mysql> select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| READ-COMMITTED |
+----------------+
1 row in set (0.00 sec)
终端1和2都开启事务;
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
终端1执行插入操作
mysql> insert into tb values(1,4);
Query OK, 1 row affected (0.00 sec)
mysql> select * from tb;
+------+------+
| id | age |
+------+------+
| 1 | 4 |
+------+------+
1 row in set (0.00 sec)
终端2显示为空
mysql> select * from tb;
Empty set (0.00 sec)
终端1提交
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
终端2才能显示结果
mysql> select * from tb;
+------+------+
| id | age |
+------+------+
| 1 | 4 |
+------+------+
1 row in set (0.00 sec)
在终端1和2修改隔离级别并开启事务。
mysql> set tx_isolation='Repeatable-read';
Query OK, 0 rows affected (0.00 sec)
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.00 sec)
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
终端1插入数据
mysql> insert into tb values(3,6);
Query OK, 1 row affected (0.00 sec)
终端2查看不到
mysql> select * from tb;
+------+------+
| id | age |
+------+------+
| 1 | 4 |
| 2 | 5 |
+------+------+
2 rows in set (0.00 sec)
终端1提交
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
终端2查看不到
mysql> select * from tb;
+------+------+
| id | age |
+------+------+
| 1 | 4 |
| 2 | 5 |
+------+------+
2 rows in set (0.00 sec)
终端2提交
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
终端2查看到了
mysql> select * from tb;
+------+------+
| id | age |
+------+------+
| 1 | 4 |
| 2 | 5 |
| 3 | 6 |
+------+------+
3 rows in set (0.00 sec)
终端1和终端2都设置成串行化,开启事务
mysql> set tx_isolation='serializable'
-> ;
Query OK, 0 rows affected (0.00 sec)
终端1执行更新操作
mysql> select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| SERIALIZABLE |
+----------------+
1 row in set (0.00 sec)
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> update tb set age=4 where id=1;
Query OK, 0 rows affected (0.00 sec)
终端2执行查询操作
mysql> select * from tb;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restartingtransaction
这里的查看竟然无法执行。被加上了锁。然而,一旦终端1commit后,2就可以查看了
mysql> select * from tb;
+------+------+
| id | age |
+------+------+
| 1 | 4 |
| 2 | 5 |
| 3 | 6 |
| 4 | 7 |
+------+------+
4 rows in set (6.80 sec)
5.事务的执行实验
START TRANSACTION:启动
COMMIT: 提交
ROLLBACK: 回滚
默认的myisam是不支持事务的,我们需要修改为innodb,可以通过修改my.cf文件,也可以通过命令修改全局变量。rollback是全部回滚,rollback to s1是回滚到指定的savepoint s1处。commit提交后事务结束。
mysql> show engines;
+------------+---------+------------------------------------------------------------+--------------+------+------------+
| Engine | Support | Comment | Transactions | XA | Savepoints |
+------------+---------+------------------------------------------------------------+--------------+------+------------+
| MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO |
| CSV | YES | CSV storage engine | NO | NO | NO |
| MyISAM | DEFAULT | Default engine as of MySQL 3.23 with great performance | NO | NO | NO |
| InnoDB | YES | Supports transactions, row-level locking, and foreign keys | YES | YES | YES |
| MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO |
+------------+---------+------------------------------------------------------------+--------------+------+------------+
5 rows in set (0.00 sec)
mysql> show variables like '%storage_engine%';
+----------------+--------+
| Variable_name | Value |
+----------------+--------+
| storage_engine | MyISAM |
+----------------+--------+
1 row in set (0.00 sec)
mysql> set storage_engine = InnoDB;
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like '%storage_engine%';
+----------------+--------+
| Variable_name | Value |
+----------------+--------+
| storage_engine | InnoDB |
+----------------+--------+
1 row in set (0.00 sec)
mysql> create table tb (id int(4));
Query OK, 0 rows affected (0.01 sec)
mysql> select * from tb;
Empty set (0.00 sec)
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into tb values (1);
Query OK, 1 row affected (0.00 sec)
mysql> select * from tb;
+------+
| id |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
mysql> savepoint s1;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into tb values (2);
Query OK, 1 row affected (0.00 sec)
mysql> select * from tb;
+------+
| id |
+------+
| 1 |
| 2 |
+------+
2 rows in set (0.00 sec)
mysql> rollback to s1;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from tb;
+------+
| id |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
mysql> rollback
-> ;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from tb;
Empty set (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)