数据库隔离级别

事务特性(ACID):

  1. 原子性(Atomicity):事务中的操作要么全部成功,要么全部失败,失败则不做任何操作,回滚到事务开始前
  2. 一致性(Consistency):一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。那转账举栗子,A账户和B账户之间相互转账,无论如何操作,A、B账户的总金额都必须是不变的。
  3. 隔离性(Isolation):多个用户的并发事务同时访问一个数据库时,一个用户的事务不应该被其他事务所干扰
  4. 持久性(Durability):事务一旦被提交,数据库中数据的改变是永久性的

不考虑隔离性,会出现以下几个问题:

  1. 脏读:读取到另一个事务未提交的数据,后果严重
  2. 不可重复度:一个事务的多次查询返回不同的结果,因为其它事务修改了数据(锁行解锁)
  3. 幻读:一个事务的多次查询返回不同的结果,因为其它事务插入了数据,与不可重复读的区别在于幻读读取的是一批数据,不可重复读读取的是一个数据(锁表解决)

四种隔离级别

  1. 读未提交(Read uncommitted):select语句不加锁,性能最强,一致性最差
  2. 读已提交(Read committed):Oracle默认,可避免脏读
  3. 可重复读(Repeatable read):MySQL默认,可避免脏读和不可重复读
  4. 序列化(Serializable):一致性最强,性能最差

悲观锁和乐观锁

由于高并发的需求,一般使用Read committed,而对于可能出现的问题,用悲观锁和乐观锁来解决

悲观锁

总是认为别人会修改,所以每次拿数据都会上锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。synchronized和ReentrantLock就是java中独占锁的代表。悲观锁适用于多写的场景。

乐观锁

总是认为别人不会修改,所以不会上锁,但是在更新时会根据版本号机制判断在此期间别人有没有去更新这个数据。乐观锁适用于多读的场景。

  1. 版本号机制
    一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。

  2. CAS算法
    即compare and swap(比较与交换),是一种有名的无锁算法。无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。CAS算法涉及到三个操作数

    需要读写的内存值 V
    进行比较的值 A
    拟写入的新值 B
    当且仅当 V 的值等于 A时,CAS通过原子方式用新值B来更新V的值,否则不会执行任何操作(比较和替换是一个原子操作)。一般情况下是一个自旋操作,即不断的重试。

posted @ 2021-03-14 12:12  Hy·  阅读(113)  评论(0)    收藏  举报