`

Oracle数据库悲观锁与乐观锁

 
阅读更多

原文出处:http://database.51cto.com/art/201108/284797.htm

 

2011-08-18 13:44 lr5200 CSDN博客 字号:T | T
一键收藏,随时查看,分享好友!

我们知道,数据的锁定分为两种方法,第一种叫做悲观锁,第二种叫做乐观锁。本文我们主要就介绍一下Oracle数据库的悲观锁与乐观锁的相关知识,希望能够对您有所收获!

AD:2013云计算架构师峰会课程资料下载

 

Oracle数据库悲观锁乐观锁是本文我们主要要介绍的内容。有时候为了得到最大的性能,一般数据库都有并发机制,不过带来的问题就是数据访问的冲突。为了解决这个问题,大多数数据库用的方法就是数据的锁定。

数据的锁定分为两种方法,第一种叫做悲观锁,第二种叫做乐观锁。什么叫悲观锁呢,悲观锁顾名思义,就是对数据的冲突采取一种悲观的态度,也就是说假设数据肯定会冲突,所以在数据开始读取的时候就把数据锁定住。而乐观锁就是认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让用户返回错误的信息,让用户决定如何去做。

先从悲观锁开始说。在SqlServer等其余很多数据库中,数据的锁定通常采用页级锁的方式,也就是说对一张表内的数据是一种串行化的更新插入机制,在任何时间同一张表只会插1条数据,别的想插入的数据要等到这一条数据插完以后才能依次插入。带来的后果就是性能的降低,在多用户并发访问的时候,当对一张表进行频繁操作时,会发现响应效率很低,数据库经常处于一种假死状态。而Oracle用的是行级锁,只是对想锁定的数据才进行锁定,其余的数据不相干,所以在对Oracle表中并发插数据的时候,基本上不会有任何影响。

注:对于悲观锁是针对并发的可能性比较大,而一般在我们的应用中用乐观锁足以。

Oracle的悲观锁需要利用一条现有的连接,分成两种方式,从SQL语句的区别来看,就是一种是for update,一种是for update nowait的形式。比如我们看一个例子。首先建立测试用的数据库表。

CREATE TABLE TEST(ID,NAME,LOCATION,VALUE,CONSTRAINT test_pk PRIMARY KEY(ID))AS SELECT deptno, dname, loc, 1 FROM scott.dept

这里我们利用了Oracle的Sample的scott用户的表,把数据copy到我们的test表中。首先我们看一下for update锁定方式。首先我们执行如下的select for update语句。

select * from test where id = 10 for update

通过这条检索语句锁定以后,再开另外一个sql*plus窗口进行操作,再把上面这条sql语句执行一便,你会发现sqlplus好像死在那里了,好像检索不到数据的样子,但是也不返回任何结果,就属于卡在那里的感觉。这个时候是什么原因呢,就是一开始的第一个Session中的select for update语句把数据锁定住了。由于这里锁定的机制是wait的状态(只要不表示nowait那就是wait),所以第二个Session(也就是卡住的那个sql*plus)中当前这个检索就处于等待状态。当第一个session最后commit或者rollback之后,第二个session中的检索结果就是自动跳出来,并且也把数据锁定住。不过如果你第二个session中你的检索语句如下所示。

select * from test where id = 10

也就是没有for update这种锁定数据的语句的话,就不会造成阻塞了。另外一种情况,就是当数据库数据被锁定的时候,也就是执行刚才for update那条sql以后,我们在另外一个session中执行for update nowait后又是什么样呢。比如如下的sql语句。 由于这条语句中是制定采用nowait方式来进行检索,所以当发现数据被别的session锁定中的时候,就会迅速返回ORA-00054错误,内容是资源正忙, 但指定以 NOWAIT 方式获取资源。所以在程序中我们可以采用nowait方式迅速判断当前数据是否被锁定中,如果锁定中的话,就要采取相应的业务措施进行处理。

select * from test where id = 10 for update nowait

那这里另外一个问题,就是当我们锁定住数据的时候,我们对数据进行更新和删除的话会是什么样呢。比如同样,我们让第一个Session锁定住id=10的那条数据,我们在第二个session中执行如下语句。

update test set value=2 where id = 10

这个时候我们发现update语句就好像select for update语句一样也停住卡在这里,当你第一个session放开锁定以后update才能正常运行。当你update运行后,数据又被你update语句锁定住了,这个时候只要你update后还没有commit,别的session照样不能对数据进行锁定更新等等。

总之,Oracle中的悲观锁就是利用Oracle的Connection对数据进行锁定。在Oracle中,用这种行级锁带来的性能损失是很小的,只是要注意程序逻辑,不要给你一不小心搞成死锁了就好。而且由于数据的及时锁定,在数据提交时候就不呼出现冲突,可以省去很多恼人的数据冲突处理。缺点就是你必须要始终有一条数据库连接,就是说在整个锁定到最后放开锁的过程中,你的数据库联接要始终保持住。与悲观锁相对的,我们有了乐观锁。乐观锁一开始也说了,就是一开始假设不会造成数据冲突,在最后提交的时候再进行数据冲突检测。

在乐观锁中,我们有3种常用的做法来实现:

[1]第一种就是在数据取得的时候把整个数据都copy到应用中,在进行提交的时候比对当前数据库中的数据和开始的时候更新前取得的数据。当发现两个数据一模一样以后,就表示没有冲突可以提交,否则则是并发冲突,需要去用业务逻辑进行解决。

[2]第二种乐观锁的做法就是采用版本戳,这个在Hibernate中得到了使用。采用版本戳的话,首先需要在你有乐观锁的数据库table上建立一个新的column,比如为number型,当你数据每更新一次的时候,版本数就会往上增加1。比如同样有2个session同样对某条数据进行操作。两者都取到当前的数据的版本号为1,当第一个session进行数据更新后,在提交的时候查看到当前数据的版本还为1,和自己一开始取到的版本相同。就正式提交,然后把版本号增加1,这个时候当前数据的版本为2。

当第二个session也更新了数据提交的时候,发现数据库中版本为2,和一开始这个session取到的版本号不一致,就知道别人更新过此条数据,这个时候再进行业务处理,比如整个Transaction都Rollback等等操作。在用版本戳的时候,可以在应用程序侧使用版本戳的验证,也可以在数据库侧采用Trigger(触发器)来进行验证。不过数据库的Trigger的性能开销还是比较的大,所以能在应用侧进行验证的话还是推荐不用Trigger。

[3]第三种做法和第二种做法有点类似,就是也新增一个Table的Column,不过这次这个column是采用timestamp型,存储数据最后更新的时间。在Oracle9i以后可以采用新的数据类型,也就是timestamp with time zone类型来做时间戳。这种Timestamp的数据精度在Oracle的时间类型中是最高的,精确到微秒(还没与到纳秒的级别),一般来说,加上数据库处理时间和人的思考动作时间,微秒级别是非常非常够了,其实只要精确到毫秒甚至秒都应该没有什么问题。和刚才的版本戳类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。如果不想把代码写在程序中或者由于别的原因无法把代码写在现有的程序中,也可以把这个时间戳乐观锁逻辑写在Trigger或者存储过程中。

关于Oracle数据库的悲观锁与乐观锁的知识就介绍到这里了,希望本次的介绍能够对您有所收获!

 

分享到:
评论

相关推荐

    Java 中的悲观锁和乐观锁的实现

    乐观锁与悲观锁相反,它假定数据不太可能被其他线程或进程修改,因此不会一开始就锁定数据。这种锁机制通常不会直接使用数据库级别的锁定机制,而是通过版本号或其他标记来检测数据是否已被其他事务修改。 **1. ...

    Hibernate的乐观锁与悲观锁

    ### Hibernate的乐观锁与悲观锁 #### 一、引言 在并发环境下,尤其是在金融、电商等业务场景中,确保数据的一致性和完整性至关重要。**Hibernate**作为一种流行的Java持久层框架,提供了多种机制来处理并发控制...

    Hibernate乐观锁和悲观锁分析

    【Hibernate乐观锁与悲观锁详解】 在开发过程中,尤其是在并发环境下,确保数据的一致性和完整性至关重要。Hibernate,作为Java领域广泛使用的ORM框架,提供了一种处理并发数据访问冲突的手段,那就是锁机制。主要...

    HIbernate与oracle数据库应用例子

    - 乐观锁/悲观锁:处理并发控制,防止数据冲突。 通过上述步骤,开发者可以在Java应用中高效地使用Hibernate与Oracle数据库进行数据操作。实践过程中,应不断优化和调整,以适应不同场景的需求。在实际项目中,还...

    hibernate的乐观锁和悲观锁

    ### Hibernate的乐观锁和悲观锁 #### 一、引言 在软件开发中,尤其是在涉及大量并发操作的应用场景下,确保数据的一致性和完整性是非常重要的。对于基于Java Web的应用而言,Hibernate作为一款流行的ORM框架,提供...

    hibernate乐观锁和悲观锁学习

    与悲观锁不同,乐观锁假设并发环境下数据不会被同时修改,因此在读取数据时不会立即加锁。只有在更新数据时,才会检查数据是否自上次读取后发生了变化。在Hibernate中,通常通过在实体类的映射文件中设置`optimistic...

    查看Oracle锁表

    3. **并发控制机制**:如乐观锁和悲观锁等技术。 4. **定期检查锁定情况**:定期执行上述SQL查询,及时发现并解决锁定问题。 #### 五、总结 在Oracle数据库中,了解和掌握锁定机制对于确保数据完整性和提高系统...

    ORACLE数据库系统加锁问题的研究 (1).pdf

    在并发控制中,Oracle采用的是乐观锁和悲观锁策略的结合。乐观锁假设并发事务不会发生冲突,只有在提交时才检查数据是否被其他事务修改;悲观锁则是在事务开始时就对所需资源进行锁定,防止其他事务修改。这两种策略...

    Hibernate实现悲观锁和乐观锁代码介绍

    Hibernate 实现悲观锁和乐观锁代码介绍 Hibernate 是一个基于 Java 的持久层框架,它提供了多种锁机制来实现事务的隔离性和一致性。在本文中,我们将详细介绍 Hibernate 实现悲观锁和乐观锁的代码实现,并讨论 ...

    java调用Oracle的锁表命令

    - 考虑使用乐观锁或悲观锁策略,根据应用的并发需求选择合适的方式。 通过以上步骤,你可以在Java程序中安全有效地调用Oracle的锁表命令,确保数据一致性并优化并发性能。对于更复杂的应用场景,如分布式事务,...

    SQL数据库系统原理(二)———乐观锁与悲观锁、MVCC、范式理论、SQL和NoSQL比较

    在数据库系统中,为了保证数据的一致性和完整性,有多种并发控制策略,其中包括乐观锁和悲观锁。这两种锁机制主要用于解决事务在并发环境中的数据冲突问题。 乐观锁是一种假设事务在执行过程中不会发生冲突的策略。...

    ORACLE数据库性能优化的方法研究.pdf

    有效管理并发事务,如合理设置锁定级别、使用乐观锁或悲观锁,可以避免阻塞和死锁,提高系统吞吐量。 10. 硬件升级和架构调整 当软件优化无法满足性能需求时,考虑硬件升级,如增加CPU、内存或采用更快的存储设备...

    Oracle数据库高级技术交流计划-性能调优

    - **减少锁冲突**:通过优化事务处理逻辑减少锁等待时间,比如采用乐观锁或悲观锁机制。 - **使用Hint**:在SQL语句中加入提示(Hint),指导优化器如何执行查询,这对于复杂查询尤其有用。 #### 论全表扫描 全表...

    Oracle数据库课件

    4. **事务与并发控制**:了解事务的ACID特性,以及锁定机制、乐观锁和悲观锁在并发场景下的应用。 5. **备份与恢复**:掌握Oracle的物理备份、逻辑备份方法,以及RMAN(恢复管理器)的使用。 6. **性能优化**:学习...

    Oracle11g数据库入门第6章 锁

    什么是锁? 锁定问题 丢失更新 悲观锁定 乐观锁定 乐观锁定还是悲观锁定? 阻塞 死锁 锁升级

    《数据库系统原理与应用——Oracle版》-电子教案.rar

    7. 数据库并发控制:讲述多用户环境下如何处理并发操作,包括锁定机制、乐观锁和悲观锁、多版本并发控制(MVCC)等。 8. 数据库恢复:介绍如何处理系统故障或错误,包括事务日志、检查点、前滚与后滚操作等。 9. ...

    Oracle的锁机制

    根据锁定时间,锁可分为悲观锁和乐观锁。悲观锁假设数据操作会发生冲突,所以在读取数据时立即锁定,例如表级锁。乐观锁则在数据更新时检查冲突,如行级锁,这样可以提高并发性能。 根据保护的对象,Oracle的锁分为...

    Oracle 9i&10g编程艺术:深入数据库体系结构.pdf

    本章详细分析了锁的概念、类型(如DML锁、DDL锁、闩锁)以及锁定策略(乐观锁定与悲观锁定)。还探讨了锁定可能导致的问题,如丢失更新、阻塞、死锁和锁升级,帮助读者设计更加健壮的并发控制方案。 ### 第7章:...

Global site tag (gtag.js) - Google Analytics