天天看点

关系型数据库保证数据完整性和一致性的方法

对于数据库来说,关系型数据库对于保证数据完整性和一致性方面表现是最好的!

数据的完整性

完整性分类 具体描述 如何保证
实体完整性 每个实体都是独一无二的 主键 / 唯一索引(唯一约束)
参照完整性(引用完整性) 子表中不能有父表中没有的数据 外键
域完整性 数据都是有效的 数据类型和长度、非空约束、默认值约束、检查约束

数据的一致性:

数据的一致性通过事务实现 —> 一系列的对数据进行的不可分割的操作,要么全做,要么全部做

事务的ACID特性:

事物的特性 描述
Atomicity(原子性) 不可分割
Consistency(一致性) 事务前后数据状态保持一致
Isolation(隔离性) 多个并发的事务不知道彼此的中间状态
Duration(持久性) 事务完成后,对数据的修改要持久化

并发事务访问数据可能产生五大类的问题:

  • 第一类丢失更新
  • 第二类丢失更新
  • 脏读(读脏数据)
  • 不可重复读
  • 幻读

如何解决这五类问题

  • 单版本并发控制 - 锁 - 悲观锁 - 性能太差
  • 多版本并发控制(MVCC)- 乐观锁 - 性能更好 - 需要冗余字段来支持

直接操作锁非常的麻烦,我们可以通过设置事务隔离级别的方式,让数据库自动选择合适的锁机制来保护数据。

事物的隔离级别 特点
read uncommitted 可以读到脏数据
read committed Oracle默认的隔离级别 -不能避免不可重复读现象,但不会读到脏数据
repeatable read 避免不可重复读现象( MySQL默认的事物隔离级别) 另一个事物更新数据,刚才查到的是什么,现在还是什么(查询事物没有提交和回滚之前都可以重复读)
serializable 此种方法不会出现并发数据的问题,但是效率地下,不建议使用

MySQL如何查看和修改事务隔离级别(transaction —> tx)

功能 方法
查看事物隔离级别 select @@tx_isolation
修改事物隔离级别 set session transaction isolation level read committed

在Linux环境下验证不同事物隔离级别的特性所需要使用到的命令

事物过程 相关命令
开事物 begin; / start transaction;
提交事物 commit;
回滚事物 rollback;(未提交之前,取消前面的操作,如更新或删除操作)

linux下面验证的场景举例:

数据库连接:mysql -u root -p

第一个实验场景:读脏数据

事物A:
begin;
update tb_emp set sal=2800 where eno = 1359;
事物B:
set session transaction isolation level read committed;
begin;
select * from tb_emp;       --->读脏数据
commit;
事物A:
rollback;
           

第二个实验场景:不可重复读

事物B:
set session transaction isolation level read committed;
begin;
select * from tb_emp where sal<3000;
事物A:
begin;
update tb_emp set sal=3800 where eno=1359;
commit;
事物B:
select * from tb_emp where sal<3000; --->没有1359对应的记录了,不可重复读
commit;
           

第三个实验场景:可以重复读

事物B:
set session transaction isolation level repeatable read;
begin;
select * from tb_emp where sal<3000;
事物A:
begin;
update tb_emp set sal=3800 where eno=1359;
commit;
事物B:
select * from tb_emp where sal<3000; --->还可以读到最开始使用select使用此命令读到的内容
commit;