Fal*_*que 15 sql sql-server oracle rowversion
Oracle是否具有与SQL ServerRowVersion类似的数据类型?
插入或更新行时,相应的"版本"列(类型RowVersion)会自动更新.
是一种在数据库中公开自动生成的唯一二进制数的数据类型.rowversion通常用作版本标记表行的机制.存储大小为8个字节.rowversion数据类型只是一个递增的数字,不保留日期或时间.
每个数据库都有一个计数器,该计数器针对在数据库中包含rowversion列的表上执行的每个插入或更新操作递增.此计数器是数据库rowversion.这会跟踪数据库中的相对时间,而不是可以与时钟关联的实际时间.一个表只能有一个rowversion列.每次修改或插入具有rowversion列的行时,都会在rowversion列中插入递增的数据库rowversion值.
您可以使用行的rowversion列轻松确定自上次读取行以来该行中的任何值是否已更改.如果对该行进行了任何更改,则会更新rowversion值.如果没有对该行进行任何更改,则rowversion值与先前读取的值相同.
您可以向表中添加rowversion列,以便在多个用户同时更新行时帮助维护数据库的完整性.您可能还想知道在不重新查询表的情况下更新了多少行和哪些行.
我们正在使用oracle设计数据模型,并希望使用Version列来管理并发.
我还想知道Oracle世界中是否有更好的方法.
kro*_*lko 17
Oracle有SCN(系统变更号):http://docs.oracle.com/cd/E11882_01/server.112/e10713/transact.htm#CNCPT039
系统更改编号(SCN)是Oracle数据库使用的逻辑内部时间戳.SCN对数据库中发生的事件进行排序,这是满足事务的ACID属性所必需的.Oracle数据库使用SCN标记SCN,在此之前已知所有更改都在磁盘上,以便恢复避免应用不必要的重做.数据库还使用SCN标记一组数据不存在重做的点,以便可以停止恢复.
SCN以单调递增的顺序发生.Oracle数据库可以像时钟一样使用SCN,因为观察到的SCN表示逻辑时间点,重复观察返回相等或更大的值.如果一个事件的SCN低于另一个事件,则它在较早的时间发生在数据库中.多个事件可能共享相同的SCN,这意味着它们与数据库同时发生.
每笔交易都有一个SCN.例如,如果事务更新了一行,则数据库会记录发生此更新的SCN.此事务中的其他修改具有相同的SCN.当事务提交时,数据库会记录此提交的SCN.
使用ORA_ROWSCN伪列来检查行的当前SCN:
http
://docs.oracle.com/cd/B28359_01/server.111/b28286/pseudocolumns007.htm#SQLRF51145
示例:
SELECT ora_rowscn, t.* From test t;
Run Code Online (Sandbox Code Playgroud)
演示 - > http://www.sqlfiddle.com/#!4/535bc/1
(在SQLFiddle显式提交显然不起作用 - 在真实数据库上每次提交都会增加SCN).
关于"真实"数据库的示例:
CREATE TABLE test(
id int,
value int
);
INSERT INTO test VALUES(1,0);
COMMIT;
SELECT ora_rowscn, t.* FROM test t;
ORA_ROWSCN ID VALUE
---------- ---------- ----------
3160728 1 0
UPDATE test SET value = value + 1 WHERE id = 1;
COMMIT;
SELECT ora_rowscn, t.* FROM test t;
ORA_ROWSCN ID VALUE
---------- ---------- ----------
3161657 1 1
UPDATE test SET value = value + 1 WHERE id = 1;
COMMIT;
SELECT ora_rowscn, t.* FROM test t;
ORA_ROWSCN ID VALUE
---------- ---------- ----------
3161695 1 2
Run Code Online (Sandbox Code Playgroud)
如果知道事务的SCN,我们可以使用闪回查询来获取该行的过去值:
http
://docs.oracle.com/cd/B28359_01/appdev.111/b28424/adfns_flashback.htm#g1026131
示例:
SELECT t.*,
versions_startscn, versions_starttime,
versions_endscn, versions_endtime,
versions_xid, versions_operation
FROM test VERSIONS BETWEEN SCN MINVALUE AND MAXVALUE t;
ID VALUE VERSIONS_STARTSCN VERSIONS_STARTTIME VERSIONS_ENDSCN VERSIONS_ENDTIME VERSIONS_XID VERSIONS_OPERATION
---------- ---------- ----------------- ------------------- --------------- ------------------- ---------------- ------------------
1 2 3161695 13/12/10 08:19:39 06000300EA070000 U
1 1 3161657 13/12/10 08:18:39 3161695 13/12/10 08:19:39 06001200EA070000 U
1 0 3161657 13/12/10 08:18:39
SELECT t.*,
versions_startscn, versions_starttime,
versions_endscn, versions_endtime,
versions_xid, versions_operation
FROM test VERSIONS BETWEEN SCN 3161657 AND 3161657 t;
ID VALUE VERSIONS_STARTSCN VERSIONS_STARTTIME VERSIONS_ENDSCN VERSIONS_ENDTIME VERSIONS_XID VERSIONS_OPERATION
---------- ---------- ----------------- ------------------- --------------- ------------------- ---------------- ------------------
1 1 3161657 13/12/10 08:18:39 06001200EA070000 U
Run Code Online (Sandbox Code Playgroud)
简单的答案是“否”-但是使用NUMBER列和设置/更新它的触发器来创建自己很容易。
Oracle 11gR2的一个简单示例:
CREATE SEQUENCE global_rowversion_seq;
ALTER TABLE mytable1 ADD rowversion NUMBER;
ALTER TABLE mytable2 ADD rowversion NUMBER;
CREATE TRIGGER mytable1_biu
BEFORE INSERT OR UPDATE
ON mytable1
FOR EACH ROW
BEGIN
:NEW.rowversion := global_rowversion_seq.NEXTVAL;
END mytable1_biu;
CREATE TRIGGER mytable2_biu
BEFORE INSERT OR UPDATE
ON mytable2
FOR EACH ROW
BEGIN
:NEW.rowversion := global_rowversion_seq.NEXTVAL;
END mytable2_biu;
Run Code Online (Sandbox Code Playgroud)
(如果您使用的是较早的Oracle版本,则触发器中的分配必须通过查询完成,例如:
SELECT global_rowversion_seq.NEXTVAL
INTO :NEW.rowversion
FROM dual;
Run Code Online (Sandbox Code Playgroud)
现在,请记住,在某些情况下,由于所有使用相同序列进行数据库插入/更新的争用,该设计在极端情况下(例如,具有极高插入/更新活动的数据库)可能会对性能产生影响。当然,在这种情况下,您可能首先会避免触发。
根据您使用rowversion列的方式,最好对每个表使用单独的序列。当然,这意味着行版本将不再是全局唯一的-但是,如果您仅对比较表中行的更改感兴趣,那么就可以了。
另一种方法是分别为每行增加计数器-不需要序列,并且允许您检测到行的更改(但不允许将任何行与另一行进行比较):
ALTER TABLE mytable ADD rowversion NUMBER;
CREATE TRIGGER mytable_biu
BEFORE INSERT OR UPDATE
ON mytable
FOR EACH ROW
BEGIN
:NEW.rowversion := NVL(:OLD.rowversion, 0) + 1;
END mytable_biu;
Run Code Online (Sandbox Code Playgroud)
每行将以rowversion = 1插入,然后对该行的后续更新会将其递增为2、3,依此类推。