楼主: yulihua49

[讨论] 侃一下关于程序的“柔性”

[复制链接]
论坛徽章:
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
11#
发表于 2011-8-23 22:19 | 只看该作者
你把接口层和应用层混为一谈,接口层要力求透明,必须具备应变能力,比如你这个所谓的DAU在数据库上强加的“包装”层。
这个只对你自己有用,咱用PLSQL和数据库直接打交道,方便得很,从来不需要再来一层包装。那些试图在PLSQL中引入包装层的,比如PLSQL大牛Steven Feuerstein发明的TAPI(TABLE API),最终只是累赘,我在某公司用过TAPI,对它是深恶痛绝。
应用层的程序该柔则柔,该刚则刚,应用为需求服务,需求变了就得变,如果设计得好,每次改变就只修改相应的模块,不会把很多无辜的模块拉下水。
这方面PLSQL和其他语言一样,别的语言能做到的PLSQL也能做到。
PLSQL的优势在于和SQL的无缝结合,因此它天生是处理业务逻辑的最佳语言。

请举出一个PLSQL"应用级代码的重用性不高"的例子,把你的C代码秀出来看看,我来告诉你PLSQL该怎么写。注意是应用级的哦,就是业务逻辑处理单元,可别把你那个模仿SQLLDR的加载工具再拉出来!

使用道具 举报

回复
论坛徽章:
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
12#
发表于 2011-8-23 22:22 | 只看该作者
原帖由 昨夜袜子 于 2011-8-23 09:08 发表
这帖有什么历史渊源吗?

看这里:
http://www.itpub.net/viewthread.php?tid=1088197&highlight=

楼主在这里的发帖大多数少不了要推荐他做的“包装器”,我能理解他的落寞之情,毕竟这东西离开了他的单位就没有人用,茫茫人海知音难觅。不管他怎么敝帚自珍我都没意见,但是只要踩PLSQL我这个ORACLE卫道士就要跳出来。

使用道具 举报

回复
论坛徽章:
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
13#
发表于 2011-8-23 22:25 | 只看该作者
原帖由 〇〇 于 2011-8-23 08:59 发表
没有万古长青的程序,c,pl/sql都一样

TOM经常说的一句话:
Applications come, applications go, data stays forever.

PLSQL没有那些花里胡哨的东西,多年来更新有限,但它是最贴近你的数据的一层,你的数据存在它就存在,这种恐龙级的技术具有强大的生命力。

使用道具 举报

回复
论坛徽章:
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
14#
 楼主| 发表于 2011-8-24 14:46 | 只看该作者
原帖由 solomon_007 于 2011-8-23 09:33 发表
看了楼主的一篇精华帖,感觉LZ懂业务,精通C,但对ORACLE 数据库的开发理解尚且不足,
至少“SQL + PLSQL 是处理ORACLE数据库应用最便捷最高效的工具组合”,对这一观点
在这样一个论坛,尚不能与我等达成一致。。。。。。悲哀。。。。。。

加上“之一”,要看应用场景。

使用道具 举报

回复
论坛徽章:
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
15#
 楼主| 发表于 2011-8-24 14:51 | 只看该作者
原帖由 guostong 于 2011-8-23 22:13 发表


见过你写的关于exclude some columns 的解决方案,我实在想不出现在这种方案能够适用的场景,不会是拨号上网为了从SQL中节省几个字节?
如果你称次类举动为“柔性”我觉得有点牵强了。
首先从程序的易读性来讲,你这样做无疑是增加的读程序的难度,变相的提高了项目的成本。
其次,对数据库引擎,你增加的动态生成和解析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
16#
 楼主| 发表于 2011-8-24 14:54 | 只看该作者
本帖最后由 yulihua49 于 2025-9-14 19:41 编辑
原帖由 newkid 于 2011-8-23 22:19 发表
请举出一个PLSQL"应用级代码的重用性不高"的例子,把你的C代码秀出来看看,我来告诉你PLSQL该怎么写。

岂止是“重用性不高”,简直是除了你这样的高手中的高手,恐怕别人根本就无能为力。
给个题目:
由于安全要求,客户端不允许直接连接数据库,要通过类似TUXEDO、东方通、SDBC或其他交易中间件接入。一般的交易是交易服务器完成,交易服务器接数据库。
系统有些字典性的表,大概几十个,如车站表,城市表,线路表,席别表,票种表,列车等级表等等,相对稳定的。客户端可能要把他们暂存在客户端数据库、数据文件或数据结构里。不定期的需要从主数据库里提取数据,可能取某一条记录,或符合某条件的一批记录,也可能全部。想提取的表可能增加也可能减少。这样你可能需要数十个服务来解决这些问题。能否用一个服务来解决字典数据提取问题?允许服务器使用存储过程或其他办法,**是一个存储过程解决所有的表。

[ 本帖最后由 yulihua49 于 2011-8-24 15:07 编辑 ]

使用道具 举报

回复
论坛徽章:
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
17#
 楼主| 发表于 2011-8-24 15:10 | 只看该作者
原帖由 yulihua49 于 2011-8-24 14:54 发表

岂止是“重用性不高”,简直是出了你这样的高手中的高手,恐怕别人根本就无能为力。
给个题目:
由于安全要求,客户端不允熙直接连接数据库,要通过类似TUXEDO、东方通、SDBC或其他交易中间件接入。一般的交易是交易服务器完成,交易服务器接数据库。
系统有些字典性的表,大概几十个,如车站表,城市表,线路表,席别表,票种表,列车等级表等等,相对稳定的。客户端可能要把他们暂存在客户端数据库、数据文件或数据结构里。不定期的需要从主数据库里提取数据,可能取某一条记录,或符合某条件的一批记录,也可能全部。想提取的表可能增加也可能减少。这样你可能需要数十个服务来解决这些问题。能否用一个服务来解决字典数据提取问题?允许服务器使用存储过程或其他办法,最好是一个存储过程解决所有的表。

我们的技术设计:
查询服务:
输入JSON格式:(客户端到服务器的请求格式)
{"tablename":"表名","where","where 子句","page_size":页尺寸,"page_idx":页号,
"values":{"列名":"值",.........}}
说明:只支持一个表,表名必须是数据库里的一个普通表名、视图名。
where  子句可以是WHERE打头的语句,也可以是完整的select语句。其中可以有:列名形式的占位符。也可以是 PRIMARY_KEY 代表使用主键访问。
如果使用了占位符,或主键,需提供 values 对象。//绑定值
调用 page_select 服务。返回值:JSON数组格式。
如果成功,返回json格式的结果集。

否则:
[{"errno":错误号,msg:"错误信息"}.{...}]

[ 本帖最后由 yulihua49 于 2011-8-24 15:12 编辑 ]

使用道具 举报

回复
论坛徽章:
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
18#
 楼主| 发表于 2011-8-24 15:15 | 只看该作者
原帖由 yulihua49 于 2011-8-24 15:10 发表

我们的技术设计:
查询服务:
输入JSON格式:(客户端到服务器的请求格式)
{"tablename":"表名","where","where 子句","page_size":页尺寸,"page_idx":页号,
"values":{"列名":"值",.........}}
说明:只支持一个表,表名必须是数据库里的一个普通表名、视图名。
where  子句可以是WHERE打头的语句,也可以是完整的select语句。其中可以有:列名形式的占位符。也可以是 PRIMARY_KEY 代表使用主键访问。
如果使用了占位符,或主键,需提供 values 对象。//绑定值
调用 page_select 服务。返回值:JSON数组格式。
如果成功,返回json格式的结果集。

否则:
[{"errno":错误号,msg:"错误信息"}.{...}]

服务接口层,与中间件的接口:
这个是SDBC接口,还有TUXEDO接口的,以后再发:
  1. //service层,如果更换中间件就修改这
  2. int page_select(T_Connect *conn,T_NetHead *nethead)
  3. {
  4. T_SRV_Var *sp;
  5. JSON_OBJECT result;
  6. char *p,msg[SDBC_BLKSZ];
  7. int ret,event;

  8.         event=nethead->PROTO_NUM&65535;
  9.         sp=(T_SRV_Var *)conn->Var;
  10. /* 调用分页slelct服务  */
  11.         result=json_object_new_array();
  12.         ret=getpage(sp,nethead->data,result,msg); //调用应用层
  13.         if(ret<0) {
  14.                 p=msg;
  15. ShowLog(1,"%s:%s",__FUNCTION__,p);
  16.         } else {
  17.                 p=(char *)json_object_to_json_string(result);
  18.         }

  19.         nethead->data=p;
  20.         nethead->PKG_LEN=strlen(nethead->data);
  21.         nethead->PROTO_NUM=PutEvent(conn,event);
  22.         nethead->PKG_REC_NUM=json_object_array_length(result);
  23.         nethead->ERRNO1=sp->SQL_Connect->Errno;
  24.         nethead->ERRNO2=ret;
  25.         nethead->O_NODE=LocalAddr(conn->Socket,msg+sizeof(msg)-20);
  26.         ret=SendPack(conn,nethead);

  27. //      ShowLog(2,"%s:%s",__FUNCTION__,nethead->data);
  28.         json_object_put(result);
  29.         return 0;
  30. }
复制代码

[ 本帖最后由 yulihua49 于 2011-8-25 09:28 编辑 ]

使用道具 举报

回复
论坛徽章:
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
19#
 楼主| 发表于 2011-8-24 15:18 | 只看该作者
原帖由 yulihua49 于 2011-8-24 15:15 发表

服务接口层,与中间件的接口:
这个是SDBC接口,还有TUXEDO接口的,以后再发:
//service层

服务器端应用函数,对JSON的命令进行分析:

  1. //app层
  2. int getpage(T_SRV_Var *ctx,char *rqst,JSON_OBJECT result,char *msg)
  3. {
  4. int ret;
  5. INT64 now;
  6. struct msg_stu app;
  7. DAU table_DAU;
  8. JSON_OBJECT json,val;

  9.         if(!msg) {
  10.                 return -1 ;
  11.         }
  12.         now=now_sec();
  13.         *msg=0;
  14.         data_init(&app, msg_tpl);
  15. ShowLog(5,"getpage:%s",rqst);

  16.         //对传入的JSON对象进行拆包
  17.         json=json_tokener_parse(rqst);
  18.         if(!json) {
  19.                 sprintf(msg,"getpage:#json 格式错误!#");
  20.                 return -1;
  21.         }
  22.         val=json_object_object_get(json,"values");
  23.         ret=json_to_struct(&app,json,msg_tpl);//利用命令解析模板将命令解析到app结构。
  24.         if(!ret){
  25.                 json_object_put(json);
  26.                 sprintf(msg,"getpage:transfer json error!");
  27.                 return -1;
  28.         }
  29. ShowLog(5,"getpage:%s,ret=%d",msg,ret);
  30.         ret=DAU_init(&table_DAU,ctx->SQL_Connect,app.tablename,0,0);//自动分析表结构,是开销最大的部分。
  31.         if(ret) {
  32.                 json_object_put(json);
  33.                 sprintf(msg,"getpage:#表名%s不存在!#",app.tablename);
  34.                 return -1;
  35.         }
  36.         if(val) {
  37.                 DAU_fromJSON(&table_DAU,val);//绑定值装入DAU。
  38.         }
  39.         json_object_put(json);
  40.         if(!strcmp(app.where,"PRIMARY_KEY")) {//要求按主键提取
  41.         char *p;
  42.                 p=mk_where(table_DAU.srm.pks,app.where);//模板里的主键
  43.                 if(!*app.where) {
  44.                         sprintf(msg,"getpage:#table %s:没有主键!",table_DAU.srm.tabname);
  45.                         DAU_free(&table_DAU);
  46.                         return -2;
  47.                 }
  48.         }

  49.         /*分页操作
  50.                 *如果page_idx=0&&page_size=0,则不分页,取全部结果集;
  51.                 *如果page_idx=0&&page_size=n,则不分页,取n条结果集;
  52.                 *如果page_idx=n&&page_size=0,则表示分n页,取1条结果集;
  53.                 *如果page_idx=n&&page_size=n,则表示分n页,取n条结果集;
  54.         */

  55.         if(app.page_idx==0) {//不分页的查询
  56.                 if(0>=(ret=DAU_select(&table_DAU,app.where,app.page_size))){//柔性代码,生成sql语句。
  57.                         sprintf(msg,"getpage:nopage select error:%s",app.where);
  58.                         DAU_free(&table_DAU);
  59.                         return -3;
  60.                 }
  61.         } else {
  62.                 if(app.page_size==0)  app.page_size=1;
  63.                 if(0>=(ret=mk_select(&table_DAU,app.where,app.page_idx,app.page_size))){//生成分页的sql语句。
  64.                         sprintf(msg,"getpage:page_idx=%d select page_size=%d msg=%s!",
  65.                                 app.page_idx,app.page_size,
  66.                                 app.where);
  67.                         DAU_free(&table_DAU);
  68.                         return -1;
  69.                 }
  70.         }
  71.         ShowLog(5,"getpage:ret=%d,stmt=%s",ret,app.where);
  72.         while(!(ret=DAU_next(&table_DAU))){
  73.         int rn;
  74.                 //结果集打成JSON包
  75.                 JSON_NEW(json);
  76.                 DAU_toJSON(&table_DAU,json,0);
  77.                 if(app.page_idx) {
  78.                         table_DAU.srm.rp+=net_dispack(&rn,table_DAU.srm.rp,IntType);
  79.                 }
  80.                 json_object_array_add(result,json);
  81.         }
  82.         DAU_free(&table_DAU);

  83.         return 0;
  84. }
复制代码

命令解析模板:

  1. #define JSON_NEW(json) { \
  2.                 if(!((json)=json_object_new_object())){ \
  3.                         sprintf(msg,"getpage:new json error!"); \
  4.                         break; \
  5.                 }}

  6. /*输入结构:{tablename:表名,where:where语句,page_idx:页号,page_size:页长,values:{列名:值,,,}//对where里的bind赋值 */

  7. static T_PkgType msg_tpl[]={
  8.         {CH_CHAR,1024,"tablename",0,-1},
  9.         {CH_CHAR,4096,"where"},
  10.         {CH_INT,sizeof(int),"page_idx"},
  11.         {CH_INT,sizeof(int),"page_size"},
  12.         {-1,0,0}
  13. };

  14. struct msg_stu {
  15.         char tablename[1024];
  16.         char where[4096];
  17.         int page_idx;
  18.         int page_size;
  19. };

复制代码

[ 本帖最后由 yulihua49 于 2011-8-24 17:43 编辑 ]

使用道具 举报

回复
论坛徽章:
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
20#
 楼主| 发表于 2011-8-24 15:26 | 只看该作者
原帖由 yulihua49 于 2011-8-24 15:18 发表

服务器端应用函数,对JSON的命令进行分析:




分页处理DAO:

  1. //服务器用 分页查询,通过JSON协议
  2. #include "sqlsrv.h"

  3. //DAO层
  4. int mk_select(DAU *DP,char *where,int page_idx,int page_size)
  5. {
  6. int ret,rown=-1;
  7. char *p,tmprowid[10];
  8. const char *rowid=NULL;
  9. int min,max;

  10.         min=(page_idx-1)*page_size;
  11.         max=min+page_size;
  12.         rown=index_col(DP->srm.colidx,abs(DP->srm.Aflg),"ROWID",DP->srm.tp);
  13.         if(rown >=0) { //如果模板里有ROWID列,必须剔除
  14.                 rowid=DP->srm.tp[rown].name;
  15.                 sprintf(tmprowid,"ROWNUM");
  16.                 DP->srm.tp[rown].name=tmprowid;
  17.         }

  18.         if(ret=SRM_mk_select(&DP->srm,DP->SQL_Connect->DBOWN,where)) {//柔性代码,生成SQL语句
  19.                 if(rowid)  DP->srm.tp[rown].name=rowid;
  20.                 DP->srm.hint=0;
  21.                 return ret;
  22.         }
  23.         if(rowid)  DP->srm.tp[rown].name=rowid;
  24.         p=strdup(where);
  25. //如果更换数据库就改这
  26.         sprintf(where,"select * FROM (select A.*,ROWNUM RN FROM (%s) A WHERE ROWNUM <= %d) WHERE RN > %d",
  27.                 p,max,min);
  28.         free(p);
  29. ShowLog(5,"%s:stmt=%s",__FUNCTION__,where);
  30.         return  DAU_select(DP,where,0);
  31. }

复制代码

以上几个部分组合成完整的services。
没有实现设计文档中的错误信息格式。

[ 本帖最后由 yulihua49 于 2011-8-25 09:37 编辑 ]

使用道具 举报

回复

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

本版积分规则 发表回复

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