对于数据库来说,关系型数据库对于保证数据完整性和一致性方面表现是最好的!
数据的完整性
完整性分类 | 具体描述 | 如何保证 |
---|---|---|
实体完整性 | 每个实体都是独一无二的 | 主键 / 唯一索引(唯一约束) |
参照完整性(引用完整性) | 子表中不能有父表中没有的数据 | 外键 |
域完整性 | 数据都是有效的 | 数据类型和长度、非空约束、默认值约束、检查约束 |
数据的一致性:
数据的一致性通过事务实现 —> 一系列的对数据进行的不可分割的操作,要么全做,要么全部做
事务的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;