数据库一致性

数据库一致性特性

ACID

ACID是事务的四个特性,指的是atomicity,原子性;consistency,一致性;isolation,隔离性;durability,持久性

  1. A:atomicity,原子性
  2. C:consistency, 一致性
  3. I: isolation,隔离性
  4. D:durability,持久性
  5. 内部不一致性情况: 丢失修改\脏读\幻读\不可重复读

导致数据不一致原因

修改丢失、脏读、幻读、不可重复读

提交读、串行化隔离这些概念是什么

修改丢失

修改丢失是事务A和B先后更改数据数据x(假设初始是x0),但是在A未正式更改前,B已经读取了原先的数据x0,最后A更改后为x1,B更改的并不是A更新后的x1,而是更改的x0,更改后假设为x2,这时x2将x1覆盖了,相当于事务A针对x的更改丢失了

脏读

事务T1读取了T2更改的x,但是T2在实际存储数据时可能出错回滚了,这时T1读取的实际是无效的数据,这种情况下就是脏读

幻读

在T1读取符合某个条件的所有记录时,T2增加了一条符合该条件的记录,这就导致T1执行过程中前后读取的记录可能不一致,即T2之后读取时会多出一条记录。

不可重复读

是说在T1读取x时,由于中间T2更改了x,所以T1前后两次读取的x值不相同,这就是所谓的不可重复读

幻读和不可重复读区别
  1. 由于很多人(当然也包括本人), 容易搞混 不可重复读幻读, 这两者确实非常相似。
    • 不可重复读 主要是说多次读取一条记录, 发现该记录中某些列值被修改过。
    • 幻读 主要是说多次读取一个范围内的记录(包括直接查询所有记录结果或者做聚合统计), 发现结果不一致(标准档案一般指记录增多, 记录的减少应该也算是幻读)。(可以参考MySQL官方文档对 Phantom Rows 的介绍)
  2. 其实对于 幻读, MySQL的InnoDB引擎默认的RR级别已经通过MVCC自动帮我们解决了, 所以该级别下, 你也模拟不出幻读的场景; 退回到 RC 隔离级别的话, 你又容易把幻读不可重复读搞混淆, 所以这可能就是比较头痛的点吧!
    具体可以参考《高性能MySQL》对 RR 隔离级别的描述, 理论上RR级别是无法解决幻读的问题, 但是由于InnoDB引擎的RR级别还使用了MVCC, 所以也就避免了幻读的出现!

怎么解决数据不一致问题

MVCC

MVCC(Muti-Version Concurrency Control)是多版本并发控制的方法,一般在数据库关系系统中,实现对数据库并发访问。在MySQL中,MyISAM使用的是表级锁,而InnoDB使用的是行级锁,其中默认的隔离级别Repeat Read(可重复读)采用的是乐观锁,而乐观锁的实现采用的就是MVCC,其较低系统开销,才早就了InnoDB强大的事务处理能力。

MVCC主要解决读写互相不阻塞问题,每次更新都会产生一个新的版本,读的话可以读历史版本(某个时间点的快照),但MVCC不能解决幻读

MVCC实现机制

InnoDB的MVCC是通过在每行记录后面保存两个隐藏的列来实现的,分别保存这条行的创建时间和行的删除时间。这里的时间并不是实际的时间值,而是系统版本号(事务的ID)。事务开始时刻的系统版本号会作为事务的ID,每次执行一个新事务,系统版本号就会自动递增

InnoDB只会查找 创建事务ID<=当前事务ID && 删除事务ID > 当前事务ID

数据库各种锁

InnoDB 实现了两种类型的行级锁:
  • 共享锁 (也称为 S 锁,读锁):允许事务读取一行数据。

    可以使用 SQL 语句 select * from tableName where... lock in share mode; 手动加 S 锁。

  • 独占锁 (也称为 X 锁、写锁):允许事务删除或更新一行数据。

    可以使用 SQL 语句 select * from tableName where... for update; 手动加 X 锁。

S 锁和 S 锁是 兼容 的,X 锁和其它锁都 不兼容 ,举个例子,事务 T1 获取了一个行 r1 的 S 锁,另外事务 T2 可以立即获得行 r1 的 S 锁,此时 T1 和 T2 共同获得行 r1 的 S 锁,此种情况称为 锁兼容 ,但是另外一个事务 T2 此时如果想获得行 r1 的 X 锁,则必须等待 T1 对行 r 锁的释放,此种情况也成为 锁冲突

行锁的算法

InnoDB 存储引擎使用三种行锁的算法用来满足相关事务隔离级别的要求。

  • Record Locks

    该锁为索引记录上的锁,如果表中没有定义索引,InnoDB 会默认为该表创建一个隐藏的聚簇索引,并使用该索引锁定记录。

  • Gap Locks

    该锁会锁定一个范围,但是不括记录本身。可以通过修改隔离级别为 READ COMMITTED 或者配置 innodb_locks_unsafe_for_binlog 参数为 ON

  • Next-key Locks

    该锁就是 Record Locks 和 Gap Locks 的组合,即锁定一个范围并且锁定该记录本身。InnoDB 使用 Next-key Locks 解决幻读问题。需要注意的是,如果索引有唯一属性,则 InnnoDB 会自动将 Next-key Locks 降级为 Record Locks。举个例子,如果一个索引有 1, 3, 5 三个值,则该索引锁定的区间为 (-∞,1], (1,3], (3,5], (5,+ ∞)

你可能感兴趣的:(服务端,java,数据库)