楼主: yulihua49

[PRO*C] 看我做的数据库包装器

[复制链接]
论坛徽章:
14
2009新春纪念徽章
日期:2009-01-04 14:52:28沸羊羊
日期:2015-03-04 14:51:52优秀写手
日期:2014-03-14 06:00:13马上有房
日期:2014-02-18 16:42:022014年新春福章
日期:2014-02-18 16:42:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-09 18:08:15蜘蛛蛋
日期:2012-06-27 21:08:142012新春纪念徽章
日期:2012-01-04 11:53:29ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
491#
 楼主| 发表于 2010-3-3 09:51 | 只看该作者
原帖由 newkid 于 2010-3-2 23:56 发表
"处理业务时知道结构就足够了,存取时没必要点名,对着百十来个列名,一看就头大。"

我们的"处理业务"做法是不一样的。你们C程序员的思路:读取数据,处理,写回去;
PLSQL程序员的思路:一个SQL搞定。
比如生成一条交易记录我会这么写:
INSERT INTO TRANSACTIONS (TXN_ID,TXN_TIME,CUSTOMER_ID,ITEM_ID,PRICE,QTY,AMOUNT)
SELECT SEQ_TXN.NEXTVAL,SYSDATE,P_CUSTOMER_ID,P_ITEM_ID,PRICE,PRICE*P_QTY - DISCOUNT)
  FROM ITEMS
WHERE ITEM_ID = P_ITEM_ID
这里面包含了读,写,和所有的处理。你清楚地看到它们的关系。

我看不出为什么不能用一个二维数组来存放数据?你490楼写了一堆OCI_BindString然后说速度不快,我说可以用数组绑定,不必一行一行地逐个绑定。
你要我写出来咱可没办法,再给你GOOGLE个例子:

你可以写一个通用的,先解析数据结构,再循环调用obndra. 当然没那么容易,我只是说可以不用结构。

"根据传送标志卸载并重新标记传送标志。加载时如果遇到重码,以时间戳新的为准。这个简单逻辑你用系统方法给我实现一个。
这用DAU实现很容易。一般都是定时卸载,按需要分发到其他节点。"
我轻而易举用MATERIALIZED VIEW就给你实现了,一行代码也不写。

既然说到时间戳,我且来考考你,这就叫做抬杠不忘布道。你是如何判断增量修改的?

一般人做法:
1.本次刷新时间=系统当前时间
2.SELECT * FROM 源表 WHERE 时间戳>=上次刷新时间
3.把步骤2结果写入目标

你也是这么做的吗?这里面的漏洞看出来没有?

那是个很老的ORACLE7的oci的成组绑定。还是那个问题,个别行的错误是如何定位和处理的?如果:E[2]、[4]、[6]是NULL怎么办?DAU处理成组非常容易,增加一个记录数量就可以了,因为解决不了上述问题才没有做。
另外,那个demo不通用。如果编程时不知表结构呢?运行时才告你,到时候百十来个列你怎么办?
一大堆数组,不是二维数组,因为每个数组类型不同,根本没有存放规则,运行时无法映射,还是要用结构,结构数组。

结构不仅是按名访问成员,更重要的是集合数据形成数据记录,以便数据存取、通信、和在函数间传递。
恰恰是这个最重要的数据存取功能,过去在文件系统时代很合用,到数据库时代傻眼了。DAU恢复了这个功能。

增量修改:如果在局域网内,同数据库,可以考虑复制服务。如果节点远程分布,不一定在线,那么:

需要卸载时间戳,卸载时间戳要改回原表,对比修改时间戳和卸载时间戳。如果多个目标需要数据就乱了。所以我不会直接写新表。
在多目标的情况,由一个任务先卸载原表并更新状态。所有目标读卸载文件加载自己的库。加载可能不按次序或重复,以修改时间戳最新为准。
一个大的系统这种表很多,你不会一个表一个程序的写吧?
别的没看出来,请指教。

char P_ITEM_ID[10];
T_PkgType P_ITEM_tpl[]={
      {CH_CHAR,10,"P_ITEM_ID",0,-1},
      {-1,0,"ITEMS",0}
};
DAU dau;
char stmt[4096];
int ret;

              DAU_init(&dau,SQL_Connect,0,P_ITEM_ID,&P_ITEM_tpl);
               strcpy(P_ITEM_tpl,"abcde");
          sprintf(stmt,"INSERT INTO $DB.TRANSACTIONS (TXN_ID,TXN_TIME,CUSTOMER_ID,ITEM_ID,PRICE,QTY,AMOUNT)
SELECT SEQ_TXN.NEXTVAL,SYSDATE,P_CUSTOMER_ID,P_ITEM_ID,PRICE,PRICE*P_QTY - DISCOUNT)  FROM $DB.ITEMS WHERE ITEM_ID = :P_ITEM_ID");
              ret=DAU_exec(&dau,stmt);

补充一点,在表名前我加了$DB.符号,在安全数据库里可能使用其他用户的表,DAU自动帮你处理属主问题,将来有或者没有属主前缀,通过配置文件决定,程序不要改。
DAU内部替换或删除这个符号。

当然也可以调用sqlora直接做:
定义游标-sqlo_prepare-bind-sqlo_execute- sqlo_prows
比DAU费事。

如果调用存储过程,DAU也不太费事,sqlora比较费事,in,out,inout,返回游标都要处理。
总之,DAU是在OCI和sqlora的基础上简化操作,并提供通用化的手段。

[ 本帖最后由 yulihua49 于 2010-3-3 14:04 编辑 ]

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
492#
发表于 2010-3-4 00:10 | 只看该作者
"那是个很老的ORACLE7的oci的成组绑定。还是那个问题,个别行的错误是如何定位和处理的?如果:E[2]、[4]、[6]是NULL怎么办?DAU处理成组非常容易,增加一个记录数量就可以了,因为解决不了上述问题才没有做。"

我知道PLSQL中轻易可以用SAVE EXCEPTIONS搞定,OCI的我帮你GOOGLE了半天终于找出来这个:
http://www.mscd.edu/~ittsdba/ora ... a76975/oci04sql.htm

看里面的Batch Error Mode for OCIStmtExecute().

"另外,那个demo不通用。如果编程时不知表结构呢?运行时才告你,到时候百十来个列你怎么办?
一大堆数组,不是二维数组,因为每个数组类型不同,根本没有存放规则,运行时无法映射,还是要用结构,结构数组。"
我不是说了吗,通用的也可以做到,无非就是解析模板或者控制文件或者去找数据字典。类型不知道就全部用字符串。一大堆数组就用动态指针指向数组,即数组的数组。

"需要卸载时间戳,卸载时间戳要改回原表,对比修改时间戳和卸载时间戳。如果多个目标需要数据就乱了。所以我不会直接写新表。
在多目标的情况,由一个任务先卸载原表并更新状态。所有目标读卸载文件加载自己的库。加载可能不按次序或重复,以修改时间戳最新为准。"

"卸载时间戳"就是我说的“本次刷新时间”吧?为什么你要写回原表?如果更新的数据很多难道你又把每行更新一遍?你只要把它存在某处,比如你有一个调度任务表,就放在那里好了。

如果我理解有误,你就举一个最最简单的单表复制到单目标的例子,说明你的增量刷新是怎么做的。

我说的漏洞出在更新时间戳,上次说的那个方法会导致数据遗漏,我必须看看你的例子才知道这个问题是否存在。

我那个INSERT SELECT固然可以用你的DAU做到,但是它就不是写个SQL那么简单了,还加了很多东西。因为按我的做法事务处理大多不是单表操作,连接、子查询是很常用的,所以存储过程是最好的选择,在过程里写这些很简单。

使用道具 举报

回复
论坛徽章:
14
2009新春纪念徽章
日期:2009-01-04 14:52:28沸羊羊
日期:2015-03-04 14:51:52优秀写手
日期:2014-03-14 06:00:13马上有房
日期:2014-02-18 16:42:022014年新春福章
日期:2014-02-18 16:42:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-09 18:08:15蜘蛛蛋
日期:2012-06-27 21:08:142012新春纪念徽章
日期:2012-01-04 11:53:29ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
493#
 楼主| 发表于 2010-3-4 10:06 | 只看该作者
原帖由 newkid 于 2010-3-4 00:10 发表
"那是个很老的ORACLE7的oci的成组绑定。还是那个问题,个别行的错误是如何定位和处理的?如果:E[2]、[4]、[6]是NULL怎么办?DAU处理成组非常容易,增加一个记录数量就可以了,因为解决不了上述问题才没有做。"

我知道PLSQL中轻易可以用SAVE EXCEPTIONS搞定,OCI的我帮你GOOGLE了半天终于找出来这个:
http://www.mscd.edu/~ittsdba/ora ... a76975/oci04sql.htm

看里面的Batch Error Mode for OCIStmtExecute().

"另外,那个demo不通用。如果编程时不知表结构呢?运行时才告你,到时候百十来个列你怎么办?
一大堆数组,不是二维数组,因为每个数组类型不同,根本没有存放规则,运行时无法映射,还是要用结构,结构数组。"
我不是说了吗,通用的也可以做到,无非就是解析模板或者控制文件或者去找数据字典。类型不知道就全部用字符串。一大堆数组就用动态指针指向数组,即数组的数组。

"需要卸载时间戳,卸载时间戳要改回原表,对比修改时间戳和卸载时间戳。如果多个目标需要数据就乱了。所以我不会直接写新表。
在多目标的情况,由一个任务先卸载原表并更新状态。所有目标读卸载文件加载自己的库。加载可能不按次序或重复,以修改时间戳最新为准。"

"卸载时间戳"就是我说的“本次刷新时间”吧?为什么你要写回原表?如果更新的数据很多难道你又把每行更新一遍?你只要把它存在某处,比如你有一个调度任务表,就放在那里好了。

如果我理解有误,你就举一个最最简单的单表复制到单目标的例子,说明你的增量刷新是怎么做的。

我说的漏洞出在更新时间戳,上次说的那个方法会导致数据遗漏,我必须看看你的例子才知道这个问题是否存在。

我那个INSERT SELECT固然可以用你的DAU做到,但是它就不是写个SQL那么简单了,还加了很多东西。因为按我的做法事务处理大多不是单表操作,连接、子查询是很常用的,所以存储过程是最好的选择,在过程里写这些很简单。


这里明确说明OCI绑定地址:
For each placeholder in the SQL statement or PL/SQL block, you must call an OCI routine that binds the address of a variable in your program to the placeholder. When the statement executes, Oracle gets the data that your program placed in the input, or bind, variables and passes it to the server with the SQL statement.
通过我490楼的例子也可以看出,绑定操作开销还是很大的。DAU优化绑定的操作很必要。
要想优化490楼的程序,把绑定移到循环外,分配一堆变量,或一个结构。循环内一堆赋值语句。又点了两遍列名,共5遍了。
如果处理重码,执行update语句,又是两遍列名。即使手写模板,也就是点两遍列名,用了7次,你说值不值?


看了,bath错误处理比较复杂,有空试试看。这很有挑战性,越是复杂的处理,包装越有意义,能够让用户非常简单的使用复杂的功能。

我做两个时间戳,一个修改时间戳,每次修改时更新,一个下载时间戳,每次下载完更新。下载前比较二者,更新时间戳>下载时间戳的才下载。下载文件名也是带时间戳的,各目标节点自行选择某一个阶段的下载文件。为了方便这个选择,下载程序对下载任务记录日志。目标节点可以在日志中选择下载文件、时间段或某个版本。数据删除比较困难,修改程序应该写一个删除日志,标明哪个表,哪行什么时间被删除。下载程序也需要下载删除日志,目标节点以适当的策略同步数据。这样下载逻辑也比较复杂,一般的ftp,http比较难弄,还要写一些程序来办这事,SDBC就提供了这样的工具,写这类东西很方便。这就是你最讨厌的DIY,DAU,DIY了数据库,SDBC,DIY了网络,并完成了网络与数据库的沟通,提供应用级接口和工具。

下载服务器未必与数据库在一台机器上,所以存储过程未必好用。如此细碎的功能系统程序难以承担。每个表专用下载太累,还是写个半通用的好,处理类似逻辑的一批表。

当然DAU-SDBC工具也适合写专用上、下载程序。比如物流系统,一个订单受理后,有一个流程,记录每一步操作。订单及其流程必须一起传到总部或从总部下载,处理这个订单的个分公司不在一地,各自数据库并非实时在线,各自有不同的与总部的联络时间。甚至各自有不同数据库,有的是SYBASE,有的是ORACLE。有的是MYSQL,还有SQLserver。这时DIY的程序就无法避免。DAU-SDBC就适合这样的DIY程序,很方便的处理事务、原子一级的数据传送。

[ 本帖最后由 yulihua49 于 2010-3-4 11:02 编辑 ]

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
494#
发表于 2010-3-5 00:57 | 只看该作者
"我做两个时间戳,一个修改时间戳,每次修改时更新,一个下载时间戳,每次下载完更新。"
这个下载戳的代价可是很高的,UPDATE是一种昂贵的操作,而且你这个UPDATE和“修改时间戳”的UPDATE还有并发冲突。每行都设一个下载时间戳是一种浪费,你只需要一个批次的时间戳。我上次说的漏洞依然存在,你仔细想想。提示:“修改时间戳”和事务提交之间有延迟。

你又是如何UPDATE的?每下载一行就回写一行,还是用UPDATE ... WHERE 成批修改?

使用道具 举报

回复
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
495#
发表于 2010-3-5 08:15 | 只看该作者

回复 #501 newkid 的帖子

如果:E[2]、[4]、[6]是NULL怎么办?
http://www.itpub.net/viewthread. ... p;extra=&page=7第70帖

/**   indp    - place to store the length of the returned value. If returned
   **             value is:
   **             negative, the field fetched was NULL
   **             zero    , the field fetched was same length or shorter than
   **               the buffer provided
   **             positive, the field fetched was truncated*/

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
496#
发表于 2010-3-5 09:02 | 只看该作者
原帖由 〇〇 于 2010-3-5 08:15 发表
如果:E[2]、[4]、[6]是NULL怎么办?
http://www.itpub.net/viewthread. ... p;extra=&page=7第70帖

/**   indp    - place to store the length of the returned value. If returned
   **             value is:
   **             negative, the field fetched was NULL
   **             zero    , the field fetched was same length or shorter than
   **               the buffer provided
   **             positive, the field fetched was truncated*/

他的意思是当用数组成批运行SQL时,其中有些行会引发异常(比如在非空列插入NULL)要如何处理。你的程序也有批量捕获异常功能?

使用道具 举报

回复
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
497#
发表于 2010-3-5 09:12 | 只看该作者

回复 #505 newkid 的帖子

我理解错了...

使用道具 举报

回复
论坛徽章:
14
2009新春纪念徽章
日期:2009-01-04 14:52:28沸羊羊
日期:2015-03-04 14:51:52优秀写手
日期:2014-03-14 06:00:13马上有房
日期:2014-02-18 16:42:022014年新春福章
日期:2014-02-18 16:42:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-09 18:08:15蜘蛛蛋
日期:2012-06-27 21:08:142012新春纪念徽章
日期:2012-01-04 11:53:29ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
498#
 楼主| 发表于 2010-3-5 09:48 | 只看该作者
原帖由 newkid 于 2010-3-5 00:57 发表
"我做两个时间戳,一个修改时间戳,每次修改时更新,一个下载时间戳,每次下载完更新。"
这个下载戳的代价可是很高的,UPDATE是一种昂贵的操作,而且你这个UPDATE和“修改时间戳”的UPDATE还有并发冲突。每行都设一个下载时间戳是一种浪费,你只需要一个批次的时间戳。我上次说的漏洞依然存在,你仔细想想。提示:“修改时间戳”和事务提交之间有延迟。

你又是如何UPDATE的?每下载一行就回写一行,还是用UPDATE ... WHERE 成批修改?

这是个难题。不管谁修改,读时都要加行锁才保证不漏。下载时间如果很长就比较困难。
批量修改,如果找不到条件是没法办的。通用一点的,还是fetch一条改一条吧,为了少影响别人,每卸载一定的记录就commit一次。我会安排一个参数COMMITNUM,缺省10000.
至于速度问题,一般非实时下载,还是可以容忍的。关键是快速找到增量。
使用保留游标和一次绑定、投影少量列的技术,update操作已经快了不少,不过仍比fetch操作差一个数量级。
这类程序,一般编程简单一些,使用省事一些,速度够用即可。大部分用于更新字典表,这类表很少修改,比较稳定,但是表的数量较大。业务表的上载下载,同步更新往往有原子性要求,应该采取交易处理的办法。
你可有更好的算法?

[ 本帖最后由 yulihua49 于 2010-3-5 09:59 编辑 ]

使用道具 举报

回复
论坛徽章:
5
2010新春纪念徽章
日期:2010-03-01 11:20:51ITPUB学员
日期:2010-04-14 14:24:31ITPUB学员
日期:2010-08-21 18:20:28ITPUB9周年纪念徽章
日期:2010-10-08 09:31:212011新春纪念徽章
日期:2011-02-18 11:42:49
499#
发表于 2010-3-5 10:09 | 只看该作者
OMG,这个帖子讨论了一年多!?我看到26页的时候就完全跟不上了,一直翻到最后一页发现大家还在讨论,太佩服了

使用道具 举报

回复
论坛徽章:
14
2009新春纪念徽章
日期:2009-01-04 14:52:28沸羊羊
日期:2015-03-04 14:51:52优秀写手
日期:2014-03-14 06:00:13马上有房
日期:2014-02-18 16:42:022014年新春福章
日期:2014-02-18 16:42:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-09 18:08:15蜘蛛蛋
日期:2012-06-27 21:08:142012新春纪念徽章
日期:2012-01-04 11:53:29ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
500#
 楼主| 发表于 2010-3-5 11:56 | 只看该作者
原帖由 linyisen1985 于 2010-3-5 10:09 发表
OMG,这个帖子讨论了一年多!?我看到26页的时候就完全跟不上了,一直翻到最后一页发现大家还在讨论,太佩服了


才发现了一个数据库包装器:OTL,现在非常火。SDBC是与他非常类似的。
DAU的包装级别更高一些,直接映射结构了。
如果你认真读到了26页,应该能明白我想解决什么问题,以及基本思路。后边都是一些实例和争论。这些争论对提高DAU的性能、增加功能有好处。

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表