一、什么是事务
- 传统理解mysql中的一次操作过程(sql 执行)是一次事务;
- 那么多个线程,同时操作mysql中的数据(同一条数据,一个范围内的数据)就叫做并发事务;
- 数据库层面使用不同的事务隔离级别来进行并发事务的控制,不同的隔离级别是因为数据库中内部锁机制的使用方式不同,例如有的是在select 完成之后立马释放锁,有的是在整个事务commit之后释放锁。
二、关于ACID
- 原子性:事务可以简单理解为一次数据库操作,也是执行sql的过程,要么完整执行,要么干脆不执行,整个执行结果要么全部成功,要么全部失败。
- 一致性:A有100块钱,转1块钱给另外一个帐户,还有99块钱,在整个事务执行过程中,钱数总是100块,不会变,这就是一致性。
- 隔离性:事务执行过程中相互隔离,不会相互直接产生影响。意思是多个事务并发执行的话,结果应该与多个事务串行执行效果是一样的。但并发情况下要考虑性能,所以就需要在隔离性上做些手教,也就是制定不同的隔离级别达到不同的并发性能。
- 持久性:事务每一次的执行结果都应该持久化存储到数据库中(磁盘数据)。
三、事务的隔离级别
1.1 为什么需要隔离级别
- 四个特效隔离性的体现。
- 对不同并发事务应用场景提供不同解决方案。解决方案本质,加锁。
1.2 数据库中的几种隔离级别
- read uncommited 读未提交:该隔离级别指即使一个事务的更新语句没有提交,但是别的事务可以读到这个改变。极易出错,没有安全性可言,基本不会使用。
- red commited 读已提交:指一个事务只能看到其他事务已经提交的更新,看不到未提交的更新,消除了脏读,这种隔离级别也支持不可重复读,即同一个 select 可能得到不同的结果。这是大多数数据库的默认隔离级别,如Oracle,SqlServer。
- repeatable read 可重复读:这是 MySQL 默认的隔离级别,它确保同一个事务在并发读取数据时,会看到同样的数据行。不过理论上会导致另外一个问题,【幻读】。 幻读:相同的条件查询一些数据,然后其他事务【新增】或者是【删除】了该条件的数据,然后导致读取的结果不一样多。InnoDB 存储引擎通过多版本控制(MVCC)机制解决了该问题。
- serializable 序列化读:思是说这个事务执行的时候不允许别的事务并发写操作的执行.完全串行化的读,只要存在读就禁止写,但可以同时读,消除了幻读。这是事务隔离的最高级别,虽然最安全最省心,但是效率太低,一般不会用。
1.3 不同隔离级别带来的数据操作问题
- 脏读:读取了前一个事务未提交的或者是回滚的中间状态的数据
- 不可重复读:同样的 select 查询,但是结果不同,过程中有事务更新了原有的数据
- 幻读:两次查询的结果数量不一样,过程中有事务新增或者是删除数据
1.4 数据库中的锁
- 共享锁(share locks简称S锁):又称之为读锁,简称S锁,当事务对数据加上读锁后,其他事务只能对该数据加读锁,不能做任何修改操作,也就是不能添加写锁。只有当数据上的读锁被释放后,其他事务才能对其添加写锁。共享锁主要是为了支持并发的读取数据而出现的,读取数据时,不允许其他事务对当前数据进行修改操作,从而避免”不可重读”的问题的出现。
- 排他锁(Exclusivelocks检查X锁):又称为写锁,当事务对数据加上写锁后,其他事务既不能对该数据添加读锁,也不能对该数据添加写锁,写锁与其他锁都是互斥的。只有当数据写锁被释放后,其他事务才能对其添加写锁或者是读锁。写锁主要是为了解决在修改数据时,不允许其他事务对当前数据进行修改和读取操作,从而避免脏读问题的产生。
- 更新锁(简称U锁):当被读取的对象将要被更新时,则升级为X锁,主要是用来防止死锁的。因为使用共享锁时,修改数据的操作分为两步,首先获得一个共享锁,读取数据,然后将共享锁升级为排它锁,然后再执行修改操作。这样如果同时有两个或多个事务同时对一个对象申请了共享锁,在修改数据的时候,这些事务都要将共享锁升级为排它锁。这些事务都不会释放共享锁而是一直等待对方释放,这样就造成了死锁。如果一个数据在修改前直接申请更新锁,在数据修改的时候再升级为排它锁,就可以避免死锁。