楼主: yulihua49

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

[复制链接]
招聘 : 多个岗位招聘
论坛徽章:
33
2010广州亚运会纪念徽章:跆拳道
日期:2010-11-22 15:42:39灰彻蛋
日期:2012-05-16 13:17:56参与WIN7挑战赛纪念
日期:2012-05-24 10:37:35茶鸡蛋
日期:2012-05-28 17:27:32灰彻蛋
日期:2012-06-13 18:48:14双黄蛋
日期:2012-06-14 14:32:02奥运会纪念徽章:帆船
日期:2012-07-10 09:43:29奥运会纪念徽章:足球
日期:2012-08-17 09:17:32奥运会纪念徽章:帆船
日期:2012-07-26 15:46:49奥运会纪念徽章:赛艇
日期:2012-08-20 16:23:58
151#
发表于 2011-9-16 18:25 | 只看该作者
貌似丢数据了?

使用道具 举报

回复
论坛徽章:
3
2010新春纪念徽章
日期:2010-03-01 11:06:22ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26ITPUB 11周年纪念徽章
日期:2012-10-09 18:08:15
152#
发表于 2011-9-16 19:04 | 只看该作者
看sql的使用情况和要求,一般是不要超过几百行,太长的话阅读有问题。

使用道具 举报

回复
论坛徽章:
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
153#
发表于 2011-9-16 19:10 | 只看该作者
是丢了

使用道具 举报

回复
论坛徽章:
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
154#
发表于 2011-9-16 19:14 | 只看该作者
我这里今天早上的备份...
newkid
资深新手
老程序员



来自 银河系
精华贴数 15
个人空间 0
技术积分 20752 (73)
社区积分 5 (22147)
注册日期 2004-6-26
论坛徽章:66
      
      

#151
使用道具  
发表于 2011-9-14 00:36   
"DAU那点东西一点没省,为了帮你解析json参数,还增加了一段。"
谁说没省?你不用读模版了,不用读字典了,不用生成SQL/绑定变量了,这一大堆不是省下来的?
至于那些格式解析、打包等东西,我同意转移到外面来。

"你看我的代码:有关于裸数据的处理。我试图把存储过程改成裸数据,没整明白,改不了。"
我找来找去只在这里见到一个:
http://ellebaek.wordpress.com/20 ... g-plsql-java-and-c/

Here's the implementation of the C external procedure (refcurdesc.c):
.......

他说这个C外部过程用OCI解析REF CURSOR, 你看看是不是。


"我很奇怪,这里的人都搞些什么应用?光用存储过程就行了?"
光用存储过程的应该也不多,但是学会PLSQL肯定是有用的。


"代码不好读?脑袋里不要老想着SQL,你要读的是业务逻辑。读到调用DAO时,哦,这个DAU取得了它的数据。不要想怎么取。这样一个业务逻辑的大脉络就清晰了。"
对我来说SQL就是业务逻辑的一部分,“取得数据的方法”是重要的一环,这里没写好就会影响整个事务的性能。
就是用PLSQL写存储过程,也有人主张用你的方法,把数据存取分离出来,变成子过程,业务逻辑层不写SQL, 而是调用子过程。我也不是反对这种做法,假如分离出去的部分可以重用、可以改善可读性,也未尝不可。注意前面的两个前提。


"具体如何取得数据,单看DAO程序,你可以看到WHERE条件,这一般就够了。干嘛还非要看有哪些列呢?要看列,就看模板。这好像没什么难度。
即使你的程序罗列了列名,一般我也是不看的(好多人喜欢select *),只看WHERE。"
对我来说,取得哪些列也是重要一环。要修改表结构的时候,如果有这些静态SQL, 你可以快速知道哪些程序会受影响。

"看来大家对这个工作乐此不疲,那就不用模板也罢。"
我对PLSQL里面写SQL乐此不疲,我用静态SQL从来不需要PARSE,BIND,FETCH,CLOSE。

"我觉得有些人似乎是SQL依赖症。"
我很荣幸地对号入座。

"有说DAU程序不好懂的,看看这个,提意见。"

我还真的硬着头皮读了#150的程序。结论:不敢恭维。
insert_DAO最后一个参数stmt干什么用?看样子不像是往里传数据,因为OAD_exec没有用到它;反而出错的时候被改写(*stmt=0),但是只在update_by_PK使用,又不会返回任何数据给调用者?

(我又读了程序发现这个源头来自loadfile的参数buf,难道你是为了避免重复分配内存?那也应该有别的方法吧,何苦把程序接口弄得这么复杂?)

你既然有oad参数,数组长度应该不难得到,为什么还要设计第二个参数n?

num=_DAU.srm.tp[_DAU.srm.Aflg].offset; ------- 这个我说是天书有谁能反对?

再看你读文件的循环:
if(feof(ifd)) break;
这里不要急着出去嘛,先把“零头”处理了再退出,外面也少一段程序。

//返回后,还会有一个 ___SQL_Transaction__(SQL_Connect,TRANCOMMIT);
这个有点搞,你循环里面都提交了,为什么做完反而不提交,而要留给后面的代码?

[ 本帖最后由 newkid 于 2011-9-14 01:57 编辑 ]



__________________


世界上只有两种编程方法:Oracle的方法和错误的方法。

剑破冰山—Oracle开发艺术 即将隆重推出
http://www.china-pub.com/197199
http://www.huachu.com.cn/itbook/itbookinfo.asp?lbbh=10114321

只看该作者              引用  回复  报告  编辑     

yulihua49
初级会员



精华贴数 1
个人空间 18
技术积分 1509 (1609)
社区积分 0 (1312844)
注册日期 2007-2-1
论坛徽章:3
         
            

#152
使用道具  
发表于 2011-9-14 09:27   
为什么服务函数可以写明全部列?
比如,有一个存根表,原先有80多列,现在有150多列。
这个表在售票、订票、退票、检票、中转、改签、取票、TVM、错票处理,电子票流程,支付,统计,审核、清算。。。。。。。都要访问,不少于几十处。
由好几个人和小组参与。所以,一个模板要生成许多语句。多数程序修改表结构时,除了更换模板,不需要修改。
下例是售票记账模块:没给表结构,影响读懂处理逻辑吗?


[Copy to clipboard] [ - ]
CODE:
/* 售票记账服务 */
int sell_app(GDA *ctx,char *data,char *msg,JSON_OBJECT errjson)
{
int ret,newvol=0;
SELL_stu sell;
SEAT_stu seat;
DEV_BILL_stu dbill;
DAU sell_DAU,seat_DAU,bill_DAU;
JSON_OBJECT json;

        json=json_tokener_parse(data);
        if(!json) {
                sprintf(msg,"输入的数据格式错!");
                json_object_array_add(errjson,jerr(100,msg));
                return FORMATERR;
        }
        DAU_init(&sell_DAU,ctx->Connect,0,&sell,SELL_tpl);
        DAU_init(&seat_DAU,ctx->Connect,0,&seat,SEAT_tpl);
        data_init(&seat,SEAT_tpl);
        DAU_fromJSON(&seat_DAU,json); //包括end_station
//存根的数据都是前端来的,随便多少列。那些列需要在表单上处理,或打印在票面上。或是从其他数据组合(如支付系统等)而成。与本服务器无关。
        DAU_fromJSON(&sell_DAU,json);
        json_object_put(json);
//检查操作权限
        if(ret=checkperm(ctx,&sell,msg)) {
                json_object_array_add(errjson,jerr(ret+100,msg));
                DAU_free(&sell_DAU);
                DAU_free(&seat_DAU);
                return -1;
        }
// ??? 如果是订单售票,查找订单
// 修改席位和余额库
        DAU_copy(&sell_DAU,&ctx->ctx_DAU,0);
        strcpy(seat.used_dev,ctx->contex.devid);
        strcpy(seat.used_uid,ctx->contex.userid);
        seat.used_time=ctx->contex.last_oper;
        ret=sell_seat(&seat_DAU,msg,errjson);//comm_app.c,席位售出,如果需要分段在此进行
        DAU_free(&seat_DAU);
        if(ret) {
                DAU_free(&sell_DAU);
                return ret;
        }
//调整票据号
        DAU_init(&bill_DAU,ctx->Connect,0,&dbill,DEV_BILL_tpl);
        strcpy(dbill.devid,ctx->contex.devid);
        newvol=bill_add(&bill_DAU,msg,errjson); //comm_app.c,票卷号+1
        if(newvol<0) {
                DAU_free(&sell_DAU);
                DAU_free(&bill_DAU);
                return newvol;
        }
//记存根,我只用这几个字段,其余80或150个与我无关吧?
        sell.stat=0;
        strcpy(sell.ticket_no,msg);                     //当前票号
        sell.chksum=sell_chk_sum(&sell_DAU,msg);        //comm_app.c,计算校验和
        rsecstrfmt(sell.sell_time,ctx->contex.last_oper,YEAR_TO_SEC);
        ret=sell_insert_dao(&sell_DAU,msg);
        if(ret) {
                json_object_array_add(errjson,jerr(120,msg));
                DAU_free(&bill_DAU);
                DAU_free(&sell_DAU);
                return ret;
        }
//组装返回数据
        //返回下一个票号
        json_object_array_add(errjson,jerr(newvol,dbill.bill_num));
        json=json_object_new_object();
        if(!json) {
                sprintf(msg,"json MALLOC error");
                ShowLog(1,"sell_app:%s",msg);
                DAU_free(&bill_DAU);
                DAU_free(&sell_DAU);
                return MEMERR;
        }
        DAU_toJSON(&sell_DAU,json,0);
        json_object_array_add(errjson,json);
        DAU_free(&bill_DAU);
        DAU_free(&sell_DAU);
        return ret;
}

[ 本帖最后由 yulihua49 于 2011-9-14 10:41 编辑 ]



__________________

欢迎到我的blog:
http://blog.chinaunix.net/u3/92831/
只看该作者              引用  回复  报告  编辑     

yulihua49
初级会员



精华贴数 1
个人空间 18
技术积分 1509 (1609)
社区积分 0 (1312844)
注册日期 2007-2-1
论坛徽章:3
         
            

#153
使用道具  
发表于 2011-9-14 09:32   



QUOTE:
--------------------------------------------------------------------------------
原帖由 newkid 于 2011-9-14 00:36 发表
num=_DAU.srm.tp[_DAU.srm.Aflg].offset; ------- 这个我说是天书有谁能反对?

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


这个你抓得真准,不愧大侠。
要是C++,我可以来一个 recsize=table_DAU.getRecsize();
还是封得不严。写一个函数也行,不过不常用。


QUOTE:
--------------------------------------------------------------------------------
你既然有oad参数,数组长度应该不难得到,为什么还要设计第二个参数n?
--------------------------------------------------------------------------------


这个很有意思。你看那个零头,肯定n != BATCH_NUM。
这里说到DB2的批插入,它既不能定义起点,也不能定义终点,只能是数组的维,结果很难办。
正是ORACLE的优点,可以操作数组中的一部分。


QUOTE:
--------------------------------------------------------------------------------
(我又读了程序发现这个源头来自loadfile的参数buf,难道你是为了避免重复分配内存?那也应该有别的方法吧,何苦把程序接口弄得这么复杂?)
--------------------------------------------------------------------------------


前端分配了内存,在命令行可以-KkBYTEs,指定。因为不知道语句有多大。如果core dumpped,就可以再次申请大一些的。


QUOTE:
--------------------------------------------------------------------------------
这个有点搞,你循环里面都提交了,为什么做完反而不提交,而要留给后面的代码?
--------------------------------------------------------------------------------


循环里面10组(10000rows)提交一次。
begin和commit或rollback都是在svc层,另外,不够10组和零头没有commit,等出去做。
这个安排你可以看一下上边的售票记账程序,任何一步出错,都会rollback,记账失败。省得每个出错点都要rollback。C是没有try-catch的。


总之,你还是读懂了,很细。
我想稍微C了解点的,都能读个八九不离十。


QUOTE:
--------------------------------------------------------------------------------
对我来说SQL就是业务逻辑的一部分,“取得数据的方法”是重要的一环,这里没写好就会影响整个事务的性能。
就是用PLSQL写存储过程,也有人主张用你的方法,把数据存取分离出来,变成子过程,业务逻辑层不写SQL, 而是调用子过程。我也不是反对这种做法,假如分离出去的部分可以重用、可以改善可读性,也未尝不可。注意前面的两个前提。
--------------------------------------------------------------------------------


这就对了。在模块间传数据,要传结构。模板就是映射结构的,这样模块间方便些。也好读。


QUOTE:
--------------------------------------------------------------------------------
Here's the implementation of the C external procedure (refcurdesc.c):
.......

他说这个C外部过程用OCI解析REF CURSOR, 你看看是不是。
--------------------------------------------------------------------------------


是。这部分代码在ORA_Rpc()l里,也是一个包装。不然即使调用存储过程,用OCI也是很麻烦的。


使用道具 举报

回复
论坛徽章:
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
155#
发表于 2011-9-16 19:15 | 只看该作者

不敢恭维?那么你有更好的?
逻辑要清晰,效率要高,功能要满足(NULL处理,DUPKEY处理,格式处理)
如果用存储过程也必须配一个前端,好把前端的文件加进来。前端用C,JAVA,PHP都行。
代码能短一些?
效率不用和我比了,比sqlldr高就行。

我那个代码主要用于调试OAD。在实际的OLTP应用中,批量插入可以显著改善性能。
如列车编组顺序表,从MQ来,分为报头和正文。报头是关于列车的信息,正文是每辆车的信息,有几十到200个记录。如果一个批量插入,效果显著。其它如股道和车辆,车次和停靠站,订单和一批票等等。我的程序可以做一个DEMO,照猫画虎就可以了。

所以你的程序也应该有示范作用,让别人也可以借鉴。

[ 本帖最后由 yulihua49 于 2011-9-14 19:35 编辑 ]



__________________

欢迎到我的blog:
http://blog.chinaunix.net/u3/92831/
只看该作者              引用  回复  报告  编辑     

yulihua49
初级会员



精华贴数 1
个人空间 18
技术积分 1509 (1609)
社区积分 0 (1312844)
注册日期 2007-2-1
论坛徽章:3
         
            

#154
使用道具  
发表于 2011-9-14 10:55   



QUOTE:
--------------------------------------------------------------------------------
原帖由 newkid 于 2011-9-11 03:29 发表
我还想反过来问你呢,PLSQL能做到的事情,如果效率不低,为什么要把程序写到数据库外?


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


反正已经确定用OCI了,就服务器其他功能而言,也必须使用模板。用DAU可读性,可维护性都好,何必PLSQL呢。也不是绝对不能用。
多半一懒就不用了。



__________________

欢迎到我的blog:
http://blog.chinaunix.net/u3/92831/
只看该作者              引用  回复  报告  编辑     


newkid
资深新手
老程序员



来自 银河系
精华贴数 15
个人空间 0
技术积分 20752 (73)
社区积分 5 (22147)
注册日期 2004-6-26
论坛徽章:66
      
      

#155
使用道具  
发表于 2011-9-14 22:23   
"这个很有意思。你看那个零头,肯定n != BATCH_NUM。"
你的oad里面难道没有计数器?OAD_pkg_dispack里面进行累计,原来n=0的时候就清零。

"前端分配了内存,在命令行可以-KkBYTEs,指定。因为不知道语句有多大。如果core dumpped,就可以再次申请大一些的。"
那你可以搞一块公共的缓存来操作吧?没必要把一个指针在所有接口中传来传去。

"循环里面10组(10000rows)提交一次。
begin和commit或rollback都是在svc层,另外,不够10组和零头没有commit,等出去做。"
为什么要等“出去”再做?你完全可以在返回之前提交啊?(按我的做法就是在里面把if(feof(ifd))和commit_num == COMMIT_NUM的条件合并)你这个loadfile不可能包含在其他事务中。

“这个安排你可以看一下上边的售票记账程序,任何一步出错,都会rollback,记账失败。省得每个出错点都要rollback。C是没有try-catch的。”
等会再看。


"总之,你还是读懂了,很细。"
我读懂了,所以我有资格认为比PLSQL代码更不好读。


"不敢恭维?那么你有更好的?
逻辑要清晰,效率要高,功能要满足(NULL处理,DUPKEY处理,格式处理)
如果用存储过程也必须配一个前端,好把前端的文件加进来。前端用C,JAVA,PHP都行。
代码能短一些?
效率不用和我比了,比sqlldr高就行。"

用外部表,只需写表定义(如果还嫌麻烦就用动态SQL生成表定义)。
没有读文件部分,没有解析部分(但是具备SQLLDR所有解析功能,比你强大得多)。
直接用SQL访问,可以做任何连接、变换。
我才不吃饱了撑的写代码。



__________________


世界上只有两种编程方法:Oracle的方法和错误的方法。

剑破冰山—Oracle开发艺术 即将隆重推出
http://www.china-pub.com/197199
http://www.huachu.com.cn/itbook/itbookinfo.asp?lbbh=10114321

只看该作者              引用  回复  报告  编辑     

newkid
资深新手
老程序员



来自 银河系
精华贴数 15
个人空间 0
技术积分 20752 (73)
社区积分 5 (22147)
注册日期 2004-6-26
论坛徽章:66
      
      

#156
使用道具  
发表于 2011-9-15 02:22   
即使对C程序员,你这个代码也是很不友好的。比方你在DAU_init把DAU和一个结构挂上钩,随后的操作忽而是DAU忽而是结构,让人摸不着头脑。比如同样是写入数据操作,DAU_fromJSON(&sell_DAU,json)这是操作DAU, 后面的sell.stat=0又是对结构操作。sell_insert_dao(&sell_DAU,msg)乍一看和sell没有关系,谁会想到sell的数据最终要写到表里?data_init(&seat,SEAT_tpl)也是莫名其妙,照理说它应该被包含在DAU_init里面了。对sell也没见你调用data_init。
那么多地方调用DAU_free,这在PLSQL是完全不需要操心的,一旦结束调用资源就被自动释放或回收,才不会显得这么笨拙呢。
你最感到得意的地方就是sell_insert_dao之前的那几个赋值操作。这有什么了不起?如果用PLSQL来实现,你这个sell_app就是一个事务里面调用的子模块,它完全可以接受一个sell%ROWTYPE的参数。这种参数就是一个记录(类似C的结构),你可以只对其中几个列赋值,然后insert into sell values p_row_sell。
但是我还是建议写列名。当你发现表数据有错时,如果代码里有列名,你可以追踪到它是哪里来的。
估计你对DAU_copy(&sell_DAU,&ctx->ctx_DAU,0)也很得意,但在我看来很危险,因为你的“柔性”可能造成前面的数据被覆盖,仅仅因为字段名是一样的。



__________________


世界上只有两种编程方法:Oracle的方法和错误的方法。

剑破冰山—Oracle开发艺术 即将隆重推出
http://www.china-pub.com/197199
http://www.huachu.com.cn/itbook/itbookinfo.asp?lbbh=10114321

只看该作者              引用  回复  报告  编辑     

nannan5000



精华贴数 0
个人空间 0
技术积分 528 (6514)
社区积分 2 (64118)
注册日期 2008-10-6
论坛徽章:1
           
            

#157
使用道具  
发表于 2011-9-15 07:56   
越看越晕了



__________________

飞鱼576
QQ 1052382576

My Web Site: www.flyfish576.com
只看该作者              引用  回复  报告  编辑     

newkid
资深新手
老程序员



来自 银河系
精华贴数 15
个人空间 0
技术积分 20752 (73)
社区积分 5 (22147)
注册日期 2004-6-26
论坛徽章:66
      
      

#158
使用道具  
发表于 2011-9-15 09:21   
杯具,闹了半天只有我看懂楼主的代码。



__________________


世界上只有两种编程方法:Oracle的方法和错误的方法。

剑破冰山—Oracle开发艺术 即将隆重推出
http://www.china-pub.com/197199
http://www.huachu.com.cn/itbook/itbookinfo.asp?lbbh=10114321

只看该作者              引用  回复  报告  编辑     

yulihua49
初级会员



精华贴数 1
个人空间 18
技术积分 1509 (1609)
社区积分 0 (1312844)
注册日期 2007-2-1
论坛徽章:3
         
            

使用道具 举报

回复
论坛徽章:
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
156#
发表于 2011-9-16 19:17 | 只看该作者
#159
使用道具  
发表于 2011-9-15 09:54   



QUOTE:
--------------------------------------------------------------------------------
原帖由 newkid 于 2011-9-15 02:22 发表
即使对C程序员,你这个代码也是很不友好的。比方你在DAU_init把DAU和一个结构挂上钩,随后的操作忽而是DAU忽而是结构,让人摸不着头脑。比如同样是写入数据操作,DAU_fromJSON(&sell_DAU,json)这是操作DAU, 后面的sell.stat=0又是对结构操作。sell_insert_dao(&sell_DAU,msg)乍一看和sell没有关系,谁会想到sell的数据最终要写到表里?data_init(&seat,SEAT_tpl)也是莫名其妙,照理说它应该被包含在DAU_init里面了。对sell也没见你调用data_init。不需要加上也行。
那么多地方调用DAU_free,这在PLSQL是完全不需要操心的,一旦结束调用资源就被自动释放或回收,才不会显得这么笨拙呢。
你最感到得意的地方就是sell_insert_dao之前的那几个赋值操作。这有什么了不起?如果用PLSQL来实现,你这个sell_app就是一个事务里面调用的子模块,它完全可以接受一个sell%ROWTYPE的参数。这种参数就是一个记录(类似C的结构),你可以只对其中几个列赋值,然后insert into sell values p_row_sell。
但是我还是建议写列名。当你发现表数据有错时,如果代码里有列名,你可以追踪到它是哪里来的。(可以在日志中找到完整的sql语句,如果出错还有绑定变量值和错误信息,(粘到sqlplus里就可以执行))
估计你对DAU_copy(&sell_DAU,&ctx->ctx_DAU,0)也很得意,但在我看来很危险,因为你的“柔性”可能造成前面的数据被覆盖,仅仅因为字段名是一样的。你可以不用
--------------------------------------------------------------------------------


DAU本来就是SRM,结构关系映像,你当然用的是结构,DAU只是做一个操作,帮你存取数据,不仅映像到数据库,同样映像到JSON,字符串等等。它只解决某种数据对象装入结构或把结构内容打包到其他数据对象。需要读者理解这个概念。


C的内存不能自动回收,这不赖我。恰恰是提供了这种类似析构函数,还有使用规范(文档里有),使得即使新手都能写出内存安全的应用。
内存自动回收是双刃剑。在大型多线程服务器里引起不确定的结果,由于线程互斥造成互相等待,这在JAVA里表现明显。不是咱们的话题,不多说了.

前端传来的大批列,如何向记录赋值?最后的结果还要传回客户端,如何取值到通讯包?
如果使用PRO*C,光就这个sell表,看看得写多少遍列名:
1.declare 1遍
2.从json赋值,2遍(等号左右各一遍)
3.如果是varchar2型,计算长度一遍。
4.into后边列名 一遍
5.values,绑定变量 一遍。
6.打包输出一遍。
没算真正业务逻辑那几个赋值。这大概几百行了吧?
楼上一位朋友说没看懂,写上这几百行就看懂了吗?你是因为业务不懂,而且C不熟。如果几个表的SQL都写出来,几千行,完全淹没了业务逻辑。(我要是真把几千行的程序摆在这,恐怕你连看也不看了)
有看几千行代码的精力,用来学习一下业务逻辑是否更有意义?

另外,从80列到150列,不是一次,而是n次逐步的,你改这几千行代码,不辛苦吗?

[ 本帖最后由 yulihua49 于 2011-9-15 11:20 编辑 ]



__________________

欢迎到我的blog:
http://blog.chinaunix.net/u3/92831/
只看该作者              引用  回复  报告  编辑     

newkid
资深新手
老程序员



来自 银河系
精华贴数 15
个人空间 0
技术积分 20752 (73)
社区积分 5 (22147)
注册日期 2004-6-26
论坛徽章:66
      
      

#160
使用道具  
发表于 2011-9-15 22:37   
事务的接口必须是静态的。我不相信你一下子会传进来150列,很多应该是计算出来或者从其他表获得的。需求有变化,表结构修改、客户端修改、接口也要相应修改。我不认为这有什么难的,特别是你增加的数据只是简单保存起来,不参与计算。
如果你的程序允许接收任何字段,这里面有安全隐患。我的事务接收什么数据必须是已知的、能静态编译的。
就像那个DAU_copy,我的灵敏嗅觉一下子警惕起来,而你这方面的修炼显然还不够。



__________________


世界上只有两种编程方法:Oracle的方法和错误的方法。

剑破冰山—Oracle开发艺术 即将隆重推出
http://www.china-pub.com/197199
http://www.huachu.com.cn/itbook/itbookinfo.asp?lbbh=10114321

只看该作者              引用  回复  报告  编辑     

〇〇



精华贴数 10
个人空间 0
技术积分 49759 (25)
社区积分 9647 (262)
注册日期 2008-1-16
论坛徽章:229
      
      

#161
使用道具  
发表于 2011-9-16 04:46   



QUOTE:
--------------------------------------------------------------------------------
原帖由 newkid 于 2011-9-15 09:21 发表
杯具,闹了半天只有我看懂楼主的代码。
--------------------------------------------------------------------------------


本来就是



__________________

我的新浪微博,欢迎大家加我:http://weibo.com/lu01


剑破冰山—Oracle开发艺术 已经上架销售
网购地址:互动|京东电子工业出版社书店卓越亚马逊当当华储
在线阅读:5lcto华储
源代码:博文视点ITPUB
只看该作者              引用  回复  报告  编辑     

newkid
资深新手
老程序员



来自 银河系
精华贴数 15
个人空间 0
技术积分 20752 (73)
社区积分 5 (22147)
注册日期 2004-6-26
论坛徽章:66
      
      

#162
使用道具  
发表于 2011-9-16 05:21   



QUOTE:
--------------------------------------------------------------------------------
原帖由 〇〇 于 2011-9-16 04:46 发表

本来就是
--------------------------------------------------------------------------------


他贴出来本来是想让大家肯定他的代码的可读性,但不幸的是只有他的老对手读懂了。



__________________


世界上只有两种编程方法:Oracle的方法和错误的方法。

剑破冰山—Oracle开发艺术 即将隆重推出
http://www.china-pub.com/197199
http://www.huachu.com.cn/itbook/itbookinfo.asp?lbbh=10114321

只看该作者              引用  回复  报告  编辑     

使用道具 举报

回复
论坛徽章:
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
157#
 楼主| 发表于 2011-9-14 09:27 | 只看该作者
为什么服务函数可以写明全部列?
比如,有一个存根表,原先有80多列,现在有150多列。
这个表在售票、订票、退票、检票、中转、改签、取票、TVM、错票处理,电子票流程,支付,统计,审核、清算。。。。。。。都要访问,不少于几十处。
由好几个人和小组参与。所以,一个模板要生成许多语句。多数程序修改表结构时,除了更换模板,不需要修改。
下例是售票记账模块:没给表结构,影响读懂处理逻辑吗?


  1. /* 售票记账服务 */
  2. int sell_app(GDA *ctx,char *data,char *msg,JSON_OBJECT errjson)
  3. {
  4. int ret,newvol=0;
  5. SELL_stu sell;
  6. SEAT_stu seat;
  7. DEV_BILL_stu dbill;
  8. DAU sell_DAU,seat_DAU,bill_DAU;
  9. JSON_OBJECT json;

  10.         json=json_tokener_parse(data);
  11.         if(!json) {
  12.                 sprintf(msg,"输入的数据格式错!");
  13.                 json_object_array_add(errjson,jerr(100,msg));
  14.                 return FORMATERR;
  15.         }
  16.         DAU_init(&sell_DAU,ctx->Connect,0,&sell,SELL_tpl);
  17.         DAU_init(&seat_DAU,ctx->Connect,0,&seat,SEAT_tpl);
  18.         data_init(&seat,SEAT_tpl);
  19.         DAU_fromJSON(&seat_DAU,json); //包括end_station
  20. //存根的数据都是前端来的,随便多少列。那些列需要在表单上处理,或打印在票面上。或是从其他数据组合(如支付系统等)而成。与本服务器无关。
  21.         DAU_fromJSON(&sell_DAU,json);
  22.         json_object_put(json);
  23. //检查操作权限
  24.         if(ret=checkperm(ctx,&sell,msg)) {
  25.                 json_object_array_add(errjson,jerr(ret+100,msg));
  26.                 DAU_free(&sell_DAU);
  27.                 DAU_free(&seat_DAU);
  28.                 return -1;
  29.         }
  30. // ??? 如果是订单售票,查找订单
  31. // 修改席位和余额库
  32.         DAU_copy(&sell_DAU,&ctx->ctx_DAU,0);
  33.         strcpy(seat.used_dev,ctx->contex.devid);
  34.         strcpy(seat.used_uid,ctx->contex.userid);
  35.         seat.used_time=ctx->contex.last_oper;
  36.         ret=sell_seat(&seat_DAU,msg,errjson);//comm_app.c,席位售出,如果需要分段在此进行
  37.         DAU_free(&seat_DAU);
  38.         if(ret) {
  39.                 DAU_free(&sell_DAU);
  40.                 return ret;
  41.         }
  42. //调整票据号
  43.         DAU_init(&bill_DAU,ctx->Connect,0,&dbill,DEV_BILL_tpl);
  44.         strcpy(dbill.devid,ctx->contex.devid);
  45.         newvol=bill_add(&bill_DAU,msg,errjson); //comm_app.c,票卷号+1
  46.         if(newvol<0) {
  47.                 DAU_free(&sell_DAU);
  48.                 DAU_free(&bill_DAU);
  49.                 return newvol;
  50.         }
  51. //记存根,我只用这几个字段,其余80或150个与我无关吧?
  52.         sell.stat=0;
  53.         strcpy(sell.ticket_no,msg);                     //当前票号
  54.         sell.chksum=sell_chk_sum(&sell_DAU,msg);        //comm_app.c,计算校验和
  55.         rsecstrfmt(sell.sell_time,ctx->contex.last_oper,YEAR_TO_SEC);
  56.         ret=sell_insert_dao(&sell_DAU,msg);
  57.         if(ret) {
  58.                 json_object_array_add(errjson,jerr(120,msg));
  59.                 DAU_free(&bill_DAU);
  60.                 DAU_free(&sell_DAU);
  61.                 return ret;
  62.         }
  63. //组装返回数据
  64.         //返回下一个票号
  65.         json_object_array_add(errjson,jerr(newvol,dbill.bill_num));
  66.         json=json_object_new_object();
  67.         if(!json) {
  68.                 sprintf(msg,"json MALLOC error");
  69.                 ShowLog(1,"sell_app:%s",msg);
  70.                 DAU_free(&bill_DAU);
  71.                 DAU_free(&sell_DAU);
  72.                 return MEMERR;
  73.         }
  74.         DAU_toJSON(&sell_DAU,json,0);
  75.         json_object_array_add(errjson,json);
  76.         DAU_free(&bill_DAU);
  77.         DAU_free(&sell_DAU);
  78.         return ret;
  79. }
复制代码

[ 本帖最后由 yulihua49 于 2011-9-14 10:41 编辑 ]

使用道具 举报

回复
论坛徽章:
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
158#
 楼主| 发表于 2011-9-14 09:32 | 只看该作者
原帖由 newkid 于 2011-9-14 00:36 发表
num=_DAU.srm.tp[_DAU.srm.Aflg].offset; ------- 这个我说是天书有谁能反对?

这个你抓得真准,不愧大侠。
要是C++,我可以来一个 recsize=table_DAU.getRecsize();
还是封得不严。写一个函数也行,不过不常用。

你既然有oad参数,数组长度应该不难得到,为什么还要设计第二个参数n?

这个很有意思。你看那个零头,肯定n != BATCH_NUM。
这里说到DB2的批插入,它既不能定义起点,也不能定义终点,只能是数组的维,结果很难办。
正是ORACLE的优点,可以操作数组中的一部分。

(我又读了程序发现这个源头来自loadfile的参数buf,难道你是为了避免重复分配内存?那也应该有别的方法吧,何苦把程序接口弄得这么复杂?)

前端分配了内存,在命令行可以-KkBYTEs,指定。因为不知道语句有多大。如果core dumpped,就可以再次申请大一些的。

这个有点搞,你循环里面都提交了,为什么做完反而不提交,而要留给后面的代码?

循环里面10组(10000rows)提交一次。
begin和commit或rollback都是在svc层,另外,不够10组和零头没有commit,等出去做。
这个安排你可以看一下上边的售票记账程序,任何一步出错,都会rollback,记账失败。省得每个出错点都要rollback。C是没有try-catch的。


总之,你还是读懂了,很细。
我想稍微C了解点的,都能读个八九不离十。

对我来说SQL就是业务逻辑的一部分,“取得数据的方法”是重要的一环,这里没写好就会影响整个事务的性能。
就是用PLSQL写存储过程,也有人主张用你的方法,把数据存取分离出来,变成子过程,业务逻辑层不写SQL, 而是调用子过程。我也不是反对这种做法,假如分离出去的部分可以重用、可以改善可读性,也未尝不可。注意前面的两个前提。

这就对了。在模块间传数据,要传结构。模板就是映射结构的,这样模块间方便些。也好读。

Here's the implementation of the C external procedure (refcurdesc.c):
.......

他说这个C外部过程用OCI解析REF CURSOR, 你看看是不是。

是。这部分代码在ORA_Rpc()l里,也是一个包装。不然即使调用存储过程,用OCI也是很麻烦的。


不敢恭维?那么你有更好的?
逻辑要清晰,效率要高,功能要满足(NULL处理,DUPKEY处理,格式处理)
如果用存储过程也必须配一个前端,好把前端的文件加进来。前端用C,JAVA,PHP都行。
代码能短一些?
效率不用和我比了,比sqlldr高就行。

我那个代码主要用于调试OAD。在实际的OLTP应用中,批量插入可以显著改善性能。
如列车编组顺序表,从MQ来,分为报头和正文。报头是关于列车的信息,正文是每辆车的信息,有几十到200个记录。如果一个批量插入,效果显著。其它如股道和车辆,车次和停靠站,订单和一批票等等。我的程序可以做一个DEMO,照猫画虎就可以了。

所以你的程序也应该有示范作用,让别人也可以借鉴。

[ 本帖最后由 yulihua49 于 2011-9-14 19:35 编辑 ]

使用道具 举报

回复
论坛徽章:
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
159#
 楼主| 发表于 2011-9-14 10:55 | 只看该作者
原帖由 newkid 于 2011-9-11 03:29 发表
我还想反过来问你呢,PLSQL能做到的事情,如果效率不低,为什么要把程序写到数据库外?


反正已经确定用OCI了,就服务器其他功能而言,也必须使用模板。用DAU可读性,可维护性都好,何必PLSQL呢。也不是绝对不能用。
多半一懒就不用了。

使用道具 举报

回复
论坛徽章:
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
160#
发表于 2011-9-14 22:23 | 只看该作者
"这个很有意思。你看那个零头,肯定n != BATCH_NUM。"
你的oad里面难道没有计数器?OAD_pkg_dispack里面进行累计,原来n=0的时候就清零。

"前端分配了内存,在命令行可以-KkBYTEs,指定。因为不知道语句有多大。如果core dumpped,就可以再次申请大一些的。"
那你可以搞一块公共的缓存来操作吧?没必要把一个指针在所有接口中传来传去。

"循环里面10组(10000rows)提交一次。
begin和commit或rollback都是在svc层,另外,不够10组和零头没有commit,等出去做。"
为什么要等“出去”再做?你完全可以在返回之前提交啊?(按我的做法就是在里面把if(feof(ifd))和commit_num == COMMIT_NUM的条件合并)你这个loadfile不可能包含在其他事务中。

“这个安排你可以看一下上边的售票记账程序,任何一步出错,都会rollback,记账失败。省得每个出错点都要rollback。C是没有try-catch的。”
等会再看。


"总之,你还是读懂了,很细。"
我读懂了,所以我有资格认为比PLSQL代码更不好读。


"不敢恭维?那么你有更好的?
逻辑要清晰,效率要高,功能要满足(NULL处理,DUPKEY处理,格式处理)
如果用存储过程也必须配一个前端,好把前端的文件加进来。前端用C,JAVA,PHP都行。
代码能短一些?
效率不用和我比了,比sqlldr高就行。"

用外部表,只需写表定义(如果还嫌麻烦就用动态SQL生成表定义)。
没有读文件部分,没有解析部分(但是具备SQLLDR所有解析功能,比你强大得多)。
直接用SQL访问,可以做任何连接、变换。
我才不吃饱了撑的写代码。

使用道具 举报

回复

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

本版积分规则 发表回复

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