先来说说自己对事务的理解。
首先自己对事务的理解就是数据库中一个个完成的事件,我们在每次执行数据库的操作的时候,其实就是完成了一个事务,其实我们在平时使用数据库的时候,就已经在使用事务了。因为数据库默认是自动commit的,所以我们每执行一次操作,便会自动提交事务。所以这里的重点其实是对事务的理解。以及手动commit事务的一些用法以及其作用。
首先是事务的ACID特性
即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)
原子性指事务中的操作要么全部完成,要么全部失败撤销
一致性指事务中的操作都是在逻辑上正确的。
隔离性指多个事务之间不互相干扰,并发的事务之间要相互隔离。
持久性是指事务一旦提交,对数据库的操作就是永久性的。
事务的使用
想要控制事务的话,就需要关闭自动提交,这里有两种不同的方式来控制
首先是start transaction
它的意义是开始一个事务,在这个语句之后的操作都属于这个事务之内的,只有在commit之后这些数据才会生效,而使用rollback后就会回滚。回到start transaction语句之前的状态。
另一种就是set autocommit=0
使用这个语句之后就会将当前的模式转换为手动提交,在这之后的所有sql语句,都需要commit之后才会永久性的提交
这里需要注意的是两者的差别,start transaction是不管之前是否设置set autocommit,它都会开始一个手动提交的新事务,直到commit之后,才会生效,rollback之后就会回滚。在commit或者rollback之后,autocommit会自动还原到start transaction之前的状态。
在事务中还可以通过插入保存点来还原到保存点之前的状态,创建保存点的方法是SAVEPOINT point_name
删除是RELEASE SAVEPOINT point_name
回到保存点之前的状态是ROLLBACK TO SAVEPOINT point_name
例如之前作业里的表,我们查询分数

新建事务,对分数进行两次修改,并在中间设置存档点并返回存档点


接下来是事务当中概念较难理解的隔离性
首先,需要了解没有隔离性所会发生的几种问题
1、脏读(Dirty Read)
一个事务处理过程里读取了另一个未提交的事务中的数据
2、不可重复读(NonRepeatable Read)
对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询的间隔期间,另外一个事务修改并提交了该数据
3、幻读(Phantom Read)
在一个事务中读取到了别的事务插入的数据,导致前后不一致
在事务中有四个隔离级别,它们对这3种问题的解决方法用一张图来展示

当需要查看当前事务的隔离性是哪个等级的时候,可以使用SELECT @@transaction_isolation命令来查看

要修改当前事务的隔离性等级的时候,使用
SET session TRANSACTION ISOLATION LEVEL 隔离等级
如

我们来实际测试一下它的隔离性
我使用了之前作业里的score表
首先新建两个事务
我们在这个事务中查询分数

在第二个事务中将所有的分数都加上了20

再次查询,发现并没有查询到事务2中所做的改变

查询隔离性

发现系统默认的是REPEATABLE READ, 因为这种隔离方式不支持脏读,所以没有办法读取到事务2中的改变
我们重新开始一个事务,并将隔离等级改为READ UNCOMMITED

再继续新建事务2,修改表中数据

这次再在事务1中查询,发现可以查询到变化了

接下来还可以尝试不可重复读的效果
在事务1中将隔离等级设置为REPEATABLE READ,并查询成绩

在事务2中修改值并提交,查看到值已改变

再回到事务1中查询,发现并没有随着变化

在事务1中再次执行成绩加20的操作,并查看值

mysql中事务隔离级别为serializable时会锁表,插入记录会显示报错,因此不会出现幻读的情况,这种隔离级别并发性极低,开发中很少会用到。
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。
网友评论