事务的四大特性
1 原子性:
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚
2 一致性:
数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态
例子:拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
3 隔离性:
当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
4 持久性:
指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作
5 悲观锁和乐观锁
5.1 悲观锁
总是假设最坏的情况,每次读取数据的时候总会觉得别人会修改,简直是一种迫害妄想症。
所以每次取数据的时候都会加锁,这样其他人想取这个数据的时候就会被阻塞。很多传统的关系型数据库就用了悲观锁,
比如行锁、表锁、读锁、写锁等。Java中的synchronized、ReentranLock和C#中lock关键字都是悲观锁思想的实现。
这种锁是一种独占锁,可以保证数据的准确性,在写操作比较多的情况下使用悲观锁就比较合适。
5.2 乐观锁
总是假设最好的情况,每次读取数据的时候总会觉得别人不会修改,也不会上锁,感觉有点傻傻的。
但是在更新的时候会判断一下在操作的期间数据有没有被其他人修改过,
一般使用的机制有版本号和CAS(即Compare and Swap)。乐观锁适用于读多的情况,可以大幅提高吞吐量(我做的项目中涉及到这个乐观锁,嘿嘿)
5.3 版本机制
加个Version字段,每次操作根据对应version字段判断前后是否一致,若不一致就重写读取再做计算写入数据
5.4 CAS算法:
。CAS算法需要用到三个操作数:
需要读写的内存值V
进行比较的值A
更改后的新值B
流程是先比较V和A,只要当V和A的值相等时才将B写入内存,否则不执行任何操作。
比较和替换是一个原子操作(硬件级别),也是一个自旋操作,失败后会不断地重试,所以这个对CPU的开销很大。
还有就是会存在ABA问题,即如果V的值本来是A,后来变成B,后来又变成了A,那CAS进行检查的时候发现它没有变化,但是实质上它已经发生了改变。
总结
悲观锁能绝对保证数据安全,对一些安全性要求很高的场景还是要使用悲观锁;
乐观锁是一种无锁的实现,基本思想都是通过先比较后更新;
版本控制的思想可以用在很多地方,比如MySql中MVCC就是用事务ID为依据实现可重复读的事务隔离机制。
参考博客:
https://www.cnblogs.com/dwxt/p/8807981.html
https://blog.csdn.net/paolei/article/details/105707411
参考公众号:
v