回答

收藏

Sybase:尝试锁定select上的记录,以便另一个调用者无法获得相同的记录

技术问答 技术问答 282 人阅读 | 0 人回复 | 2023-09-13

我在Sybase中有一个简单的表,可以说它看起来如下:
0 z% s" {1 C1 E* l# SCREATE TABLE T2 ^' E% r+ j$ ^4 |
($ n6 H: J+ n0 `- z* b+ ^3 s
   name VARCHAR(10),: Z% v8 k. I4 u
   entry_date datetime,
8 D7 k0 o) n) c/ L   in_use CHAR(1)5 Q7 q7 e7 T9 h: `4 w
)
  {9 H  P1 J. L6 W我想根据“ entry_date”的顺序获取下一个条目,并立即将“ in_use”更新为“
* e2 K! s# Y+ x4 Q/ \- O+ V3 mY”,以指示该记录不可用于接下来的查询。我想同时阻止第二个查询,以便同时运行该查询,这样它就不会捕获相同的记录。/ J8 I+ O9 b" h, N/ |$ Z# }* R- M2 `
问题是我发现如果有ORDER BY子句,则无法在Sybase中执行“ SELECT FOR  h2 ~4 g) k9 [  }
UPDATE”,因此由于以下错误而导致无法创建以下存储的proc,这是由于select-中的ORDER BY子句引起的使用只读游标时,错误地指定了“ FOR$ i0 f! s" U, R9 q: a
UPDATE”。
; l, b. g- ?/ y6 r5 B) @+ W是否有更好的方法来获取下一条记录,将其锁定并一步一步更新所有记录?( W' J: {: Q2 [2 K3 O' |) O+ \: E7 ?
7 E' D  ^+ @+ k
CREATE PROCEDURE dbo.sp_getnextrecord
# a! }, q& H5 n7 T( T. a( z@out1 varchar(10) out,2 y; F1 x$ e! h1 `
@out2 datetime out
, w7 U8 e& @8 i' MAS
! F9 O& Y7 F4 y7 d/ yDECLARE @outOne varchar(10), @outTwo datetime
; Q) l+ p9 c; u# t3 ^8 KBEGIN TRANSACTION) z) Y9 S, X8 ~1 ~; j8 m9 L
-- Here is the problem area Sybase does not like the, d3 H: h6 l% A) w/ V3 S: ?0 T7 ~' r
-- combination of 'ORDER BY' and 'FOR UPDATE' 7 _9 s" P  k3 e' d3 c; i
DECLARE myCursor CURSOR FOR
8 i/ z- ^  c0 kSELECT TOP 1 name, entry_date FROM T
( J  o" F; M' s2 t7 V5 s( q+ IWHERE in_use = 'N'0 O1 i3 l# v! p
ORDER BY entry_Date asc FOR UPDATE OF in_use3 l$ z; S4 C' J  P+ p
OPEN myCursor/ q$ y: @4 g, K: F2 i2 Z
FETCH NEXT FROM myCursor
- H$ u, T. ?0 y- H3 i7 E5 L1 [7 ?INTO @outOne, @outOne; y& f* @+ a9 S0 O. y
-- Check @@FETCH_STATUS to see if there are any more rows to fetch.. D+ m' N0 z& p% }4 U; i
WHILE @@FETCH_STATUS = 0! ^; Q( f) A- Q
BEGIN
& a* v" A$ ?& Y7 g   UPDATE t SET IN_USE = 'Y' WHERE
7 Q: d# r! D; ?3 ~     name = @outOne AND entry_date = @outTwo
8 f% W  `# D# L4 Z" l   SELECT @out1 = @outOne; ^/ u% X, Z( C+ t; D
   SELECT @out2 = @outTwo
" o! x7 ~8 x$ d! N7 s   -- This is executed as long as the previous fetch succeeds.
) l+ [3 ]- V  L5 _: T6 S$ O   FETCH NEXT FROM myCursor- z0 S+ G0 C. G% B! ^' x# K3 B
        INTO @outOne, @outTwo
0 ~" y5 Y! P$ b3 g+ z$ J' v+ IEND
7 @7 k/ ]* s8 @' U6 \: tCLOSE myCursor
5 Y/ `! c) H6 C6 P5 ZDEALLOCATE myCursor% E. [- p4 A) O/ j8 g7 j- `
COMMIT TRANSACTION) \" ^% K# |8 S& I
               
6 g  f4 D& p' S! ^% n2 ?7 X! V4 o解决方案:
4 x6 J) V; S* [' G. h! W                7 W+ N. [, ]. E  R% ~

$ b2 v+ @7 c) ^- M
1 m. a& n6 W7 ~                由于您仅选择一行(顶部1),所以为什么不使用标准的锁定提示而忘记光标:
% T$ c* E9 o& E- i0 zBEGIN TRANSACTION  V) P! u4 X2 T
SELECT @PK=ID FROM YourTable WITH (UPDLOCK, HOLDLOCK, READPAST) WHERE ...
1 W6 ^/ W& z! ^$ EUPDATE ....
# b! L% N# A  w7 k$ z- Z% GWHERE pk=@PK8 b7 b  w7 ^* j: V# K5 r; C# F
COMMIT+ b/ }# q, X0 U% e. ?4 Z9 V' U# q/ t' {
如果您确实需要循环播放,请使用Google“ CURSOR FREE LOOP”+ Z% W% q! @  ]: n0 B7 _
您可以使用SELECT上的锁定提示通过选择下一个MIN(PK)> @ CurrentPk来循环。
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则