这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战
事务的特性:
原子性:一个事务不可在分割,要么都执行,要么都不执行
一致性:一个事务执行会使数据从以一个一致状态切换到宁外一个一致状态
隔离性:一个事务的执行不受其他事务的干扰
持久性:一个事务一旦提交,则会永久的改变数据库的数据
执行事务
步骤一:
开启事务
set autocommit=0;
步骤二:
编写事务中的sql语句
步骤三:
结束事务:
commit——提交事务
rollback——回滚事务
事务的隔离级别
对于同时运行的多个事务,当这些事务访问数据库中相同的数据时,如果没有采取必要的隔离机制,就会导致各种并发问题:
- 脏读:对于两个事务T1,T2,T1读取了已经被T2更新但还没有被提交的字段.之后,若T2回滚,T1读取的内容就是临时且无效的.
- 不可重复读:对于两个事务T1,T2,T1读取了一个字段,然后T2更新了该字段.之后,T1再次读取同一个字段,值就不同了.
- 幻读:对于两个事务T1,T2,T1从一个表中读取了一个字段,然后T2在该表中插入了一些新的行.之后,如果T1再次读取同一个表,就会多出几行.(凭空出现或者减少数据)
数据库提供的4种事务隔离级别:
| 隔离级别 | 描述 |
|---|---|
| READ UNCOMMITTED(读未提交数据) | 允许事务读取未被其他事物提交的变更.脏读,不可重复读和幻读的问题都会出现 |
| READ COMMITED(读已提交数据) | 只允许事务读取已经被其它事务提交的变更.可以避免脏读,但不可重复读和幻读问题任然可能会出现 |
| REPEATABLE READ(可重复读) | 确保事务可以多次从一个字段中读取相同的值.在这个事务持续期问,禁止其他事物对这个字段进行更新.可以避免脏读和不可重复读,但幻读的问题仍然存在. |
| SERIALIZABLE(串行化) | 确保事务可以从-一个表中读取相同的行.在这个事务持续期问,禁止其他事务对该表执行插入,更新和删除操作。所有并发问题都可以避免,但性能十分低下 |
具体演示
首先开启两方命令窗口模拟两个连接,这里为了辨认,设置成黑方、白方。
首先两方隔离级别设置为不可重复读:
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ |
+-------------------------+
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-UNCOMMITTED |
+-------------------------+
1 row in set (0.00 sec)
这时会出现脏读、不可重复读、幻读问题:
演示脏读问题:
黑方已更改数据但还未提交::
mysql> select * from test;
+----+--------+---------+
| id | name | balance |
+----+--------+---------+
| 1 | 张三 | 2500 |
| 2 | 李四 | 2500 |
+----+--------+---------+
2 rows in set (0.00 sec)
mysql> update test set name='lisi' where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
这时另一方看到的数据:
mysql> select * from test;
+----+--------+---------+
| id | name | balance |
+----+--------+---------+
| 1 | lisi | 2500 |
| 2 | 李四 | 2500 |
+----+--------+---------+
2 rows in set (0.00 sec)
黑方回滚:
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
白方看到的数据又恢复了原状
mysql> select * from test;
+----+--------+---------+
| id | name | balance |
+----+--------+---------+
| 1 | 张三 | 2500 |
| 2 | 李四 | 2500 |
+----+--------+---------+
2 rows in set (0.00 sec)
再两方隔离级别达到read commit时:
在同样的场景下另一方看到的情况,避免了脏读:
出现可重复读问题:在黑方提交事务后,白方在一次事务中再次查询,看到的结果不一样:
在隔离级别达到可重复读时
白方在黑方第一次更该数据时,看到的结果跟原来一样(避免了脏读),在黑方提交后任然看到一样的数据(避免了可重复读)
但同时还是避免不了幻读的问题:
白方插入一条数据后:
黑方明明是两条数据,但却有更改了三条的记录:
在两方隔离级别设置为串行化时:
一方插入数据,无效
直到一方提交后才会显示: