事物有四个属性(ACID)
**原子性(Atomicity):**原子性是指在一个事务中,对数据库有多次修改,在事务提交的时候,它们就都执行,在事务回滚的时候,他们就都不执行。
**一致性(Consistency):**数据库在任何时候都保持着一致性状态,包括提交、回滚后,以及在开启事务之后也保持着一致性。一致性看的是修改前的数据和修改后的数据总和不变。举个例子:小明和小红两人各有1000元,小明给小红转账500元,转帐前小明和小红总共有2000元,转账小明500元加上小红的1500元还是2000元。因为有事务具有原子性,所以转账过程中,要么小明的钱减少同时小红的钱增加,要么小明和小红的钱都不变,小明和小红的钱总和还是2000元。
**隔离性(Isolation):**隔离性是指一个事务的执行不被其他事务干扰。隔离性是通过锁机制实现的,如果能确保不同事务之间没有任何干扰,可以调低隔离级别达到提高性能和并发的目的。
**持久性(Durability ):**持久性是指一旦事务被成功提交,这个事务所有的修改操作即使服务器挂掉也不会被改变。
谈到事务的隔离性,就会想到数据库的隔离级别,不同的隔离级别会对应一些问题。
脏读、不可重复读和幻读
**脏读(dirty read ):**如果一个事务对数据做了修改,但是还没有提交,这个时候其他人读到了这个被修改的数据,这种现象就是脏读。脏读只会发生在 read-uncommitted隔离级别。 如果回滚,脏读就非常危险。
**不可重复读(non-repeatable read ):**同一个事物中有两次查询,第一次查询到一个值,这个时候另一个事务修改了这个值并且提交了,然后第二次查询的时候发现这个值改变了,这就叫不可重复读。
**幻读(phantom):**同一个事务中先后两次做相同的查询,第一次查询之后另一个事务对这个数据做了新增操作,第二次查到的结果比第一次多了一行,好像出现了幻觉,这就是幻读。
幻读和不可重复读的区别:如果开启两个事务t1和t2,t2只修改了某个字段,t1两次查询到的结果不一致,表中的行并没有改变(row不变),则是不可重复读;如果开启两个事务t1和t2,t1做了新增或删除操作,t2查询到的结果不一致,而且表中的行发生了改变(row增多或减少),则是幻读。
数据库的隔离级别有四类
**读未提交(READ-UNCOMMITTED):**这个隔离级别最不靠谱,事务t1开启之后,这个时候如果有其他事务t2对某个数据做了修改,但是还没有提交,t1也能读到这个被修改了但是还未提交的数据。所以,通常这个隔离级别的事务只执行查询,而不执行插入、更新或删除操作。
**读已提交(READ-COMMITTED):**事务t1开启之后,如果这时候有其他事务t2对某个数据做了修改,而且已经提交,t1能读到t2修改过的数据。数据库设为READ-COMMITTED这个隔离级别可以避免脏读,不能避免不可重复读和幻读。事务开启之后,要对某个字段做修改或删除操作,其他事务需要等待;如果所有并发执行的事务都是做查询操作,则可以同时进行,相互之间不受影响。
**可重复读(REPEATABLE-READ):**事务开启后,所有的查询读到的是相同的数据。MySQL数据库默认使用的隔离级别,这个隔离级别可以避免脏读和不可重复读,不能避免幻读。事务开启之后,如果对某个字段做了修改、删除操作,或者上锁查询(select … for update或者select … lock in share mode (=select … for share (MySQL8.0.1之后使用)))的时候,其他事务需要等待,按开启事务的先后顺序执行。
**串行化(SERIALIZABLE):**一个事务开启之后,其他事务做增删改操作都需要等待。这个隔离级别最安全但是效率很低。
演示:
查看默认数据库默认隔离级别
读未提交(Read-uncommit)
首先设置为read-uncommit;
设置不能自动提交并开启事务
查询结果
左侧既没有commit也没有rollback,只是对数据做了修改,然后右侧查询id=2的数据就是修改了的结果(脏读)
读已提交(Read-committed)
设置为Read-committed隔离级别
t1修改了id=3的数据还未提交的时候,t2查询不到修改的值,当t1提交之后,t2查到了id=3被修改的值(可以避免脏读,不能避免不可重复读和幻读)
可重复读(repeatable-read)
设置为repeatable-read隔离级别
t1修改了id=2的数据,而且提交了,t2查询到的结果始终保持一致(避免脏读和不可重复读)
t1删除了id=4的数据,t2查询的结果明明是四条数据,当t2修改表中的数据的时候,却提示只有三条数据修改成功,查询发现被t1删除的那条数据没有任何改变。这就是幻读。repeatable-read不能避免幻读。
串行化(Serializable)
当隔离级别设置成serializable的时候,开启多个事务,只要有事务想修改表中的数据都不被允许