Oracle DB锁表使用
最近我有一个任务,根据该任务,我需要具有特定的锁定功能。具体原因是:
- 正在更新的交易 桌子是分发的,所以我没有 控制它,
- 白天 数千个非阻塞事务 必须同时支持, 我们称它们为“常规”操作,
- 每个“常规”操作都会更新特定“分支”(“LDN”、“NY”、“LA”...)上的行,
- 一天一次有一位“大师” 每个分支的操作,这些操作在不同的分支上发生,
- 在“主”操作期间没有 该分支上可能会发生“常规”操作。
- 当“主”操作启动时 必须等待当前的“将军” 对所提供的分支完成进行操作, 在“主”操作到达之前系统中已存在这些内容。
- 在特定分支上进行“主”处理期间,所有其他分支都可以 已更新。
为了存档此内容,我创建了 Oracle DB 特定表
create table BRANCH_LOCK(
BRANCH VARCHAR2(10),
FLAG VARCHAR2(1),
CONSTRAINT "PK_BRANCH_LOCK" PRIMARY KEY ("BRANCH")
)
支持不同操作的以下功能:
对于“常规”操作:
<前><代码>1。在同一个 XA 事务中,每个操作都会锁定 BRANCH_LOCK 表 在共享模式下, 2.锁定后检查FLAG,在更新的分支上, 1.如果flag为'Y',则表示当前为'master' 操作正在进行中,因此抛出异常, 并且不进行进一步处理; 2.如果flag为'N'则一切正常,一般处理完成;
对于“主”操作:
- 当“主”操作到来时,我启动单独的事务:
- 以 EXCLUSIVE 模式锁定 BRANCH_LOCK 表,当该表在不同事务中存在 SHARE 模式锁时,该事务无法获取该表(这样,我保证“master”操作将在所有当前“常规”操作完成后开始,尽管它等待所有分支机构的交易 完成,不只指定一个),
- 将分支的标志设置为“Y” (这样,我保证在“master”时不会有“一般”交易 操作处理),
- 在传入交易中,我将表中的标志更改为“N”,因此之后 它提交 BRANCH_LOG 表将有 FLAG 列中的适当值,系统将 能够处理“一般” 再次操作。
这还没有投入生产,所以我想知道是否有更好的解决方案, 除了所描述的缺点之外,还有其他缺点吗?
一些更新,我没有提到:
- “主”操作适用于“常规”操作的结果,因此至关重要的是,在“主”处理期间不会丢失“常规”操作,这就是为什么当前的“常规”操作操作必须在主操作开始处理之前完成。
- 同一分支上每秒发生多个“常规”操作,每秒大约 3'000 次操作,
- 该分支只能发生一个“主”操作,可以同时处理不同分支上的多个“主”操作。
Recently I had a task, according to which, I needed to have a specific lock functionality. The specific was due to:
- Transaction that was updating
table was distributed, so I had no
controll over it,- During the day
thousands non blocking transactions
must be supported simultaniously,
lets call them 'general' operations,- Each 'general' operation updated rows on specific 'branch' ("LDN","NY","LA" ...),
- Once a day there is a 'master'
operation for each branch, which happen spanteniously, on different branches,
- During 'master' operation no
'general' operations on that branch can happen.- When 'master' operation start it
must wait for current 'general'
operation on the provided branch completion,
which were in the system before 'master' operation arrived.- Durring 'master' processing on a specific branch, all other branches can be
updated.
In order to archive this, I created Oracle DB specific table
create table BRANCH_LOCK(
BRANCH VARCHAR2(10),
FLAG VARCHAR2(1),
CONSTRAINT "PK_BRANCH_LOCK" PRIMARY KEY ("BRANCH")
)
The following functionality for different operations was supported:
For 'general' operations:
1. In the same XA transaction each operation locks BRANCH_LOCK table in SHARE mode, 2. After locking it checks FLAG, on updated branch, 1. If flag is 'Y', that means that currently 'master' operation is in progess, so Exception is thrown, and no further processing is done; 2. If flag is 'N' than everything is OK, and general processing is done;
For 'master' operation:
- When 'master' operation comes I start separate transaction which:
- Lock BRANCH_LOCK table in EXCLUSIVE mode, which transaction can not acquire while there is SHARE mode LOCK on this table in a different transaction (This way, I guarantee that 'master' operation would start after all current 'general' operation finish, although it waits for transactions on all branches
to finish, not only specified one),- Sets flag for the branch to 'Y'
(This way, I guarantee that there would be no 'general' transactions while 'master'
operation processing),- In incoming transaction I change a Flag in the table to 'N', so after
it commits BRANCH_LOG table will have
appropriate value in FLAG column, and system would
be able to process 'general'
operations again.
This has not gone in production yet, So I wonder is there a better solution for this,
and are there any more drawbacks besides described one?
Some updates, which I did not mention:
- 'Master' operation works on results of 'general' operations, So it is vital, that no 'general' operation get lost, durring the 'master' processing, so this why current 'general' operation must finish, before master operation start processing.
- Multiple 'general' operations on the same branch happen every second, arround 3'000 operations per second,
- Only one 'master' operation for the branch can happen, multiple 'master' operations on different branches can be processed at the same time.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
安东,
为什么您需要手动锁定表?通常情况下不需要这样做。当您描述的主操作启动时,它会获得在该主事务开始时提交的数据的读取一致视图。一般事务可以继续工作,并且您描述的主事务不会看到更改,直到它启动新事务。
Anton,
why exactly do you need to manually lock the table[s]? Normally there is no need to do such. When the master operation you describe starts, it get's a read consistent view of the data that is committed at the start of that master transaction. The general transactions can continue to work and the master transaction you describe will not see the changes, until it starts a new transaction.
我想我不会构建自己的锁表,而是尝试使用 Oracle 的锁定包 DBMS_LOCK。
它比使用DML做锁效率更高,并且是Oracle内部用来执行入队锁定的。
Rather than build my own lock table, I think I'd try to use Oracle's locking package DBMS_LOCK.
It's more efficient than using DML to do locks, and is what Oracle uses internally to perform enqueue locking.
表的体积是多少。
我会考虑让 master 操作像这样启动
,这将使用标准 Oracle 锁定来确保 do_master 等待,直到锁定这些分支的未完成的一般事务完成,然后由 do_master 获取锁,停止任何其他一般更新,直到它提交。然后这些一般更新就会恢复。
但如果卷很大,那么 SELECT...FOR UPDATE 可能会非常大。那时我会考虑 DBMS_LOCK 解决方案。
What are the table volumes.
I'd consider having the master operation start like
That would use standard Oracle locking to ensure that the do_master waits until outstanding general transactions locking those branches complete, then the locks are taken by do_master stopping any other general updates until it commits. Then those general updates resume.
But if the volumes are big, then that SELECT...FOR UPDATE could be very large. That's when I'd consider a DBMS_LOCK solution.