Oracle 丢失更新问题的解决方案
丢失更新是数据中一个比较常见的经典问题,在做项目时我们有时可能会没有注意到这个问题,但这个问题相当重要,有时会带来比较严
丢失更新是数据中一个比较常见的经典问题,在做项目时我们有时可能会没有注意到这个问题,但这个问题相当重要,有时会带来比较严重的结果。下面我们就来讨论下这个丢失更新。
一、什么是丢失更新:
用一个操作过程来说明:
(1) 会话Session1 中的一个事务获取(查询)一行数据,并显示给一个用户User1。
(2) 会话Session2 中的另一个事务也获取这一行,但是将数据显示给另一个用户User2。
(3) User1 使用应用修改了这一行,让应用更新数据库并提交。会话Session1 的事务执行完毕。
(4) User2 也修改这一行,让应用更新数据库并提交。会话Session2 的事务执行完毕。
这个过程就叫做“丢失更新”,因为第(3)步做的操作会全部丢失(被第4步操作覆盖),最终数据库只会保存第(4)步的更新结果。这个情况在有些系统中可能不会有影响,但在有些系统中可能就影响很大了,举个简单的例子:
财务系统加工资,若公司本次调薪决定给员工张三加1k人民币,财务部两名操作人员A和B,过程情况若是这样的:
1)A操作员在应用系统的页面上查询出张三的薪水信息,然后选择薪水记录进行修改,打开修改页面但A突然有事离开了,页面放在那没有做任何的提交。
2)这时候B操作员同样在应用中查询出张三的薪水信息,然后选择薪水记录进行修改,录入增加薪水额1000,然后提交了。
3)这时候A操作员回来了,在自己之前打开的薪水修改页面上也录入了增加薪水额1000,然后提交了。
其实上面例子操作员A和B只要一前一后做提交,悲剧就出来了。后台修改薪水的sql:update 工资表 set salary = salary + 增加薪水额 where staff_id = ‘员工ID’。这个过程走下来后结果是:张三开心了这次涨了2k,操作员A和B都郁闷了。
二、解决思路:
基本两种思路,一种是悲观锁,另外一种是乐观锁; 简单的说就是一种假定这样的问题是高概率的,最好一开始就锁住,免得更新老是失败;另外一种假定这样的问题是小概率的,最后一步做更新的时候再锁住,免得锁住时间太长影响其他人做有关操作。
三、解决方案1(悲观锁)
a.传统的悲观锁法(不推荐):
以上面的例子来说明,在弹出修改工资的页面初始化时(这种情况下一般会去从数据库查询出来),在这个初始化查询中使用select ...for update nowait, 通过添加for update nowait语句,将这条记录锁住,避免其他用户更新,从而保证后续的更新是在正确的状态下更新的。然后在保持这个链接的状态下,在做更新提交。当然这个有个前提就是要保持链接,就是要对链接要占用较长时间,这个在现在web系统高并发高频率下显然是不现实的。
b.现在的悲观锁法(推荐优先使用):
在修改工资这个页面做提交时先查询下,当然这个查询必须也要加锁(select ...for update nowait),有人会说,在这里做个查询确认记录是否有改变不就行了吗,是的,是要做个确认,只是你不加for update就不能保证你在查询到更新提交这段时间里这条记录没有被其他会话更新过,所以这种方式也需要在查询时锁定记录,保证在这条记录没有变化的基础上再做更新,若有变化则提示告知用户。
四、解决方案2(乐观锁)
a.旧值条件(前镜像)法:
就是在sql更新时使用旧的状态值做条件,SQL大致如下 Update table set col1 = newcol1value, col2 = newcol2value…. where col1 = oldcol1value and col2 = oldcol2value….,在上面的例子中我们就可以把当前工资作为条件进行更新,如果这条记录已经被其他会话更新过,则本次更新了0行,这里我们应用系统一般会做个提示告知用户重新查询更新。这个取哪些旧值作为条件更新视具体系统实际情况而定。(这种方式有可能发生阻塞,如果应用其他地方使用悲观锁法长时间锁定了这条记录,,则本次会话就需要等待,所以使用这种方式时最好统一使用乐观锁法。)
b.使用版本列法(推荐优先使用):
其实这种方式是一个特殊化的前镜像法,就是不需要使用多个旧值做条件,只需要在表上加一个版本列,这一列可以是NUMBER或 DATE/TIMESTAMP列,加这列的作用就是用来记录这条数据的版本(在表设计时一般我们都会给每个表增加一些NUMBER型和DATE型的冗余字段,以便扩展使用,这些冗余字段完全可以作为版本列用),在应用程序中我们每次操作对版本列做维护即可。在更新时我们把上次版本作为条件进行更新。
c.使用校验和法(不推荐)
d.使用ORA_ROWSCN法(不推荐)
五、结论:
个人建议:在用户并发数比较少且冲突比较严重的应用系统中选择悲观锁b方法,其他情况首先乐观锁版本列法。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









Oracle でテーブルがどのテーブルスペースに属しているかを確認する方法: 1. 「SELECT」ステートメントを使用し、テーブル名を指定して、指定したテーブルが属するテーブルスペースを検索します; 2. Oracle が提供するデータベース管理ツールを使用して確認します。表が属する表スペース。ツールは通常、操作をより直観的かつ便利にするグラフィカル・インターフェースを提供します。3. SQL*Plus では、「DESCRIBEyour_table_name;」コマンドを入力すると、表が属する表スペースを表示できます。 。

PDO を使用して Oracle データベースに接続する方法の概要: PDO (PHPDataObjects) は、PHP でデータベースを操作するための拡張ライブラリであり、複数の種類のデータベースにアクセスするための統合 API を提供します。この記事では、PDO を使用して Oracle データベースに接続し、一般的なデータベース操作を実行する方法について説明します。ステップ: Oracle データベース ドライバー拡張機能をインストールする PDO を使用して Oracle データベースに接続する前に、対応する Oracle をインストールする必要があります

Oracle が重複データを 1 つだけフェッチする手順: 1. SELECT ステートメントを GROUP BY および HAVING 句と組み合わせて使用し、重複データを検索します。 2. ROWID を使用して重複データを削除し、正確な重複データ レコードが削除されるようにします。重複データを削除するには、「ROW_NUMBER」() 関数を使用します。これにより、重複データの各セットの最初のレコードを除くすべてのレコードが削除されます。 3. 「select count(*) from」ステートメントを使用して、削除されたレコードの数を返します。結果を保証します。

PHP および Oracle データベースへのデータ インポートの実装 Web 開発では、サーバー側のスクリプト言語として PHP を使用すると、データベースを便利に操作できます。一般的なリレーショナル データベース管理システムとして、Oracle データベースは強力なデータ ストレージ機能と処理機能を備えています。この記事では、PHP を使用して Oracle データベースにデータをインポートする方法と、対応するコード例を紹介します。まず、PHP と Oracle データベースがインストールされていること、および PHP が次のように構成されていることを確認する必要があります。

PHP を使用して PDO を拡張し、Oracle データベースに接続する方法 はじめに: PHP は非常に人気のあるサーバー側プログラミング言語であり、Oracle は一般的に使用されるリレーショナル データベース管理システムです。この記事では、PHP 拡張機能 PDO (PHPDataObjects) を使用して Oracle データベースに接続する方法を紹介します。 1. PDO_OCI 拡張機能のインストール Oracle データベースに接続するには、まず PDO_OCI 拡張機能をインストールする必要があります。 PDO_OCI 拡張機能をインストールする手順は次のとおりです。

oracle データベースには jdk が必要です。その理由は、1. 特定のソフトウェアや機能を使用する場合、JDK に含まれる他のソフトウェアやライブラリが必要であること、2. Oracle データベースで Java プログラムを実行するには Java JDK をインストールする必要があること、3. JDK であることです。 Java アプリケーション関数の開発とコンパイルを提供します。 4. 特定の関数の実装と実装に役立つ Java 関数に対する Oracle の要件を満たします。

PHP および Oracle データベースで接続プーリングを効率的に使用する方法 はじめに: PHP アプリケーションを開発する場合、データベースの使用は不可欠な部分です。 Oracle データベースと対話する場合、アプリケーションのパフォーマンスと効率を向上させるには接続プールの使用が重要です。この記事では、PHP で Oracle データベース接続プールを効率的に使用する方法と、対応するコード例を紹介します。 1. コネクションプーリングの概念とメリット コネクションプーリングとは、データベースのコネクションを管理する技術で、あらかじめコネクションをまとめて作成し、コネクションを維持します。

Oracle でテーブル スペース サイズをクエリする手順: 1. データベース管理者アカウントを使用して Oracle データベースにログインします; 2. 「SELECT」ステートメントを使用してスペース リストを表示します; 3. テーブル スペース サイズをクエリするには 3 つの方法があります: dbms_utility パッケージを使用してクエリを実行し、dba_segments ビュー クエリを使用して、dba_data_files ビュー クエリを使用します; 4. 「DBMS_OUTPUT.PUT_LINE」関数またはその他のメソッドを使用して結果を表示し、クエリ結果を表示します。
