MySQL事务隔离级别,并发事务问题
事务的并发冲突问题有以下几种
-
脏读:脏读即读到了其他事务未提交的数据。比如事务A第一次读取了一个数据,并对其进行了修改,事务B此时操作同一个数据,对其进行读取。然后事务A回滚撤销,事务B对其进行操作时,读到的都是脏数据
-
不可重复读:不可重复读即事务两次读取的数据不同。事务A先读取了一个数据,然后事务B进入,并对这个数据进行修改,然后提交事务。事务A再次读取时,读到的就是事务B修改后的数据,两次读到的数据不同
-
幻读:幻读即两次读取数据库时,查询结果的条数不同。事务A先查询数据库,比如查到了5条数据,然后事务B进入,并插入了一条数据,事务A再次查询,读到了6条数据。两次查询结果不同,就是幻读
幻读和不可重复读的区别就是,幻读是数据查询结果的条数不同,而不可重复读读的是数据的值不一样
MySQL事务隔离级别
-
读未提交:读未提交,即允许事务读取其他事务未提交的数据。如事务B对一个数据进行了修改,但是未提交事务,事务A可以读到这个脏数据。这是性能最高的但也是安全性最低的一种隔离级别
-
读已提交:这是大多数数据库默认的隔离级别(MySQL除外)。即只允许事务读取其他事务已经提交后的数据,事务A只能读到事务B已经提交后的数据。解决了脏读的问题
-
可重复读:这是MySQL的InnoDB引擎下的默认的事务隔离级别。在第一次快照读时会创建一个ReadView,记录当前活跃的事务id列表,可重复读下整个事务都复用这一个ReadView。InnoDB引擎中,快照读(普通Select)通过ReadView来保证看不到其他事务新插入的行。当前读(Select… for update)通过临键锁=记录锁+间隙锁锁住查询区间,阻止并发插入。InnoDB的可重复读隔离级别也几乎解决了幻读
-
串行化:不允许事务并发执行,事务只能按照顺序一个个执行,不会出现任何的事务并发问题。这是安全性最好但也是性能最差的一种隔离级别
CAP理论和BASE理论
CAP理论和BASE理论都是分布式系统设计理念
CAP,即一致性,可用性,分区容忍性,在保证P的前提下,C和A只能二者取其一,不能全有
-
一致性:即集群中的节点读取数据时,读到的数据都是最新的数据,所有节点读到的数据都是一致的。不会出现数据不一致的情况
-
可用性:即在集群中,如果出现了一部分的节点故障,为了保证可用性,系统依然会继续工作,请求在合理的时间内总能得到响应,故障节点也会返回数据,即使这个数据是过期的或者错误的。为了保证可用性,所有节点依旧能工作,只是会出现数据不一致
-
分区容忍性:系统出现网络分区时,仍然能够继续工作
例如Nacos和Eureka,就是经典的AP系统,即为了保障整个系统的高可用性,允许出现短暂的数据不一致。可以允许一些鼓掌节点返回过期的数据。像Zookeeper就是CP系统,为了保证数据的强一致性,Zookeeper在出现网络分区时,会直接使分区中少数节点直接不可用,不再接受任何服务。只有大多数节点可以正常使用。并且Zookeeper在选取leader时,也会暂停系统的使用,只为了保证数据的强一致性
BASE,即保证最终一致性的理念。BASE即基本可用,软状态,最终一致性
-
基本可用:系统出现故障时,可以通过降级返回兜底数据,而不是整个系统不可用
-
软状态:允许数据存在中间状态,并且中间状态不会影响系统对话提供服务
-
最终一致性:即允许数据短时间不一致,只需要最终一致即可
刚柔事务,2PC、3PC、TCC
事务分为刚性事务和柔性事务
-
刚性事务即一个事务要么全部成功,要么全部失败。不会出现任何的中间状态
-
柔性事务即事务除了成功和失败,还有一种软状态。例如在银行转账的过程中,用户A将钱转给了用户B,此时用户A的钱已经扣减,但是因为网络原因,用户B中的余额并没有增加,这就是一种软状态
在事务的分类中,2PC、3PC就是典型的强一致性的事务,而TCC则是最终一致性的事务
2PC分为以下几个阶段
1PC,事务协调者会向事务参与者提出执行事务,这是一个prepare阶段,事务参与者执行事务之后,并不会直接提交,而是返回给事务协调者一个yes。
2PC,如果所有的事务参与者都返回了yes,事务协调者才会发送一个commit命令,让事务参与者提交事务。如果其中有一个事务参与者返回了no,说明事务并没有完全执行成功,就会让所有的事务参与者都回滚
prepare后参与者只能干等协调者的指令,协调者如果挂到,参与者就会被卡住
3PC是在2PC前加了一个canCommit阶段
1PC,事务协调者会询问所有的事务参与者是否能执行事务。然后事务参与者会各自尝试执行事务,如果能则回复一个ack给事务协调者
2PC,如果所有的事务参与者都确认可以执行事务,事务协调者就会发送指令,让事务参与者开始执行事务。事务执行完后,也是不直接提交,而是告诉事务协调者,自己已经执行完事务了。如果有一个事务参与者觉得自己不能执行事务,事务协调者就会发送abort指令,让事务中断执行
3PC,如果所有的事务参与者都返回ack告知事务协调者事务已经执行完毕,事务协调者就会让所有的事务参与者进行事务的提交。但是如果在发送提交指令的时候,因为网络波动导致一些事务参与者没有收到提交指令,超出了超时时间。事务参与者就会直接提交事务。但是这就可能会出现错误,如实际上事务协调者想要回滚事务,但是却有参与者提交了事务。如果有一个事务参与者告知TC没有执行完事务,TC就会直接发送abort指令取消事务
TCC是把一个业务分成了三个阶段
-
Try:预留业务资源
-
Confirm:确认提交,执行业务操作,并且Confirm操作要保证幂等性,防止TC多次调用导致重复扣减
-
Cancel:取消操作,把Try操作预留的资源全都释放掉
TCC属于柔性事务,靠业务补偿保证最终一致性
ThreadLocal原理
ThreadLocal内部有一个ThreadLocalMap,每一个ThreadLocalMap都有一个Entry数组,这个Entry数组继承自一个弱引用类。key是对ThreadLocal的弱引用,value是强引用持有的泛型对象。每个Thread都有一份自己的Map,互不干扰
当ThreadLocal进行set方法时,会先找到关联的Thead对象。然后从ThreadLocalMap中找到对应的ThreadLocal对象,然后ThreadLocal对象对应的值就会被覆盖。如果map中出现了冲突,就会利用线性探测来找到下一个位置来将ThreadLocalset进去
当进行get方法时,也是类似于map的get方法,找到对应的TheadLocal对象,然后在获取到指定的值
但是如果在外部没有任何强引用引用ThreadLocal实例时,就会在下一次GC时,将ThreadLocal对象回收,但是因为Entry还持有着值的引用,所以值并不会被回收,且无法通过get方法获取到这个值,就会造成内存泄漏的问题。所以每次使用ThreadLocal对象时,都需要在最后调用remove方法主动释放引用的值对象,防止出现内存泄漏的问题
为什么非公平锁的吞吐量更大
公平锁,线程在获取锁时,先调用 hasQueuedPredecessors() 检查等待队列:只要队列里有前驱线程,即使锁此刻是空闲的,也拒绝获取,直接入队 park。释放锁时需要唤醒队头线程,而 park/unpark、线程阻塞唤醒涉及用户态/内核态切换和上下文切换,整体开销大,所以吞吐低
非公平锁,线程在获取锁时,都会先通过CAS尝试获取锁对象,如果成功获取到锁对象,则这个线程会直接占有锁对象。没有获取到锁对象的线程则会继续阻塞。而这个过程不涉及用户态和内核态的切换,因此会比公平锁的性能更高
网硕互联帮助中心





评论前必须登录!
注册