由于我们公司一个数据库两个应用在使用,导致一个应用修改了数据库,另一个应用用的缓存而不知道有更新还是原来的结果。原来的处理方式是采用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是不会有任何变化。

  

--------------------------------------------------------------

由于我们的用户还有在用9i的数据库,所以放弃了上面的办法,还是采用加触发器的办法。

一开始我想将改变记录写在一个表里,但找了一下项目里没有一个恰当的表来记录这种数据,又不想随便加到一个表里,不就是一个计数器嘛,就想用序列来进行记录。

于是触发器这样写

CREATE OR REPLACE TRIGGER RECORD_DEPT_SCN
AFTER INSERT OR UPDATE OR DELETE ON DEPARTMENT
DECLARE temp NUMBER;
BEGIN
SELECT DEPT_SCN.NEXTVAL INTO temp FROM DUAL;
END;

在触发器里实现序列的自增,在oracle里我没有找到直接增加序列的方法,只能用这种曲线救国的方式了。(另外有一种直接去改序列底层对应的表sys.seq$的HIGHWATER字段,但这样太有侵入性了,还是算了)

序列这样写

DECLARE exist number;
BEGIN
SELECT COUNT(1) INTO exist FROM USER_SEQUENCES WHERE SEQUENCE_NAME='DEPT_SCN';
IF exist = 0 THEN
EXECUTE IMMEDIATE
'CREATE SEQUENCE DEPT_SCN
INCREMENT BY 1
START WITH 1
MAXVALUE 999999999
NOCACHE';
END IF;
END;

先判断有这个序列没,如果没有才创建。因为我们的sql在每一次项目启动的时候都会执行,所以必须做判断是否存在。

  这里我还学到一个新知识点,就是序列的CACHE,一般默认情况下是20,这个缓存的意义是多个connection来操作这个序列的时候,为了让性能更高,尽量少出现并发争夺,而采用的一种策略,比如cache是20,当前值是0,一个connection来了就把1到20的值全给这个connection用,connection在这个范围内自增序列不用再去访问序列本身了,以此类推另一个connection来了就把21到40给他用,所以这样就效率会提高,序列也会保证递增和唯一,但是不能保证连续,我这个应用想保持连续,而且使用频率是很少的,所以不担心什么性能问题,就不用CACHE了。

  另外说一个问题,就是你想调用序列的currval,必须先调用nextval,否则会报ORA-08002: 序列 SEQ1.CURRVAL 尚未在此会话中定义的错误,我想原因就是这个connection没去调用nextval,就是没分配给他一个缓存断,所以必须先调用。那么我想看当前值还得先自增一次,显然不科学,在 USER_SEQUENCES视图里的LAST_NUMBER就是这个系列的nextval的值,但通过SELECT LAST_NUMBER - 1 FROM USER_SEQUENCES WHERE SEQUENCE_NAME = 'DEPT_SCN' 获取的序列当期值可以不让序列自增一次,但是如果你用了CACHA这里获取的LAST_NUMBER其实是给出去缓存数之后下一次再给出缓存数开始的值,比如CACHA是20,你调用了一个nextval,那么去看这个值已经是21了。所以NOCACHE才能保证这里LAST_NUMBER - 1显示的是当前值。

  最难的问题解决了,剩下就是在项目里使用了,这个没什么难度就不说了,完成。

查看Orcale数据里的表是否有变化的更多相关文章

  1. 获取Access数据里所有表的名称和表的字段

    -------------//获取Access数据库表名        public void GetTableName()        {                string connSt ...

  2. 快速恢复update了的orcale数据表

    在update的时候 没有写条件 将整个表中的数据全部都更新了,这时候怎么办呢? orcale提供了以下的方法产看某一个时间戳, 所执行的sql的语句内容, 同时可以利用该这个时间戳查看当时语句执行显 ...

  3. 利用DBCC PAGE查看SQL Server中的表和索引数据

    16:08 2013-01-06 参考http://doc.chinaunix.net/sqlserver/200810/206034.shtmlDBCC PAGE|IND 参数 DBCC PAGE ...

  4. 快速查看SQL Server 中各表的数据量以及占用空间大小

    快速查看SQL Server 中各表的数据量以及占用空间大小. CREATE TABLE #T (NAME nvarchar(100),ROWS char(20),reserved varchar(1 ...

  5. 在SSMS里查看TDS数据包内容

    原文:在SSMS里查看TDS数据包内容 在SSMS里查看TDS数据包内容 摘抄自<SQLSERVER2012实施与管理实战指南> 要具体查看TDS数据库的内容,我们可以: 用NETWORK ...

  6. MySQL的表分区详解 - 查看分区数据量,查看全库数据量----转http://blog.csdn.net/xj626852095/article/details/51245844

    查看分区数据量,查看全库数据量 USE information_schema; SELECT PARTITION_NAME,TABLE_ROWS FROM INFORMATION_SCHEMA.PAR ...

  7. postgresql基本操作:查看数据库、索引、表、表空间大小

    一.简介 PostgreSQL 提供了多个系统管理函数来查看表,索引,表空间及数据库的大小,下面详细介绍一下. 二.数据库对象尺寸函数 函数名 返回类型 描述 pg_column_size(any) ...

  8. 查看mysql字符集及修改表结构--表字符集,字段字符集

    MySQL 乱码的根源是的 MySQL 字符集设置不当的问题,本文汇总了有关查看 MySQL 字符集的命令.包括查看 MySQL 数据库服务器字符集.查看 MySQL 数据库字符集,以及数据表和字段的 ...

  9. MySQL的奇怪的删表数据文件而表照样能打开

    MySQL的奇怪的删表数据文件而表照样能打开 author:headsen  chen      2017-11-02   17:57:17 现象:删除一个正在运行的mysql数据库的表的数据文件:* ...

随机推荐

  1. php导出excel再IE下乱码问题

    $userBrowser = $_SERVER['HTTP_USER_AGENT']; //判断是否是ie内核 $fileName = '会员列表-'.date('Y-m-d', time()).'. ...

  2. JQuery基本知识汇总;JQuery常用方法;浅入了解JQuery

    一.jQuery对象与JavaScript对象 ①JavaScript入口函数比jQuery入口函数执行的晚一些: JQuery的入口函数会等页面加载完成才执行,但是不会等待图片的加载: JavaSc ...

  3. Scoop及使用

    scoop window的命令行安装程序管理工具 通常我们下载软甲需要从网上搜索软件并下载安装等一系列复杂麻烦的过程 现在有了scoop 等一系列包管理器的诞生,就是省去了上述繁琐的搜索 - 下载 - ...

  4. Kotlin入门(3)基本变量类型的用法

    上一篇文章介绍了Kotlin在App开发中的简单用法,包括操纵控件对象.设置控件监听器,以及弹出Toast提示等等.也许大家已经迫不及待想要了解更深入的App开发,可是由于Kotlin是一门全新的语言 ...

  5. linux Mate Lxde 消耗资源对比

    腾讯云 标准型SA1 | SA1.SMALL1 1核1G AMD LXDE: MATE:

  6. Expect 安装 on centos7

    本文演示如何在CentOS7上安装和使用Expect. 使用场景 在主机A上编写并且执行Shell脚本,Shell脚本中需要ssh到主机B上执行交互命令. 安装 在主机A上安装expect: yum ...

  7. 1.Spring MVC详解

    目录 1.SpringMVC 详细介绍 2.SpringMVC 处理请求流程 3.配置前端控制器 4.配置处理器适配器 5.编写 Handler 6.配置处理器映射器 7.配置视图解析器 8.Disp ...

  8. The Tomcat connector configured to listen on port 8080 failed to start. The port may already be in use or the connector may be misconfigured

    springboot 8080端口被占用报错:The Tomcat connector configured to listen on port 8080 failed to start. The p ...

  9. 关于SQL Server将一列的多行内容拼接成一行,合并显示在另外表中

    select '['+title_a+','+title_b +']' from A   for xml path('') SELECT *, (select '['+title_a+','+titl ...

  10. 第七章 鼠标(CHECKER2)

    CHECKER2程序包含一个键盘接口,内容与CHECKER1完全相同.利用←.→.↑.↓四个方向键可以在25个矩形之间移动鼠标指针.Home键把鼠标指针移动到左上角的矩形:End键使鼠标指针落到右下角 ...