首页 > 数据库 >Oracle 第14章:并发控制

Oracle 第14章:并发控制

时间:2024-10-30 22:46:47浏览次数:3  
标签:事务 14 -- UPDATE 并发 Oracle 锁定

在Oracle数据库中,并发控制是一个关键概念,因为它确保了多个用户或事务可以同时访问数据库而不干扰彼此的工作。并发问题主要出现在多用户环境中,当多个事务试图同时修改相同的数据时可能发生数据不一致的问题。

并发问题及解决方案

并发问题:
  1. 脏读(Dirty Reads):一个事务读取了另一个未提交的事务的数据。
  2. 不可重复读(Non-repeatable Reads):一个事务读取了一行数据,之后另一个事务更新了该行数据并提交,第一个事务再次读取时得到不同的结果。
  3. 幻读(Phantom Reads):一个事务读取了一组满足某个条件的记录,之后另一个事务插入了一些符合条件的新记录并提交,第一个事务再次执行相同的查询时,发现多了几条记录。
  4. 丢失更新(Lost Updates):两个事务都读取同一行数据,然后各自进行修改并提交,导致后提交的事务覆盖了先提交的事务所做的更改。
解决方案:

为了解决这些问题,Oracle提供了多种锁机制和事务隔离级别来管理并发访问。

锁与隔离级别

锁类型:
  1. 表级锁(Table Locks):锁定整个表,防止其他事务对表进行任何操作。
  2. 行级锁(Row Locks):锁定特定的行,允许其他事务继续工作在表中的其他行。
  3. 模式对象锁(Schema Object Locks):锁定模式对象如表、索引等。
  4. 元数据锁(Metadata Locks):锁定用于DDL操作的对象。
隔离级别:

Oracle支持不同的事务隔离级别,以减少并发带来的问题:

  1. READ UNCOMMITTED:最低的隔离级别,允许读取未提交的数据,可能会导致脏读。
  2. READ COMMITTED:允许一个事务看到另一个事务已经提交的数据,可以避免脏读,但仍然可能出现不可重复读。
  3. REPEATABLE READ:保证在同一个事务中多次读取同一数据时,结果是一致的,可以避免脏读和不可重复读,但可能仍会有幻读。
  4. SERIALIZABLE:最高级别的隔离,完全避免脏读、不可重复读以及幻读,但是可能导致更多的锁定等待。

源代码示例

这里提供一个简单的PL/SQL块来演示如何使用显式锁:

BEGIN
    SELECT empno, ename INTO v_empno, v_ename
    FROM emp
    WHERE empno = 7788 FOR UPDATE;
    
    -- 进行一些处理...
    
    UPDATE emp SET sal = sal + 500
    WHERE empno = 7788;
    
    COMMIT;
EXCEPTION
    WHEN OTHERS THEN
        ROLLBACK;
        RAISE;
END;
/

在这个例子中,FOR UPDATE子句用来获取行级锁,确保在事务期间其他事务不能修改该行数据。如果尝试在没有锁定的情况下进行更新,可能会因为其他事务已经修改了数据而导致ORA-04000类的错误。

并发控制是数据库管理系统中的复杂主题,实际应用中需要根据具体情况选择合适的策略。

Oracle 中的并发控制实现

乐观锁 vs 悲观锁
  • 悲观锁(Pessimistic Locking):假设冲突会发生,在数据被读取之前就加锁。在Oracle中,FOR UPDATE就是一种悲观锁的实现方式。它阻止其他事务在当前事务完成之前修改被锁定的数据。

  • 乐观锁(Optimistic Locking):假设冲突不会发生,只在事务提交时检查是否有冲突。在Oracle中,可以通过版本号列或者时间戳列来实现乐观锁。当事务尝试提交时,会检查版本号是否发生变化,如果发生变化,则表明有其他事务也修改了这条记录,此时会抛出ORA-04091错误。

版本管理

Oracle通过版本管理来支持并发读取。每个读取操作看到的是在读取时刻的数据快照,而不是实时的数据。这样可以减少锁的竞争,提高并发性。

实践中的并发控制

在实际应用中,选择适当的并发控制策略是非常重要的。以下是一些考虑因素:

  • 性能影响:悲观锁通常会导致更多的锁竞争,从而降低系统吞吐量;而乐观锁则减少了锁的使用,但在高并发环境下可能会增加重试次数。
  • 业务需求:如果业务逻辑要求严格的一致性,那么可能需要使用悲观锁;而对于那些能容忍一定延迟一致性的场景,则可以考虑使用乐观锁。
  • 系统架构:分布式系统通常更倾向于使用乐观锁机制,因为它们更容易扩展到分布式环境中。

最佳实践

  • 最小化锁定范围:尽量使用行级锁而非表级锁,这样可以减少锁竞争。
  • 缩短锁定时间:尽量减少事务处理的时间,这样可以降低锁的竞争。
  • 合理选择隔离级别:根据应用的具体需求选择合适的隔离级别,通常情况下,READ COMMITTED级别是一个比较好的折衷点。
  • 使用分区表:对于大型表,可以考虑使用分区技术来减少锁的影响范围。

并发控制是一个复杂且多变的主题,正确地设计和实施并发控制策略对于保证系统的稳定性和性能至关重要。在实践中,还需要不断地调整和优化,以适应不断变化的应用场景和技术环境。

更详细的并发控制机制

Oracle中的锁定机制

Oracle使用多种类型的锁来控制并发访问。除了前面提到的行级锁和表级锁外,还有其他类型的锁:

  • 共享锁(Shared Locks,S):允许多个事务共享数据资源,但不允许写入。
  • 排他锁(Exclusive Locks,X):允许单个事务独占数据资源,既可读也可写。

这些锁的使用取决于具体的SQL语句和事务隔离级别:

  • SELECT ... FOR UPDATE:获取排他锁。
  • SELECT ... FOR UPDATE NOWAIT:获取排他锁,但如果无法立即获得锁,则立即返回错误。
  • SELECT ... FOR UPDATE WAIT n:获取排他锁,等待n秒后如果还无法获得锁,则返回错误。
事务隔离级别

Oracle默认的隔离级别是READ COMMITTED,这意味着事务可以看到其他已提交事务的结果。但在某些情况下,可能需要更高的隔离级别来避免数据不一致性问题。

  • SERIALIZABLE:虽然可以避免脏读、不可重复读和幻读,但由于其严格的锁定策略,可能会导致更多的死锁情况。

实现并发控制的最佳实践

使用分区和索引来减少锁竞争
  • 分区表:对于大数据量的表,使用分区可以将数据分散存储,从而减少锁的范围。例如,可以按日期或地区进行分区。

  • 索引组织表(Index Organized Tables, IOT):IOT可以减少锁定的范围,因为索引键直接指向数据本身,而不是通过指针访问数据。

死锁处理
  • 死锁检测:Oracle具有内置的死锁检测机制,当检测到死锁时,会随机选择一个事务回滚以解除死锁。
  • 避免死锁:设计应用程序时,应确保事务按照固定的顺序获取锁,减少死锁的可能性。
事务生命周期管理
  • 短事务:尽可能缩短事务的持续时间,减少锁定时间和范围。
  • 长事务管理:对于不可避免的长时间运行的事务,应考虑使用特殊的处理机制,如批处理或异步处理。

示例代码

下面是一个更具体的示例,展示了如何在Oracle PL/SQL中使用锁定机制:

-- 创建一个测试表
CREATE TABLE test_table (
    id NUMBER PRIMARY KEY,
    name VARCHAR2(50)
);

-- 插入一些数据
INSERT INTO test_table (id, name) VALUES (1, 'Test Record');
COMMIT;

-- 事务1
BEGIN
    -- 获取行级排他锁
    SELECT * INTO v_id, v_name
    FROM test_table
    WHERE id = 1 FOR UPDATE;

    -- 模拟一些处理时间
    DBMS_LOCK.SLEEP(10);

    -- 更新记录
    UPDATE test_table SET name = 'Updated Test Record' WHERE id = 1;
    COMMIT;
EXCEPTION
    WHEN OTHERS THEN
        ROLLBACK;
        RAISE;
END;
/

-- 事务2
BEGIN
    -- 尝试获取行级排他锁,但因为事务1已经锁定,所以会等待
    SELECT * INTO v_id, v_name
    FROM test_table
    WHERE id = 1 FOR UPDATE NOWAIT;

    -- 如果到达这里,说明没有等待,直接报错
    RAISE_APPLICATION_ERROR(-20001, 'Lock not acquired');
EXCEPTION
    WHEN OTHERS THEN
        ROLLBACK;
        RAISE;
END;
/

在这个示例中,事务1首先锁定并更新了记录,而事务2试图立即获取相同的锁,但由于NOWAIT选项,它会在找不到可用锁时立即失败。

通过以上方法和技术,可以有效地管理和优化Oracle数据库中的并发控制,确保数据的一致性和系统的性能。

标签:事务,14,--,UPDATE,并发,Oracle,锁定
From: https://blog.csdn.net/hummhumm/article/details/143316748

相关文章

  • 14 数据结构
    算法数据存在内存的格式是什莫?数据最好是结构化的,方便读取,所以有了数据结构。1.数组(列表,向量),数组的值一个个连续存在内存里,可以把多个值存在数组变量里2.数组的亲戚是字符串,就是字母,标点符号,数字组成的数组3.多个变量打包到一起叫做结构体,4.一个结构体叫做节点,存一个变量......
  • 16.1 并发编程基础——Java多线程
    16.1并发编程基础——Java多线程16.1.1 引言Java语言的一个重要特点是内在支持多线程的程序设计。多线程的程序设计具有广泛的应用。线程的概念来源于操作系统进程的概念。进程是一个程序关于某个数据集的一次运行。也就是说,进程是运行中的程序,是程序的一次运行活动。线......
  • Oracle数据库AWR报告中高等待事件优化方法
    一、理解等待事件什么是等待事件在Oracle数据库中,等待事件是指会话在执行SQL语句时,由于某些资源(如磁盘I/O、锁、缓冲区等)暂时不可用而必须等待的情况。AWR报告中的等待事件部分可以帮助我们识别数据库性能瓶颈的关键所在。确定高等待事件类型常见的高等待事件包括:......
  • Oracle、MySQL、ClickHouse的通用AES256加解密如何实现?
     Oracle、MySQL、ClickHouse的通用AES256加解密如何实现? 前段时间研究了加密算法aes,写了个文档,分享到博客上来。防。1  说明应XXX安全生产需求,对目标库目标表业务字段敏感信息进行加密密文存放,查询时通过解密得到明文进行数据使用,要求使用AES256。目前公司所使用主要......
  • PCIe宽带中频采集回放平台3GS/s 14bit 2通道12.6GS/s 16bit 2通道
    PCIe宽带中频采集回放平台3GS/s14bit2通道12.6GS/s16bit2通道AC耦合PCIExpressGen3x83GS/s 14bit 2通道12.6GS/s 16bit 2通道 PCIe宽带中频采集回放平台  是一款具备交流耦合和双极性宽带信号输入的高速数据采集卡,它具有2通道,14bit,3GS/s采集和2通道,16bit,12.......
  • InnoDB存储引擎、多版本并发控制(MVCC)简介、Redis简介
    (一)InnoDB存储引擎InnoDB是MySQL最常用的存储引擎之一,有支持事务处理、行级锁定和外键约束等高级功能而著称。1、InnoDB架构物理结构表空间:InnoDB的数据存储空间在表空间中,表空间可以分为系统表空间、文件表空间和通用表空间。系统表空间:默认存储在ibdata1文件中,包含系统......
  • 【C/C++】5.并发控制
    并发控制(ConcurrencyControl)是指在多线程或多进程环境中,确保多个操作在共享资源上的访问不会发生冲突或产生不一致的情况。并发控制的核心目标是在允许并发操作的同时,保证系统的正确性、数据的一致性和完整性。在并发环境下,不同的线程或进程可能会同时访问共享资源(例如变量、文......
  • 关于自己写阿里云OSS相关工具类的自动配置(黑马web开发day14)
    阿里云OSS的自动配置主要分为:驱动类:aliyun-oss-spring-boot-autoconfigure自动配置类:aliyun-oss-spring-boot-starter文章目录aliyun-oss-spring-boot-starter创建aliyun-oss-spring-boot-starteraliyun-oss-spring-boot-autoconfigure创建aliyun-oss-spring-boot-aut......
  • 2024.10.14 Codeforces Round 978 (Div. 2)
    比赛链接Solved:4/7Upsolved:5/7Rank:447(rated343)D2.Asesino(HardVersion)题意:有n个人,除了一个卧底以外,其他人或者只会说真话,或者只会说谎,且他们知道彼此的身份。卧底只会说谎,但其他人都认为他只会说真话。现在你可以进行若干次询问,每次询问形如问第i个人第j个人是什么......
  • 并发编程(1)——线程
    目录一、day11.线程的建立1.1线程如何发起1.1.1普通函数1.1.2仿函数1.1.3lambda函数1.1.4类的成员函数1.1.5move1.2子线程需要被等待1.3detach1.4.异常处理1.5慎重使用隐式转换1.6如何在线程中使用引用2.thread参数传递和调用原理2.1数据成员2.......