数据库Oracle从入门到精通!第四天(并发、锁、视图)

八、并发控制

数据库是一个共享资源,可以为多个应用程序所共享,这些程序可以串行执行(排队执行),但是很多情况下,可能出现多个程序或一个程序中的多个进程并行的执行,这就是数据库的并行操作(并发控制)。

在多用户数据库环境中,多个用户可以并行的存取数据库,如果不对并发操作进行控制,那么可能存取不正确的数据,或破坏数据库数据的一致性。

  1. 并行的例子:其中T代表事务

(1)数据库并发过程中可能出现的问题

(2)并发过程中可能出现的问题的类型

1)脏读(dirty read):一个事务读取了另一个事务修改但是没有提交事务的数据,如果稍后这个修改被回滚,那么这个事务读取到的数据就是无效的脏数据。

2)不可重复读(nonrepeated read):一个事务执行了两次或两次以上的查询,但是每次查询的结果都不一样,原因通常是另一个事务在两次查询之间修改了数据。

3)幻读(phantom read):当一个事务读取几行记录后,另一个并发事务插入了一些记录,这些插入的记录满足第一个事务读取数据的条件,此时幻读就发生了,即后面查询的数据出现了原来没有的额外的记录。

2. 事务

事务是不可分割的原子单元,事务保证SQL语句要么全部执行,要么全部不执行,数据库中的事务往往是并发的。Oracle数据库默认情况下事务是自动提交的,这意味着每执行一条SQL语句,事务都会提交一次,可以改为手动提交:SET AUTOCOMMIT OFF,此时需要显式执行COMMIT来提交事务,ROLLBACK来回滚事务,当然也可以SET AUTOCOMMIT ON恢复成自动提交事务。

(1)事务的特性(ACID)

1)原子性(A):事务将多个对数据库的操作当成一个原子单元,要么全部执行成功,要门全部失败。

2)一致性(C):系统的状态要从一种一致性状态转到另一种一致性状态,不能违反完整性约束,即两次从同一个地方获取的数据要一致,不能不一致。

3)隔离性(I):事务必须是相互隔离的,多个用户操作同一个数据的时候,一个用户的操作不能去影响其他用户的操作。

4)持久性(D):已经提交的事务对数据库的修改是永久的,事务一旦提交,再回滚是没用的。

(2)事务的隔离级别:

1)序列化:Serializable,最严格的级别,事务串行执行(排队执行),没有并发问题,但是效率最低。

2)可重复读,Repeatable read,保证事务不会修改由其他一个事务读取但未提交的数据,可以避免脏读和不可重复读的并发问题,存在幻读问题,效率一般。

3)读已提交,Read Committed,是大多数数据库默认的隔离级别,保证事务不会读取另一个并行事务修改但未提交的数据,可以避免脏读,存在不可重复读和幻读问题,效率比较高。

其中Oracle数据库默认的隔离级别是读已提交,MySQL数据库默认的隔离级别是可重复读。

(3)锁机制
数据的不一致总是由两个因素造成:一是对数据的修改,二是并发操作的发生,因此为了保证数据的一致性,必须对并发操作进行控制,最常见的方式就是加锁,数据库中常见的锁有两种:排他锁(X)和共享锁(S)
1)排他锁(X)

如果事务T对数据D加上了X锁,则其他事务都不能再对数据D添加任何类型的锁,直到T释放D上的X锁(提交或回滚事务时)。一般要求在修改数据前向数据添加排他锁,所以排他锁也称为写锁,一个资源,比如一张表只能加一个排他锁,但是可以加多个共享锁。

2)共享锁(S)

如果事务T对数据D加上S锁,则其他事务也只能对D加S锁,不能加X锁,直到T释放D上的S锁,一般要求读取数据前向该数据加共享锁,所以共享锁也称为读锁,所以共享锁具有更高的并行性。

(4)Oracle数据库将锁分为以下几类:

1)数据锁:为了保护表,在多个用户并行存取数据时保证数据的完整性,DML操作可以在两个级别上获取数据锁:行锁和表锁,当某行要被修改的时候,事务会自动在该行加上排他锁。

2)DDL锁:DDL锁保护模式对象结构的定义,DDL操作将影响对象,一个DDL语句会隐式的提交事务(会释放锁),比如创建表格时会提交事务并释放锁。

3)内部锁:保护内部数据库和内存结构

(5)数据库中加锁的两种方式:独占方式和共享方式

1)独占方式:不允许其他用户以任何方式共享锁定的资源,当进行数据库修改的时候就可以使用该模式,即加上排他锁。

2)共享模式:允许在数据访问时,并发的共享访问,但是当修改数据库时上升为独占模式,指共享锁。

(6)锁分为行级锁和表级锁,行级锁用于锁定某些记录,表级锁用于锁定整张表的所有记录。

1)行级锁

a. 当执行INSERT、UPDATE、DELETE等DML操作时,会隐式的加上行锁(排他锁),这意味其他事务只能查询这几行的数据,但是不能修改这些行的数据,直到排他锁被释放。

b. 显式通过"SELECT......FOR UPDATE"来加行锁,会将查询出来的这几行记录加上排他锁,其他事务也只能查询这几行,不能修改这几行。

示例:行锁

开启一个sqlplus(一个会话),即可开启了一个事务,将事务设置为手动提交

事务1:

此时,empno=7369的这一行就添加了行锁(排他锁),那么其他事务就只能查询不能修改这一行的记录,当然,其他非7369的行就没有加锁,其他事务就可以修改。

再开启一个sqlplus,即开启另一个事务:

事务2:

事务2去查询empno=7369这一行没有问题,但是不能去修改,试图修改empno=7369的事务会被阻塞,直到事务1提交事务释放锁之后,事务2才能修改成功:

事务2被阻塞了,原因是事务1对empno=7369这一行加了排他锁,其他事务就只能阻塞

然后事务1提交事务释放锁:

事务2就更新成功了:

注意:此时由于事务2执行了UPDATE语句,会隐式的给empno=7369这一行加上行锁,事务1也只能查询不能修改,修改的动作也会被阻塞,直到事务2提交事务释放锁才可以:

事务1:

事务1可以查询,但是更新会被阻塞

然后事务2提交事务:

事务1更新成功:

注意:行锁只对加锁的这几行数据有效,其他没有加行锁的数据其他事务还是可以修改的。

示例2:假如有其他用户要锁定同一个资源,可以使用wait子句对锁等待的时间(秒级)进行控制,例如:SELECT * FROM emp WHERE empno=7369 FOR UPDATE WAIT 3; 表示等待3秒,如果发现其他事务还没有释放锁,系统给出出错提示。

我们来操作一下,先将两个事务都COMMIT一次,保证两个事务的锁都被释放。

事务1:对7369加行锁

事务2:也试图对7369加行锁,但是由于事务1已经对7369加了行锁,其他事务不能再对7369加任何类型的锁,等到时间到了,系统给出提示:

2)表级锁:锁定整张表的所有记录,分为三种模式:

 共享模式:IN SHARE MODE

 共享更新模式:IN SHARE UPDATE MODE

 排他锁模式:IN EXCLUSIVE MODE

 表级锁的语法:LOCK TABLE 表名 锁模式;
a. 共享模式 :不允许其他用户插入、更新和删除行,多个用户可以同时在一个表上设置共享锁,这样大家都只能查询,不能修改。

示例:先把事务1和事务2都COMMIT一次,全部释放锁

事务1:

事务2:可以查询,但是不能修改数据,直到事务1提交事务释放锁之后才行

事务1提交事务释放锁:

事务2更新成功:

如果事务1和事务2都加上表级共享锁,那么两个事务都只能查询,不能修改:

此时如果两个事务都去修改数据,就会出现死锁,因为两个事务都在等待对方释放锁,就会陷入死锁状态,死锁是我们要避免的一个问题。
b. 共享更新模式 :允许多个用户同时锁定表的不同行,允许其他用户执行DML操作,除了已锁定的行。

示例:

LOCK TABLE emp IN SHARE UPDATE MODE;

SELECT * FROM emp WHERE deptno=30 FROM UPDATE; -- 锁定特定行,其他用户不能修改

SELECT * FROM emp WHERE deptno=30; -- 但是其他用户可以查询

示例:

事务1加了共享更新模式,对empno=8888加了行锁,那么事务2可以对其他行进行更新,但是不能对empno=8888进行更新,除非事务1提交事务释放锁:

直到事务1提交事务释放锁:

c. 排他锁模式

不允许其他用户插入、更新和删除行,允许查询数据,如果一个事务对表加了排他锁,其他事务不能再对这张表加任何类型的锁,包括共享锁。

示例1:还是两边都COMMIT一次

事务1:

事务2:也试图给emp加排他锁,会被阻塞

直到事务1提交或回滚事务释放锁之后,事务2加锁才能成功:

目前事务2加上了排他锁,事务1不能加任何类型的锁,包括共享锁:

事务1:

总结:一旦一个事务加了排他锁,其他事务只能查询,不能修改,例如:

两边都COMMIT一次:

事务1:

事务2:可以查询,但是修改emp表的任何一条记录都会被阻塞,直到事务1提交事务释放锁后才行:

事务1提交事务释放锁,事务2更新才能成功:

总结:共享锁的并发性比排他锁的好,对于排他锁,行锁的并发性比表锁的并发性好。

九、其他重要模式对象

1.其他重要模式对象,主要包含:索引、序列、视图
2.索引
(1)索引概述

1)索引(index)是为了提高数据库查询性能而建立的,利用它可以快速的确定指定的信息,索引就像书的目录。

2)索引可以建立在表的一列或多列上,一旦建立,由Oracle数据库自动维护和使用,但是当表中建立的索引过多的时候,修改、插入、删除的性能会下降,因为修改数据的时候,Oracle会去维护索引,带来额外的开销,所以索引并不是越多越好。

3)索引分为唯一索引和非唯一索引,唯一索引保证表中的索引字段不能重复,Oracle自动在UNIQUE字段上创建唯一索引。

4)Oracle自动在PRIMARY KEY 字段上创建主键索引,所以建议创建表的时候,一定要给出主键约束,以便通过主键来查询数据时利用主键索引提高查询的速度。

5)当WHERE子句中包含索引字段时,就会使用索引来检索数据,性能会大大增强,例如:SELECT * FROM emp WHERE empno=7369;

(2)创建索引的语法:

CREATE [UNIQUE] INDEX 索引名 ON 表名(索引列1,索引列2,...);

其中 UNIQUE 表示创建唯一索引,可以省略

示例:

(3)删除索引

DROP INDEX 索引名;

3.序列
(1)序列概述

序列(SEQUENCE)用于产生序列号(流水号),在多用户环境下使用序列特别有用,可以生成整数类型,最多可有38位的数字。

(2)创建序列的语法:

CREATE SEQUENCE 序列名 -- 创建序列

START WITH 初始值\] -- 序列的初始值,默认是1 \[INCREMENT BY 递增值\] -- 每次递增的值,默认是1 \[MAXVALUE 最大值 \| NOMAXVALUE\] -- 能达到的最大值或没有限制 \[MINVALUE 最小值 \| NOMINVALUE\] -- 最小值或没有限制 \[CYCLE \| NOCYCLE\] -- 循环生成序列或不循环 \[CACHE 缓冲数据个数 \| NOCACHE\] -- 保留在缓冲区中的序列值个数,缓冲区是为了提高读取速度,默认20个 \[ORDER \| NOORDER\] -- 按照顺序生成序列值或不强调按照顺序生成 其中\[\]里面内容可以省略,"\|"表示或者的意思 (3)序列中的两个伪列:currval和nextval,其中currval表示序列的当前值,nextval表示序列的下一个值 示例: ![](https://i-blog.csdnimg.cn/direct/875f6b9731ea44ac82d8bec9ce6f3970.png) 序列最大的用途是生成递增的主键值,例如: 创建users表,插入5条记录,使用序列生成递增的主键值: ![](https://i-blog.csdnimg.cn/direct/eeff3dc03b074a84b900fde50de530a5.png) ![](https://i-blog.csdnimg.cn/direct/916b29d06ba8418ba3260b2799586e43.png) (4)删除序列 DROP SEQUENCE 序列名; ![](https://i-blog.csdnimg.cn/direct/746a7be6cb0a496cb1e0354fddd8c5fd.png) **4.视图:一张虚拟的数据库表** 视图是从一个或多个基本表或视图中查询出来的记录形成的一张虚拟表,可以简单认为: 视图就是查询表或视图形成的一张虚拟表 视图只存放视图的定义,不会存放数据,视图的数据任然在原来的数据库表中。 **(1)视图的作用:** 1)视图能简化用户的操作 2)使用户能够以多种角度来看待同一个数据 3)对重构数据库提供了一定程度的逻辑独立性 4)能够对机密数据提供安全保护,比如只公开部分字段 **(2)创建视图的语法** CREATE \[OR REPLACE\] VIEW 视图名 AS SELECT语句; 其中: OR REPLACE:如果视图名已经存在,则替换,否则就创建新的视图,可以省略 SELECT语句:查询语句,可以是单表、多表或子查询 注意:创建视图必须具有CREATE VIEW或CREATE ANY VIEW的系统权限 示例: ![](https://i-blog.csdnimg.cn/direct/4748c296eb4c4dde9a77642e10816999.png) 示例2: ![](https://i-blog.csdnimg.cn/direct/ed23326e0e704cc88329167ea8be3d32.png) (3)删除视图 DROP VIEW 视图名; ![](https://i-blog.csdnimg.cn/direct/7e0b996a37e7452c8bdfd8a7ded6f5ac.png)

相关推荐
互联网搬砖老肖3 小时前
运维打铁: MongoDB 数据库集群搭建与管理
运维·数据库·mongodb
积跬步,慕至千里4 小时前
clickhouse数据库表和doris数据库表迁移starrocks数据库时建表注意事项总结
数据库·clickhouse
极限实验室4 小时前
搭建持久化的 INFINI Console 与 Easysearch 容器环境
数据库
白仑色5 小时前
Oracle PL/SQL 编程基础详解(从块结构到游标操作)
数据库·oracle·数据库开发·存储过程·plsql编程
程序猿小D6 小时前
[附源码+数据库+毕业论文]基于Spring+MyBatis+MySQL+Maven+jsp实现的个人财务管理系统,推荐!
java·数据库·mysql·spring·毕业论文·ssm框架·个人财务管理系统
钢铁男儿7 小时前
C# 接口(什么是接口)
java·数据库·c#
__风__8 小时前
PostgreSQL kv(jsonb)存储
数据库·postgresql
轩情吖8 小时前
Qt的第一个程序(2)
服务器·数据库·qt·qt creator·qlineedit·hello world·编辑框
Databend8 小时前
Databend 产品月报(2025年6月)
数据库