由于我们公司一个数据库两个应用在使用,导致一个应用修改了数据库,另一个应用用的缓存而不知道有更新还是原来的结果。原来的处理方式是采用session缓存的方式,用户登出了就清空缓存,这样只需要重新登录一次就得到最新的快照放在缓存中了,但现在新的要求是不登出就要实时刷新改了的内容。其实这种方式最好的处理办法是一个应用改了数据库通知另一个应用去刷新缓存,但是线下应用用vb写的成熟的产品,都是一帮老员工很难让他们去改点东西来适合新应用,都是新应用去套他们的。领导本来说直接不用缓存了,每次去读数据库,我觉得这样解决问题太粗暴了,之前的努力都白费了,就想通过一种查询数据库表是否改变了的方式进行折中处理,在应用里记录一个版本号或者最后修改时间,每次先去数据库读一次看看有没有变化,如果有变化就刷新缓存,如果没有变化就用缓存里的。
我最先想到的是触发器,的确是可以这样实现,但最好不要这样做,因为数据库是另一个项目主要在用,我们不能去过多的改变数据库。我们项目支持的是oracle数据库,user_objects表里有个LAST_DDL_TIME字段,但这个不是我想要的,我想要表DML操作的记录。9i以上可以在user_tab_modifications视图里查找到想要的信息,user_tab_modifications收集自采集信息以来被改变表的dml操作量数据,一个表只有数据量被改变10%以上才会被定期采集信息,也可以执行过程
DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO进行实时采集。
These views are populated only for tables with
the MONITORING
attribute.
They are intended for statistics collection over a long period of time. For
performance reasons, the Oracle Database does not populate these views
immediately when the actual modifications occur. Run
the FLUSH_DATABASE_MONITORING_INFO
procedure
in
the DBMS_STATS
PL/SQL
package to populate these views with the latest information.
The ANALYZE_ANY
system
privilege is required to run this procedure.
所以用这种方式是不行的,为了时实还得不断地去执行exec
dbms_stats.FLUSH_DATABASE_MONITORING_INFO这个命令,这种方式对数据库操作太多了。
于是有了下面这种方式:ora_rowscn
oracle 10G开始提供的一个伪列ORA_ROWSCN,它又分为两种模式一种是基于block这是默认的模式(块级跟踪);还有一种是基于row上,这种模式只能在建里表时指定ROWDEPENDENCIES(行级跟踪),不可以通过后期的alter table语句来将表修改为ROWDEPENDENCIES。我只需要判断这个表有没有被DML语句操作所以只需要用第一种模式就可以了,不需要精确到row上,所以简单用第一种就可以了。
我们知道,每个Block在头部是记录了该block最近事务的SCN(SystemChangeNumber)的,所以默认情况下,只需要从block头部直接获取这个值就可以了,不需要其他任何的开销,Oracle就能做到这一点。但是这明显是不精确的,一个block中会有很多行记录,每次事务不可能影响到整个block中所有的行,所以这是一个非常不精准的估算值,同一个block的所有记录的ORA_ROWSCN都会是相同的,基本上没有多大的使用价值。
如果在建表的时候开启行级跟踪选项,Oracle则可以为每一行记录精确的SCN,那么显然不能再直接从block头部获取。要获得足够的信息,肯定要付出一定的代价,Oracle必须为每一行存储这个实际的SCN。所以这个行级跟踪的选项,只能在建表的时候指定,而不能通过alter
table来修改现有的表,否则需要修改每一行记录的物理存储格式,代价是可想而知的。
在10g之前,很多系统要实现增量数据抽取,要么通过解析日志,要么加触发器,要么就在表上加一个时间截字段。ORA_ROWSCN其实就是第三种方式,只是这个字段由Oracle来维护,这样可以避免一些应用绕过时间截去更新其他字段带来的问题。
第一种方式(块级跟踪):
select ora_rowscn,
dbms_rowid.ROWID_BLOCK_NUMBER(rowid)
blockid,
scn_to_timestamp(ora_rowscn)
from hs_futures.fuentrust
t
order by scn_to_timestamp(ora_rowscn);
dbms_rowid.ROWID_BLOCK_NUMBER(rowid):是为获取数据所在块的ID
scn_to_timestamp(ora_rowscn):获取数据最所修改的时间
数据发现变化后通过上面SQL语句可以查看到数据最后修改的时间,注意因为是同一个块上,所以这个块上只要有DML操作那么所有数据的scn都更新了,所以凡是跟这条记录在同一个块上数据获取到的ora_rowscn和scn_to_timestamp(ora_rowscn)两个值都发生了相应的变化。
第二种方式(行级跟踪):
create table hs_futures.fuentrust_test1 rowdependencies as
select * from hs_futures.fuentrust
用以上语句创建一个基于ROWDEPENDENCIES模式的表,然后用第一种方法中的SQL去查询此表数据中的ora_rowscn,scn_to_timestamp(ora_rowscn)两个值,修改其中的某一条记录然后再去查询那个值发现发生变化的只是被修改那条记录的这两个值发生了变化,而在同一个块中没有被修改的其它记录这两个值是不会产生变化的。
注意DDL操作:只要现有表记录中的数据有发生变化那么SCN肯定就会发生更新,如删除有数据的列,但是如果索引删除/修改/增加及增加/者删除没有任何数据的列那么SCN是不会有任何变化。
查看Orcale数据里的表是否有变化,布布扣,bubuko.com