首页 > 数据库 >数据库的读现象浅析

数据库的读现象浅析

时间:2024-06-13 12:04:39浏览次数:11  
标签:事务 WHERE 数据库 修改 现象 Query 数据 浅析 SELECT

“读现象”是多个事务并发执行时,在读取数据方面可能碰到的状况。先了解它们有助于理解各隔离级别的含义。其中包括脏读、不可重复读和幻读。

脏读

脏读又称无效数据的读出,是指在数据库访问中,事务T1将某一值修改,然后事务T2读取该值,此后T1因为某种原因撤销对该值的修改,这就导致了T2所读取到的数据是无效的。

脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交(commit)到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。

举例说明:

在下面的例子中,事务2修改了一行,但是没有提交,事务1读了这个没有提交的数据。现在如果事务2回滚了刚才的修改或者做了另外的修改的话,事务1中查到的数据就是不正确的了。

事务一 事务二
/* Query 1 */

SELECT age FROM users WHERE id = 1;

/* will read 20 */
 
 
/* Query 2 */

UPDATE users SET age = 21 WHERE id = 1;

/* No commit here */

/* Query 1 */

SELECT age FROM users WHERE id = 1;
/* will read 21 */
 
 
ROLLBACK;

/* lock-based DIRTY READ */

在这个例子中,事务2回滚后就没有id是1,age是21的数据了。所以,事务一读到了一条脏数据。

不可重复读

不可重复读,是指在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。这是由于查询时系统中其他事务修改的提交而引起的。比如事务T1读取某一数据,事务T2读取并修改了该数据,T1为了对读取值进行检验而再次读取该数据,便得到了不同的结果。

一种更易理解的说法是:在一个事务内,多次读同一个数据。在这个事务还没有结束时,另一个事务也访问该同一数据。那么,在第一个事务的两次读数据之间。由于第二个事务的修改,那么第一个事务读到的数据可能不一样,这样就发生了在一个事务内两次读到的数据是不一样的,因此称为不可重复读,即原始读取不可重复。

举例说明:

在基于锁的并发控制中“不可重复读(non-repeatable read)”现象发生在当执行SELECT 操作时没有获得读锁(read locks)或者SELECT操作执行完后马上释放了读锁; 多版本并发控制中当没有要求一个提交冲突的事务回滚也会发生“不可重复读(non-repeatable read)”现象。

事务一 事务二
/* Query 1 */

SELECT * FROM users WHERE id = 1;
 
 
/* Query 2 */

UPDATE users SET age = 21 WHERE id = 1;

COMMIT;


/* in multiversion concurrency
control, or lock-based READ COMMITTED */

/* Query 1 */

SELECT * FROM users WHERE id = 1;

COMMIT;

/*lock-based REPEATABLE READ */
 

在这个例子中,事务2提交成功,因此他对id为1的行的修改就对其他事务可见了。但是事务1在此前已经从这行读到了另外一个“age”的值。

幻读

幻读是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,比如这种修改涉及到表中的“全部数据行”。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入“一行新数据”。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样.一般解决幻读的方法是增加范围锁RangeS,锁定检锁范围为只读,这样就避免了幻读。

幻读(phantom read)”是不可重复读(Non-repeatable reads)的一种特殊场景:当事务没有获取范围锁的情况下执行SELECT ... WHERE操作可能会发生“幻影读(phantom read)”。

举例说明:

当事务1两次执行SELECT ... WHERE检索一定范围内数据的操作中间,事务2在这个表中创建了(如INSERT)了一行新数据,这条新数据正好满足事务1的“WHERE”子句。

事务一 事务二
/* Query 1 */

SELECT * FROM users
WHERE age BETWEEN 10 AND 30;
 
 
/* Query 2 */

INSERT INTO users VALUES ( 3, 'Bob', 27 );

COMMIT;

/* Query 1 */

SELECT * FROM users
WHERE age BETWEEN 10 AND 30;
 

在这个例子中,事务一执行了两次相同的查询操作。但是两次操作中间事务二向数据库中增加了一条符合事务一的查询条件的数据,导致幻读。

解决方案

要想解决脏读、不可重复读、幻读等读现象,那么就需要提高事务的隔离级别。但与此同时,事务的隔离级别越高,并发能力也就越低。所以,还需要读者根据业务需要进行权衡。

标签:事务,WHERE,数据库,修改,现象,Query,数据,浅析,SELECT
From: https://www.cnblogs.com/liftsail/p/18245576

相关文章

  • mysql查询数据库大小
    我们可以使用MySQL命令来查看数据库的数据量大小。首先打开命令行终端,进入MySQL的安装目录,然后执行以下命令:mysql-uusername-p其中,username是你的MySQL用户名。执行命令后,会提示你输入密码。输入正确的密码后,你将进入MySQL命令行界面。接下来,选择你要查看的数据库。假设你想......
  • 开源数据库生态遇新变数,天翼云TeleDB提供企业数据管理更优解!
    近日,知名开源大规模并行处理(MPP)数据库Greenplum的源代码在其官方GitHub页面突然消失,引发了用户和开发者的广泛关注,PostgreSQL生态系统或将产生新变数。开源软件在面对商业化和盈利需求时的举措,将对行业产生巨大影响:开源信任的挑战:频繁的开源协议变更可能会导致企业和开发者......
  • 数据库表名作为参数传递给存储过程的方法
    CREATE   PROCEDURE   SpecialInsertProcedure        @TableName   varchar (50),       @userId   varchar (10),        @pwd   varchar (10),        @userRole intAS      exec ( 'insertinto' +@TableN......
  • Java学习 - MySQL数据库常用命令 实例
    进入MySQL命令行>>mysql-u用户名-p>>输入密码查看MySQL的版本--方法1:通过命令行>>mysql--version>>mysql-V--方法2:通过MySql内置函数>>SELECTVERSION();查看所有的数据库SHOWDATABASES;打开指定的数据库USEtables;查看当前数据库所有的表......
  • Java学习 - MySQL数据库导入和查询方式 实例
    目录练习用数据库导入基础查询条件查询排序查练习用数据库导入下载相关资源中的myemployess.sql执行sql脚本sourcemyemployees.sql;基础查询SELECT子句SELECT查询字段FROM表名;--查询字段包括:表的字段,常量值,表达式,函数--查询的结果是一个虚拟的表查......
  • Java项目:基于SSM框架实现的家居商城系统分前后台【ssm+B/S架构+源码+数据库+毕业论文
    一、项目简介本项目是一套基于SSM框架实现的家居商城系统包含:项目源码、数据库脚本等,该项目附带全部源码可作为毕设使用。项目都经过严格调试,eclipse或者idea确保可以运行!该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值二、技术实现......
  • 数据库原理与应用教程 第四版 何玉洁 编 答案
    继手写五大篇实验报告后我们面善的杨老师又留了新作业(课后题)怎么办怎么才能提高我们写作业的效率呢?思来想去唯有一计我用夸克网盘分享了「2419964972《数据库原理与应用教程》(第4版)习题参考答案.pdf」,点击链接即可保存。打开「夸克APP」在线查看,支持多种文档格式转换。链......
  • 成为MySQL DBA后,再看ORACLE数据库(八、进程、连接与会话)
    不同于MySQL的单进程多线程架构,ORACLE是多进程架构。一个ORACLE实例主要有以下三类进程:1.后台进程,这些进程随数据库启动而启动,用于完成数据库的各种后台任务;2.服务器进程(serverprocess),这些进程一般由客户端的请求产生,根据客户端的请求完成工作;3.从属进程,这些进程类似后台进程,它们......
  • Navicat的使用、PDManer、PyMySQL(连接数据库、执行SQL语句、结果获取、插入数据、删
    【一】Navicat的使用【1】连接数据库打开Navicat,找到连接选项输入连接参数测试参数【2】创建数据库新建数据库输入数据库参数新建表并设置主键修改表字段【3】导出SQL文件【4】备份数据库【5】视图展示会展示当前数据库下的所有表模型......
  • 解决本地机器连接虚拟机中MySQL数据库的问题指南
    在很多开发场景下,我们需在本地电脑通过应用程序或管理工具访问部署在虚拟机里的MySQL数据库,这对于项目测试、调试极其重要。默认配置下,MySQL可能仅接受源自虚拟机本身的连接请求。以下是详细步骤,指导你调整MySQL设置,实现本地到虚拟机MySQL数据库的无缝连接。第一步:登录MySQ......