事务就是把一组操作打包到一起,执行的时候能够保证这一组操作之间是有一定的特性的,避免出现一些安全问题。因此这组操作就是要不就全部成功执行,要不就是全部失败。
在某些数据表中,根据业务的需要,要求一些操作是必须要绑定在一起,要不就全部成功,要不就全部失败。比如我们在银行操作转账时,你的账户余额减小和对方的账户余额增加是必须是绑定在一起的。如果中间出现异常就会导致所有的操作恢复原来的样子。
原子性是事务中的最重要特性,需要保证这组操作必须是原子的。若干个操作,要不就全部成功,要不就全部不执行。这里的不执行实际是如果说某个中间环节出错,就会把前面已经执行的步骤“回滚”回去。
执行事务的前后,必须保证数据始终处于一种合法的状态。这里的合法性指的是,如果某一列的数据取值范围是0-10,执行事务之后,这一列的取值范围还在0-10就是合法的,如果不在这个范围就是不合法的。
事务一旦执行完毕,数据的修改就是持久生效的,也就是数据写入到了磁盘中。
多个事务并发执行时,事务之间是不可以相互干扰的。
但是隔离和并发是两个完全相反的概念,前者是保证数据的准确性,后者是保证效率。因此隔离性就需要保证在满足数据准确的要求下,最大程度去提高并发的程度。
并发执行事务就会产生以下问题
1、脏读
举个简单的例子,老师们马上就要收作业了,你的同桌的作业已经写了一半了,你的作业才刚开始,你想要抄同学作业,但是你在抄的过程中没有注意到同桌修改了前面的作业,但是你已经抄了没有跟着他一起修改,那你抄到的作业就是脏读。
如果一个事务A正在修改数据,另一个事务B在读取这里的数据,事务B的读操作就属于脏读。因为事务A可能在提交之前,修改刚才事务B读取到的数据。
解决的办法:给写的操作加锁,直到写操作完成之后,再允许读。如果在写的过程中尝试读,就会阻塞。也就是你可以和同学约定好他写完一科之后告诉你,你再抄。
2、不可重复读
接着上面的说,上面我们解决了同桌在写的时候,你不能抄的问题,但是你在抄的时候,同桌还是可以修改自己的作业。此时你就会发现刚才抄的作业怎么和同桌的不一样了。这就出现了不可重复读的问题。
一个事务A在执行的过程中,事务B两次读取到的数据是不相同的。
解决的办法:给读操作也加锁。
写加锁指的是修改代码的时候,不可以读。读加锁指的是读操作的时候,也不可以写。
3、幻读
一次事务执行的过程中,多次读取的结果集是不一样的。虽然在读操作加了锁,不可以修改,但是可以新增和删除元素。
解决的办法:串行化
隔离性的要求越高,并发程度就越低,数据就越可靠,效率也就越低
1、read uncommitted:允许读取为提交的数据(会存在脏读的问题)
2、read committed:只允许读取已经提交的数据,写操作加锁(解决了脏读问题,但是存在不可重复读的问题)
3、repeatable(默认的隔离级别):读操作加锁(解决了不可重复读的问题,但是存在幻读的问题)
4、serializable:严格串行化执行(隔离级别最高,并发程度最低,解决幻读问题)