回答

收藏

SQL Server:与Oracle中的RowVersion等效

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

Oracle是否具有与SQL ServerRowVersion相似的数据类型?
& K; L# c% _! a  e1 x5 E: J) F当您插入或更新一行时,相应的Version列(类型为RowVersion)会自动更新。$ _' @4 m4 }+ z( Z! m9 B( `' t
MSDN说到RowVersion$ b7 Z9 [6 _% B4 J

9 t" X6 Z% o% @4 Z3 V- i# o- r; ]/ @  b, Y. D6 M( g1 ^( K5 v. P
*
; W/ P0 Z3 I( ]! ~是一种数据类型,它公开了数据库中自动生成的唯一二进制数。rowversion通常用作版本标记表行的机制。存储大小为8个字节。rowversion数据类型只是一个递增数字,并不保留日期或时间。
6 k3 \9 \# d+ f1 {*
$ u: n3 [# T* l0 U* x$ [3 {每个数据库都有一个计数器,该计数器针对在数据库中包含rowversion列的表上执行的每个插入或更新操作递增。此计数器是数据库行版本。这将跟踪数据库中的相对时间,而不是可与时钟关联的实际时间。一个表只能有一个rowversion列。每次修改或插入具有rowversion列的行时,数据库增量rowversion值都会插入到rowversion列中。
4 ?- e3 H! u% F! ]4 G. o*; x) Q. S  q9 O7 d$ k( i" y8 x
您可以使用一行的rowversion列轻松确定自上次读取该行以来,该行中的任何值是否已更改。如果对该行进行了任何更改,则将更新rowversion值。如果未对行进行任何更改,则rowversion值与先前读取的值相同。
9 f* ~- T* e0 f/ f" p* R您可以在表中添加rowversion列,以在多个用户同时更新行时帮助维护数据库的完整性。您可能还想知道多少行以及更新了哪些行而无需重新查询表。& t" P- t$ U3 [2 w. `( y' }3 _

8 ~2 U. ?* @3 c; S1 S
* I3 N$ Y8 @5 f( ~# A+ e
我们正在使用oracle设计数据模型,并希望使用Version列来管理并发。
1 a$ w( p) }6 T& P# G+ e% A我也想知道在Oracle世界中是否有更好的方法。4 k5 N3 T  w/ Q; r5 }# }, T/ {
                5 A) K: w/ ?$ W6 O% j
解决方案:% c2 y5 C$ P5 E0 u1 W5 L+ R' f5 |9 c8 a
                4 L& H4 o8 H! ~; @* `4 q  X) J

, O. Z! Q& G" V+ L4 y  f
! U# x0 _9 t6 u  m/ i                简单的答案是“否”-但是使用NUMBER列和设置/更新它的触发器来创建自己很容易。
; I6 [& @1 [) DOracle 11gR2的一个简单示例:' ~, L; b+ b7 d2 V; [( J
CREATE SEQUENCE global_rowversion_seq;
( C4 I5 ~4 I( T) bALTER TABLE mytable1 ADD rowversion NUMBER;# u9 {7 d! b6 U, D0 i
ALTER TABLE mytable2 ADD rowversion NUMBER;& a+ l$ t4 {1 w# @3 i
CREATE TRIGGER mytable1_biu
6 U8 Q! D" ?7 c/ |4 E   BEFORE INSERT OR UPDATE! s4 B! @, j: M" B
   ON mytable1  u: s* M, ^- L
   FOR EACH ROW
* J( ?) C" o; Z/ aBEGIN
3 G/ n* G! f$ L; S  :NEW.rowversion := global_rowversion_seq.NEXTVAL;
6 q+ W4 Y' T5 _( P; {END mytable1_biu;
9 u/ d) D1 P4 u% j3 NCREATE TRIGGER mytable2_biu" u/ O" m! ]: B+ f" W2 S4 w
  BEFORE INSERT OR UPDATE+ y3 {( j) h: K6 ?
  ON mytable2
$ e+ v* W7 e& e; {$ g0 \  }  FOR EACH ROW! x5 D8 X. F+ y% y
BEGIN1 K& W0 B. z# P7 f1 R* g6 e2 g# W
  :NEW.rowversion := global_rowversion_seq.NEXTVAL;
6 F* `  e5 s+ ?  s6 k# [& @( _' ^END mytable2_biu;0 u8 O7 p8 B% E3 [
(如果您使用的是较早的Oracle版本,则触发器中的分配必须通过查询来完成,例如:# C* V. w5 E7 H: {8 a5 n2 u+ N
  SELECT global_rowversion_seq.NEXTVAL* k- C) D! H3 [1 N0 |% H* \
  INTO :NEW.rowversion* P: }+ I- B/ j" c( {, {% C. m
  FROM dual;: d0 X0 }1 o3 c' i+ X
现在,请记住,在某些情况下,由于所有使用相同序列进行数据库插入/更新的争用,该设计在极端情况下(例如,具有极高插入/更新活动的数据库)可能会对性能产生影响。当然,在这种情况下,您可能首先会避免触发。
+ m& r5 x! z& D/ E根据您使用rowversion列的方式,最好对每个表使用单独的序列。当然,这意味着行版本将不再是全局唯一的-
, e7 Q' ]2 y( n但是,如果您仅对比较表中行的更改感兴趣,那么就可以了。  T% n5 s0 r  x; s! `
另一种方法是分别为每一行增加计数器-这不需要序列,并且允许您检测到行的更改(但不允许将任何行与另一行进行比较):- V" K: k- ]6 Q  N% T/ ~, N
ALTER TABLE mytable ADD rowversion NUMBER;! M6 `) I7 N+ o% J  R9 r
CREATE TRIGGER mytable_biu
- f0 }9 o8 J7 x; \. J6 h  BEFORE INSERT OR UPDATE
1 y! b" S! z: e- i" u4 O) d. Z  ON mytable2 q2 a' q9 C$ T" V3 V8 \
  FOR EACH ROW0 c5 g1 G% S5 z6 Z$ n4 E. N, j
BEGIN4 y! O; U+ K9 f+ i' a7 r3 Y3 z
  :NEW.rowversion := NVL(:OLD.rowversion, 0) + 1;
* x% j; ~# c3 J; Q4 |. _: K1 J3 QEND mytable_biu;
/ N* Q- |  Y9 o+ q0 S$ G6 i每行将以rowversion = 1插入,然后对该行的后续更新会将其递增为2、3,依此类推。
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则