事务的四个特征(ACID)
- 原子性(atomicity):一个事务必须视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性。
- 一致性(consistency):数据库总数从一个一致性的状态转换到另一个一致性的状态。
- 隔离性(isolation):一个事务所做的修改在最终提交以前,对其他事务是不可见的。
- 持久性(durability):一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,修改的数据也不会丢失。
事务的隔离级别
不可重复读"意味着,在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。这是由于查询时系统中其他事务修改的提交而引起的。 例如:事务B中对某个查询执行两次,当第一次执行完时,事务A对其数据进行了修改。事务B中再次查询时,数据发生了改变
脏读意味着一个事务读取了另一个事务未提交的数据,而这个数据是有可能回滚的。
幻读是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
- 读未提交(Read uncommited)
在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。除非有特殊的应用场景,在一般应用中很少使用。 - 读已提交(Read Committed)
这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。 - 可重复读(Repeatable Read)
这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。 - 可串行化(Serializable)
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
四个隔离级别可能出现的问题:
悲观锁和乐观锁
悲观锁:顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。
乐观锁:顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。
悲观锁和乐观锁本质区别在于,一个对象被加锁,悲观锁是发现对象被加锁,直接切换上下文,等待对象解锁通知;而乐观锁不切换上下文,在那自旋,隔段时间主动询问是否解锁;
使用场景
悲观锁适用于并发争抢比较严重的场景;
使用
select * from table where id = 1;
可实现悲观锁;
乐观锁使用于并发争抢不太严重的场景;
使用
update table set name = #{test},version = version+1 where id = #{id} and version = #{version}
可实现乐观锁;
事务调优原则
- 减少锁的覆盖范围
myisam表锁--->Innodb行锁
原位锁(排他锁、读写锁)--->MVCC多版本 - 增加锁上课并行的线程数
读写分离,允许并发读取数据;可使用ReadWriteLock读写锁 - 选择正确的锁类型
悲观锁和乐观锁
MVCC多版本
待续~~~
切换上下文
目前流行的CPU在同一时间内只能运行一个线程,超线程的处理器可以在同一时间运行多个线程(包括多核CPU),Linux内核会把多核的处理器当作多个单独的CPU来识别。
一个标准的Linux内核可以支持运行50~50000个进程运行,对于普通的CPU,内核会调度和执行这些进程。每个进程都会分到CPU的时间片来运行,当一个进程用完时间片或者被更高优先级的进程抢占后,它会备份到CPU的运行队列中,同时其他进程在CPU上运行。这个进程切换的过程被称作上下文切换。过多的上下文切换会造成系统很大的开销。