楼主: 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
251#
 楼主| 发表于 2009-2-26 17:08 | 只看该作者
原帖由 qingyun 于 2009-2-25 11:37 发表
楼主的包容器,就算再好,我觉得有3大硬伤:
1.用C开发,很多人不是很懂,大部分人都是搞java的;特别是数据库方面,鲜有听说用C的;所以你这个包容器如何让别人和你协助开发是个问题;
2.现在不是有现成的ejb,hibernate等数据访问层框架,有必要你再搞了类似功能的C的包容器,就算你做的比他们好,你又怎能以一己之力抗衡之;
3.对于Oracle,它本身就是java开发,所以它和java更有天然的交互性;

我觉得楼主可以把你的包容器做成一个开源框架,让相关的爱好者共同参与完善;可能会成为一个气候。也是不错的选择;

C语言现在的确是小众。
但我们的情况是必须用C。其实领导们并不爽,他们喜欢JAVA,用C是实在没办法。
C写数据库很麻烦的,JAVA框架又不能用,所以要做C框架。
我很想开源,需要有人能在这方面帮助我,但现在无人喝彩,如果哪位有兴趣,可以提供全套源码。我更愿意探讨这东西怎么做更好,而不是做不做的问题。

另外我们是做3层C/S的,都是客户端与数据库间的传递。用这个框架很好。如果是从数据库来到数据库去,我可能考虑存储过程。
如前边说的聚合函数和group by的东西,结帐时用,其他时候基本不用。就是说,90%以上DAU就够用了。

所谓程序‘优雅’问题,不是审美的问题,玩JAVA的可能都知道,是指程序具有优良的结构,逻辑清晰,简洁易懂,易改,可重用等等。
例如,看我前边的程序,一句 DAU_insert(&_DAU,stmt);立刻就懂了,把一个数据插入数据库了。怎么插的?插的什么,当你关心业务逻辑是,可以暂时不管这些。
如果你关心存储逻辑,那么我们就可以讨论了。首先在日志里看到了insert语句,大致了解了其性能。也可以要求日志bind区,看数据是否正确。
通过前边的讨论你大概可以知道DAU通过数据库字典得到表结构,这个程序在前边。有了模板,就可以生成语句了,根据模板可以生成数据区,有了数据区,就可以装填和bind数据了。就这么简单,产生了高度通用的程序。应用程序员就不用关心细节了。

[ 本帖最后由 yulihua49 于 2009-2-26 17:58 编辑 ]

使用道具 举报

回复
论坛徽章:
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
252#
发表于 2009-2-26 23:26 | 只看该作者
原帖由 yulihua49 于 2009-2-26 17:03 发表

谢谢。技术上的交锋可以增进友谊。


看来我们还真是猩猩相惜呀。现在哪天不和你辩上几句我就有种失落感呢。

所谓程序‘优雅’问题,不是审美的问题,玩JAVA的可能都知道,是指程序具有优良的结构,逻辑清晰,简洁易懂,易改,可重用等等。

你说的这些优点我在PLSQL上都能找到。当然写得烂的也有,这得分情况。

例如,看我前边的程序,一句 DAU_insert(&_DAU,stmt);立刻就懂了,把一个数据插入数据库了。怎么插的?插的什么,当你关心业务逻辑是,可以暂时不管这些。

你这句话我只看到了INSERT动作,更重要的信息我没看到。怎么可以不管“插的什么”?业务逻辑不都在这里体现吗?
举个类似的例子,PLSQL中可以把一个变量声明为行变量,相当于一个结构:
DECLARE
   lv_row my_table%ROWTYPE;

你可以先写一堆代码给变量lv_row里面的每个字段赋值,然后:
INSERT INTO my_table VALUES lv_row;

这句话优雅吧?可是它给你很少的信息。我更愿意把字段带入INSERT, 在VALUES中写计算, 或在INSERT...SELECT中完成计算。在一个地方我看到了我需要的所有信息。

其实领导们并不爽,他们喜欢JAVA,用C是实在没办法。

愿问其详?为什么非用不可?
所有非商业性的项目都得服从进化论,适者生存,只要你的作品有其生命力就不怕没市场。

我在#250又下了挑战书,你有空看一下吧。

使用道具 举报

回复
论坛徽章:
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
253#
发表于 2009-2-27 04:02 | 只看该作者
我刚才突然想起一个事,验证了一下,结果成功地把那个“抢票”的存储过程提速了。
我原来用的是FOR循环游标。在10G里面ORACLE会自动预先FETCH 100行记录,因为这是个高度并发的一致读,有大量的并发修改,它不得不频频访问回滚段。
而我们需要的票是远远小于100张的。我的测试脚本用100个JOB去抢,每人要5张。因此这个100行一致读是很浪费的。我改用显性游标,按常规的写法OPEN,FETCH,CLOSE, 结果新程序的用时只有原来的三分之一。
你的程序应该没有这个问题,本来用的就是显性游标,估计你也没有BULK FETCH。

使用道具 举报

回复
论坛徽章:
26
ITPUB新首页上线纪念徽章
日期:2007-10-20 08:38:44ITPUB十周年纪念徽章
日期:2011-11-01 16:20:282012新春纪念徽章
日期:2012-01-04 11:49:542013年新春福章
日期:2013-02-25 14:51:24夏利
日期:2013-08-13 23:25:29优秀写手
日期:2013-12-18 09:29:092014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11蓝色妖姬
日期:2015-03-19 09:37:00ITPUB年度最佳技术原创精华奖
日期:2015-03-19 09:43:24
254#
发表于 2009-2-27 10:35 | 只看该作者
原帖由 newkid 于 2009-2-27 04:02 发表
我刚才突然想起一个事,验证了一下,结果成功地把那个“抢票”的存储过程提速了。
我原来用的是FOR循环游标。在10G里面ORACLE会自动预先FETCH 100行记录,因为这是个高度并发的一致读,有大量的并发修改,它不得不频频访问回滚段。
而我们需要的票是远远小于100张的。我的测试脚本用100个JOB去抢,每人要5张。因此这个100行一致读是很浪费的。我改用显性游标,按常规的写法OPEN,FETCH,CLOSE, 结果新程序的用时只有原来的三分之一。
你的程序应该没有这个问题,本来用的就是显性游标,估计你也没有BULK FETCH。


没想到显示游标和 for xxx in (select 。。。) 这样的隐式游标比,性能相差这么大啊,有空我也测试一下;
据说 for  xx in 这种隐式游标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
255#
 楼主| 发表于 2009-2-27 10:52 | 只看该作者
原帖由 newkid 于 2009-2-27 04:02 发表
我刚才突然想起一个事,验证了一下,结果成功地把那个“抢票”的存储过程提速了。
我原来用的是FOR循环游标。在10G里面ORACLE会自动预先FETCH 100行记录,因为这是个高度并发的一致读,有大量的并发修改,它不得不频频访问回滚段。
而我们需要的票是远远小于100张的。我的测试脚本用100个JOB去抢,每人要5张。因此这个100行一致读是很浪费的。我改用显性游标,按常规的写法OPEN,FETCH,CLOSE, 结果新程序的用时只有原来的三分之一。
你的程序应该没有这个问题,本来用的就是显性游标,估计你也没有BULK FETCH。

是的。所以,我当初300个进程争夺时,时间比你那个测试少得多,我没敢说比你快,只说旗鼓相当。现在咱们速度差不多了。其实几十%的性能差别,用户根本不关心,只是我们做技术的在测着玩。其实最关键的,bind的作用你给我讲懂了,实现了,大家都速度不会有天翻地覆的差别。

为什么用C?这超出了这个专题,可以说一下。1.TUXEDO是选定的中间件,业主和开发商共同论证、测试过的。TUXEDO只支持C。2.用C的多进程、无状态长连接方式是最适于这个项目的。
论证这个问题,要弄清大密度交易时的负载线性可伸缩的问题,就是响应时间1+1=2的问题,非线性指1+1>2,超线性指1+1<2。
TUXEDO在低负载时具有超线性,大负载时具有线性特征,而J2EE具有非线性特征,而且过载极易崩溃。
TUXEDO是服务器池方式,大量呼叫涌入,没有空闲服务可用时,呼叫请求被排队。其调度策略很好,大规模压力测试表明负载完全是线性的,不会崩溃。


比方我那个300客户端争夺实验就是在TUXEDO进行的,4核处理机,20个服务进程。即使300个请求同时到达,最多也只有20个人在争夺,其余在排队。这大大减少了系统的无序性,提高了系统的线性度。

J2EE为什么非线性?因为JAVA的多线程,又大量存储分配,在公共的池里分配,必然互斥。还有垃圾收集,是不可控的过程。在大负荷下是否有内存可用是不确定因素。
在C的多进程环境,没有JAVA那么多的存储分配,又是独享空间,没有互斥。又是有限的服务进程,内存需求是有限的。这一切保证了系统的稳定性和可靠性,永远不会因拥挤而崩溃。进程是预先启动好的,服务时没有进程启动开销。

我们的测试有点不公平哦!我的300个客户请求是不包含进程启动,打开、关闭数据库的,占了便宜。

经测试,JDBC比SDBC慢不少(一半到1/3吧)。SDBC是我们开发的,是DAU的底层。就是说J比C还是要慢不少的。用C自有用C的道理。
不过这个结果,JDBC已经相当不错了,如果ODBC,只有SDBC几十分之一的性能。

[ 本帖最后由 yulihua49 于 2009-2-27 16:04 编辑 ]

使用道具 举报

回复
论坛徽章:
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
256#
 楼主| 发表于 2009-2-27 11:17 | 只看该作者
原帖由 qingyun 于 2009-2-27 10:35 发表


没想到显示游标和 for xxx in (select 。。。) 这样的隐式游标比,性能相差这么大啊,有空我也测试一下;
据说 for  xx in 这种隐式游标oracle内部是做优化的。

我测试结果是差3倍,与newkid的结果一样。所以我在前边的帖子里一再说,DAU为你保留游标,提高了性能。
而且保留了bind树,不论显示隐式,连bind都省了,很少谁的程序能做出这个。
再一次提示朋友们,包装器,不会比系统性能更好,但是很可能比你自己写的程序性能好。

[ 本帖最后由 yulihua49 于 2009-2-27 11:19 编辑 ]

使用道具 举报

回复
论坛徽章:
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
257#
 楼主| 发表于 2009-2-27 11:34 | 只看该作者
原帖由 newkid 于 2009-2-24 23:53 发表

你我那个自动生成空票的业务模块,我们来比试一下如何?你可以把原始需求保密,修改到你认为对包装器最有利的状态。

保密到不是绝对的,管中窥豹也无妨。只是涉及到数据结构很多,比方车次表、停靠站表、母表等等,太复杂,不好测。原先也不是DAU写的,最近用DAU改写了一下,还没调试。
可以在这show一下,看看能否容易看出业务逻辑。现在太忙,下周不在家,过几日再聊。

从最后一个程序main看起。


  1. /****************************************************
  2. * 席位发布 新的母表格式
  3. * usage sample:
  4. * xwfb -f xbfb.ini -d 日期表达式 -c 车次 -n 车厢号,车厢号,...
  5. ****************************************************/
  6. #include <kpapp.h>
  7. #include <libgen.h>

  8. static INT4 today;
  9. static int dflg=0;

  10. static int xwfb(DAU *train_DAU,char *carno);
  11. // 以下定义DAO函数
  12. static int adj_remant(DAU *DP,char *stmt)
  13. {
  14. int ret;
  15. char tmp[2048],*p;
  16. int amoung;

  17.         p=stmt;
  18.         amoung=((SEAT_REMANT_stu *)DP->srm.rec)->amoung;
  19.         if(DP->pre_sth<0) {
  20.         char *p;
  21.                 p=DAU_mk_where(DP,DP->srm.pks,stmt);
  22.                 p+=sprintf(p," for update");
  23.         }
  24.         if((ret=DAU_prepare(DP,stmt)) || DAU_next(DP)) {
  25.                 if(DP->SQL_Connect->Errno == SQLNOTFOUND)
  26.                         return DAU_insert(DP,stmt);
  27.                 ShowLog(1,"adj_remant stmt=%s",stmt);
  28.                 return ret;
  29.         }
  30.         ((SEAT_REMANT_stu *)DP->srm.rec)->amoung += amoung ;
  31.         ret=update_by_PK(DP,stmt);
  32.         if(ret != 1) {
  33.                 ShowLog(1,"adj_remant stmt= %s",stmt);
  34.         }
  35.         return 0;
  36. }

  37. int addxw(DAU *DP,char *stmt)
  38. {
  39. int ret;
  40.         if(ret=DAU_insert(DP,stmt)) {
  41.                 if(DP->SQL_Connect->Errno == DUPKEY) { //dummy_update
  42.                         if(DP->upd_sth<0) {
  43.                                 char *p=DAU_mk_update(DP,stmt);
  44.                                 p+=sprintf(p,"SET %s=%s ",DP->srm.tp[0].name,DP->srm.tp[0].name);
  45.                                 DAU_mk_where(DP,DP->srm.pks,p);
  46.                         }
  47.                         DAU_update(DP,stmt);
  48.                 } else  ShowLog(1,"addxw:%s",stmt);
  49.         }
  50.         return ret;
  51. }
  52. /* 确定了车次,没有确定车站,可能会有若干车站 */
  53. int stop_station_dao(DAU *DP,char *stmt)
  54. {
  55.         sprintf(stmt,"WHERE train_no=:train_no AND beg_date <= :beg_date AND end_date >= :beg_date AND flag=0 AND over>0 ");
  56.         ret DAU_select(DP,stmt,0);
  57. }
  58. // 车次车站都确定了,只有一条记录
  59. int get_stop_station(DAU *DP,char *stmt)
  60. {
  61. char *p;

  62.         p=DAU_mk_where(DP,"train_no,sequence",stmt);
  63.         sprintf(p," AND beg_date <= :beg_date AND end_date >= :beg_date AND flag=0")
  64.         if(0 >= DAU_select(DP,stmt,1)) {
  65.                 ShowLog(1,"get_stop_station stmt=%s",stmt);
  66.                 return DP->SQL_Connect->Errno;
  67.         }
  68.         return DAU_next(DP);
  69. }

  70. int train_dao(DAU *train_DAU,char *stmt)
  71. {
  72. TRAIN_stu *train;
  73. char *p;

  74.         train=(TRAIN_stu *)train_DAU->srm.rec;
  75.         p=stmt;
  76.         p+=sprintf(p,"WHERE flag=0 AND end_date >= :beg_date ");                //today存放在beg_date
  77.         if(*train->train_no)
  78.                 p+=sprintf(p,"AND train_no=:train_no");
  79.         return DAU_select(train_DAU,stmt,0);
  80. }

  81. INT4 getday(DAU *train_DAU,char *stmt)
  82. {
  83. /* 应该根据权限查找相应的天数 */
  84.         return 10;
  85. }
  86. //DAO函数定义完毕

  87. static int mkxw(DAU *pre_DAU,char *stmt,char *day,int start_time, char *carno)
  88. {
  89. int ret,i;
  90. INT64 now;
  91. char s_now[30];
  92. INT4 jobday;
  93. int totalnum=0;
  94. PRE_SEAT_INDEX_stu *pre_index;
  95. PRE_SEAT_stu pre_seat;
  96. SEAT_stu seat;
  97. SEAT_REMANT_stu remant;
  98. STOP_STATION_stu stop_station;
  99. DAU pre_seat_DAU,cz_DAU,seat_DAU,remant_DAU;

  100.         DAU_init(&pre_seat_DAU,pre_DAU->SQL_Connect,0,&pre_seat,PRE_SEAT_tpl);
  101.         DAU_init(&cz_DAU,pre_DAU->SQL_Connect,0,&stop_station,STOP_STATION_tpl);
  102.         DAU_init(&seat_DAU,pre_DAU->SQL_Connect,0,&seat,SEAT_tpl);
  103.         DAU_init(&remant_DAU,pre_DAU->SQL_Connect,0,&remant,SEAT_REMANT_tpl);

  104.         pre_index=(PRE_SEAT_INDEX_stu *)pre_DAU->srm.rec;
  105.         jobday=rstrfmttojul(day,YEAR_TO_DAY);
  106.         strcpy(stop_station.train_no,pre_index->train_no);

  107.         rjultostrfmt(s_now,pre_index->beg_date,"YYYYMMDD");
  108.         sprintf(pre_seat.pre_id,"%s:%c:%s", pre_index->Train_no,*pre_index->item,s_now);
  109.         sprintf(stmt,"WHERE pre_id=:pre_id");
  110.         if(0 >= (ret=DAU_select(&pre_seat_DAU,stmt,0))) {
  111.                 ShowLog(1,"mkxw stmt=%s,err=%d.%s",stmt);
  112.                 return ret;
  113.         }

  114.         now=now_sec();
  115.         strcpy(seat.start_date,day);
  116.         strcpy(seat.used_dev,"xwfb");
  117.         strcpy(seat.used_uid,seat.used_dev);
  118.         seat.used_time=now;
  119.         seat.flag=0; // 应该是=3,暂不可用
  120.         strcpy(seat.train_no,pre_index.train_no);
  121.         pre_index.distribute_time=now;

  122.         while(!DAU_next(&pre_seat_DAU)) {
  123.                 stop_station.sequence=pre_seat.beg_station;
  124.                 stop_station.beg_date=jobday;
  125.                 if(get_stop_station(&cz_DAU,stmt)) continue;

  126.                 i=start_time+stop_station.running_time+stop_station.stop_time;
  127.                 ret=jobday*1440+timezone/60+i;
  128.                 rminstrfmt(seat.on_date,ret,YEAR_TO_MIN);               //上车时间
  129.                 strcpy(seat.beg_station,stop_station.station_code);     //上车站代码
  130.                 strcpy(seat.run_train,stop_station.run_train_no);
  131.                 seat.Carno=pre_seat.Carno;
  132.                 seat.end_station=pre_seat.end_station;
  133.                 seat.shortest_station=pre_seat.shortest_station;
  134.                 seat.purpose=pre_seat.purpose;
  135.                 strcpy(seat.gride,pre_seat.gride);
  136.                 DAU_copy(&remant_DAU,&seat_DAU,0);
  137.                 remant.amoung=0;

  138.                 for(i=pre_seat.beg_seatno;i<=pre_seat.end_seatno;i++) {
  139.                         seat.seat_no=i;
  140.                         *seat.pro=0; //应该查编组库确定席位属性
  141.                         seat.seat_type=pre_seat.seat_type;
  142.                         if(pre_seat.seat_type==20) { //硬卧
  143.                         int j;
  144.                                 for(j=0;j<3;j++) {
  145.                                         seat.seat_type++;
  146.                                         ret=addxw(&seat_DAU,stmt);
  147.                                         if(!ret) remant.amoung++,totalnum++;
  148.                                 }
  149.                         } else {
  150.                                 if(pre_seat.seat_type==30) { //软卧
  151.                                         seat.seat_type++;
  152.                                         if(!(i&1)) seat.seat_type++;
  153.                                 }
  154.                                 ret=addxw(&seat_DAU,stmt);
  155.                                 if(!ret) remant.amoung++,totalnum++;
  156.                         }

  157.                 }
  158. ShowLog(2,"mkxw Train=%s:%s,beg_station=%s,end_station=%d,carno=%d,remant=%d",
  159. remant.on_date,remant.run_train,remant.beg_station,remant.end_station,remant.Carno,remant.amoung);

  160.                 if(!seat.flag && remant.amoung>0)
  161.                         ret=adj_remant(&remant_DAU,stmt);

  162.                 if(pre_DAU->upd_sth<0) {
  163.                 char *p=stmt;
  164.                         p+=sprintf(p,"UPDATE %s.PRE_SEAT_INDEX SET "
  165.                             "distribute_time=:distribute_time ");
  166.                         p=DAU_mk_where(&pre_DAU,pre_DAU->srm.pks,p);
  167.                 }
  168.                 if(1 != DAU_update(pre_DAU,stmt)) {
  169.                         ShowLog(1,"mkxw stmt= %s",stmt);
  170.                 }
  171.         }
  172.         DAU_feee(&pre_seat_DAU);
  173.         DAU_feee(&cz_DAU);
  174.         DAU_feee(&seat_DAU);
  175.         DAU_feee(&remant_DAU);
  176.         return totalnum;
  177. }

  178. int xwfb(DAU  *train_DAU,char *carno)
  179. {
  180. char *p,stmt[4096],tmp[4096],day[30];
  181. int ret,i,i_item;
  182. INT4 jobday,totalnum=0;
  183. INT64 now;
  184. TRAIN_stu *train;
  185. SEAT_stu seat;
  186. PRE_SEAT_INDEX_stu pre_rec;
  187. SEAT_REMANT_stu remant;
  188. STOP_STATIOn_stu stop_station;
  189. DAU stop_station_DAU,seat_DAU,seat_remant_DAU,pre_seat_DAU;

  190.         train=(TRAIN_stu *)train_DAU->srm.rec;
  191.         now=now_sec();
  192.         rjultostrfmt(day,today,YEAR_TO_DAY);
  193.         trans_begin(train_DAU->SQL_Connect);
  194.         ret=train_dao(train_DAU,stmt);
  195.         if(ret<=0) {
  196.                 ShowLog(1,"没找到车次 %s",stmt);
  197.                 return -1;
  198.         }
  199.         DAU_init(&pre_seat_DAU,train_DAU->SQL_Connect,0,&pre_rec,PRE_SEAT_INDEX_tpl);
  200.         DAU_init(&stop_station_DAU,train_DAU->SQL_Connect,0,&stop_station,STOP_STATION_tpl);
  201.         DAU_init(&seat_DAU,train_DAU->SQL_Connect,0,&seat,SEAT_tpl);
  202.         DAU_init(&seat_remant_DAU,train_DAU->SQL_Connect,0,&seat_remant,SEAT_REMANT_tpl);

  203.         while(!DAU_next(train_DAU)) { //对于每一个车次
  204.                 jobday=today; //每次需要重新设定
  205.                 if(!dflg) { // 没有指定日期,按规定设置提前量
  206.                         if(train->days>0) jobday=today+train->days;
  207.                         else jobday+=getday(&train_DAU,stmt);
  208.                 }
  209.                 if(train->beg_date > jobday || train->end_date < jobday)
  210.                                  continue;
  211.                 /* 计算席位母表周期 */
  212.                 i=(jobday-train->beg_date)%strlen(train->cycle);
  213.                 i_item=train->cycle[i];
  214.                 rjultostrfmt(day,jobday,YEAR_TO_DAY);
  215. ShowLog(5,"xwfb gettrain:Train_no=%s,beg_date=%s,end_date=%s,jobday=%s,i_item=%c",
  216.         train->train_no, rjulstr(tmp,train->beg_date), rjulstr(tmp+100,train->end_date),day,i_item);
  217.                 if(i_item=='0') continue;

  218. // 准备发布无号席位
  219.                 strcpy(stop_station.train_no,train->train_no);
  220.                 stop_station.beg_date=jobday;
  221.                 ret=stop_station_dao(&stop_station_DAU,stmt);
  222.                 if(ret < 1) {
  223.                         ShowLog(1,"xwfb 为无号查找停靠站表 stmt=%s, err=%d,%s", stmt);
  224.                 } else {
  225.                   strcpy(seat.train_no,train->train_no);
  226.                   strcpy(seat.gride,train->gride); // 如果无号的等级不是列车等级怎么办?
  227.                   seat.end_station=train->station_num-1;
  228.                   strcpy(seat.start_date,day);
  229.                   seat.carno=0;
  230.                   seat.purpose=0; //????
  231.                   seat.seat_type=0;
  232.                   seat.shortest_station=0;
  233.                   seat.flag=0;  // 应该=3,暂不可用
  234.                   seat.used_time=now;
  235.                   strcpy(seat.used_dev,"xwfb");
  236.                   strcpy(seat.used_uid,seat.used_dev);

  237.                   while(!DAU_next(&stop_station_DAU)) {//该车次的各站
  238.                     strcpy(seat.beg_station,stop_station.station_code);
  239.                     i=train->start_time+stop_station.running_time+
  240.                         stop_station.stop_time;
  241.                     rminstrfmt(seat.on_date,jobday*1440+i/1440,YEAR_TO_MIN);
  242.                     strcpy(seat.run_train,stop_station.run_train_no);
  243.                     if(seat.end_station <= stop_station.sequence) {
  244.                         ShowLog(1,"无号:%s: 起止站错 seq=%d,station_num=%d",
  245.                                 seat.Train_no,stop_station.sequence,
  246.                                 train->station_num);
  247.                         continue;
  248.                     }
  249.                     *seat.pro=0; //席位属性
  250.                     DAU_copy(&seat_remant_DAU,&seat_DAU,0);
  251.                     remant.amoung=0;
  252.                     for(i=0;i<stop_station.over;i++) {
  253.                         seat.seat_no=i+1;
  254.                         ret=addxw(&seat_DAU,stmt);
  255.                         if(!ret) remant.amoung++;
  256.                     }
  257.                     totalnum += remant.amoung;
  258. ShowLog(2,"Train=%s;%s,carno=%d,beg_station=%s,end_station=%d,remant=%d",
  259. remant.on_date,remant.run_train,remant.Carno,remant.beg_station,remant.end_station,remant.amoung);
  260.                     if(!seat.flag && remant.amoung) ret=adj_remant(&seat_remant_DAU,stmt);
  261.                   }
  262.                 }
  263. // 发布普通席位
  264.                 pre_rec.beg_date=jobday;
  265.                 strcpy(pre_rec.train_no,train->train_no);
  266.                 pre_rec.item=i_item;
  267.                 p=DAU_mk_where(&pre_seat_DAU,"train_no,item",stmt);//stmt="WHERE train_no=:train_no AND item=:item "
  268.                 sprintf(p," AND beg_date <= :beg_date AND end_date >= :beg_date AND flag=0");//这两个日期字段将被变换为to_date(:?,'YYYY-MM-DD')
  269.                 if(0 >= DAU_select(&pre_seat_DAU,stmt,1)) continue;
  270.                 DAU_next(&pre_seat_DAU);
  271.                 ret=mkxw(&pre_seat_DAU,stmt,day,train->start_time,carno);
  272.                 if(ret>0) totalnum+=ret;
  273.                 trans_commit(train_DAU->SQL_Connect);
  274.         }
  275.         DAU_free(&stop_station_DAU);
  276.         DAU_free(&seat_DAU);
  277.         DAU_free(&stat_remant_DAU);
  278.         DAU_free(&pre_seat_DAU);
  279.         trans_commit(train_DAU->SQL_Connect);
  280.         ShowLog(2,"totalnum=%d",totalnum);

  281.         return 0;
  282. }

  283. static char my_showid[128];
  284. main(int argc,char *argv[])
  285. {
  286. int ret,i;
  287. T_SQL_Connect SQL_Connect;
  288. DAU train_DAU;
  289. TRAIN_stu train;
  290. char *carno=0;

  291.         tzset();
  292.         nice(10);
  293.         nice(10);
  294.         today=rtoday();
  295.         sprintf(my_showid,"%s:%d",basename(argv[0]),getpid());
  296.         Showid=my_showid;
  297.         memset(train.train_no,0,sizeof(train.train_no));

  298. /*******************************************************************
  299. *  get Opt
  300. *******************************************************************/
  301.         for(i=1;i<argc;i++) {
  302.                 if(*argv[i]=='-') {
  303.                         switch(argv[i][1]) {
  304.                         case 'f':
  305.                                 if(argv[i][2]) ret=envcfg(argv[i]+2);
  306.                                 else {
  307.                                         i++;
  308.                                         ret=envcfg(argv[i]);
  309.                                 }
  310.                                 continue;

  311.                         case 'd':
  312.                                 dflg=1;
  313.                         case 'D':
  314.                                 if(argv[i][2]) today=cvtdate(&argv[i][2],today);
  315.                                 else {
  316.                                         i++;
  317.                                         today=cvtdate(argv[i],today);
  318.                                 }
  319.                                 continue;

  320.                         case 'c':
  321.                                 if(argv[i][2]) strncpy(train.Train_no,
  322.                                         &argv[i][2],sizeof(train.train_no)-1);
  323.                                 else {
  324.                                         i++;
  325.                                         strncpy(train.train_no,
  326.                                              argv[i],sizeof(train.train_no)-1);
  327.                                 }
  328.                                 continue;

  329.                         case 'n':
  330.                                 if(argv[i][2]) carno=&argv[i][2];
  331.                                 else {
  332.                                         i++;
  333.                                         carno=argv[i];
  334.                                 }
  335.                                 continue;

  336.                         default:
  337.                                 fprintf(stderr,"no know option:%s",argv[i]);
  338.                                 fprintf(stderr,"Usage:%s -f 配置文件 -d 日期表达式 -c 车次 -n 车厢号,车厢号,...",
  339.                                         argv[0]);
  340.                                 continue;
  341.                         }
  342.                 }
  343.         }
  344. /*********************************************************************
  345. *      Open DATABASE
  346. *********************************************************************/
  347.         if(!*train.train_no) carno=0;
  348.         train.beg_date=today;

  349.         ret=db_open(&SQL_Connect);
  350.         if(ret) {
  351.                 ShowLog(1,"Open Database err=%d.%s",
  352.                         SQL_Connect.Errno,
  353.                         SQL_Connect.ErrMsg);
  354.                 return 1;
  355.         }
  356.         DAU_init(&train_DAU,&SQL_Connect,0,&train,TRAIN_tpl);

  357.         ret=xwfb(&train_DAU,carno);

  358.         DAU_free(&train_DAU);
  359.         ___SQL_CloseDatabase__(&SQL_Connect);
  360.         return(0);
  361. }
复制代码

[ 本帖最后由 yulihua49 于 2009-3-7 09:42 编辑 ]

使用道具 举报

回复
论坛徽章:
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
258#
 楼主| 发表于 2009-2-27 14:12 | 只看该作者
[quote]原帖由 newkid 于 2009-2-24 23:53 发表

模板意味着动态SQL, 这个我是坚决反对的。它隐藏了数据库编程最有用的信息,SQL不可知,查询计划不可知,给调优、排错制造了障碍。

不是动态SQL,是自动生成的SQL,日志里有生成的语句。原来是带值语句,非常容易调试,粘到sqlplus里就可以执行。后来改bind,没那么方便了,但是还是可以打印一个bind区协助调试。况且,一个没有select的insert语句,有什么好看的呢?
查询计划可知。

___SQL_Exec(SQL_Connect,"set trace on");//语句可能不对,反正是给一条打开explain的语句就行了。

上边的程序看不到数据结构,太抽象了,只有抽象的东西才是通用的东西,具体的,只能是专用的。
框架面对形形色色的对象,所以,必须抽象,结果应用程序也抽象了。但是,这并不妨碍程序逻辑的阅读,
至少,应该在语法逻辑的理解没有太大问题,业务逻辑还真是一时半会交代不清,看你的造化了。

[ 本帖最后由 yulihua49 于 2009-2-27 14:22 编辑 ]

使用道具 举报

回复
论坛徽章:
26
ITPUB新首页上线纪念徽章
日期:2007-10-20 08:38:44ITPUB十周年纪念徽章
日期:2011-11-01 16:20:282012新春纪念徽章
日期:2012-01-04 11:49:542013年新春福章
日期:2013-02-25 14:51:24夏利
日期:2013-08-13 23:25:29优秀写手
日期:2013-12-18 09:29:092014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11蓝色妖姬
日期:2015-03-19 09:37:00ITPUB年度最佳技术原创精华奖
日期:2015-03-19 09:43:24
259#
发表于 2009-2-27 14:57 | 只看该作者
原帖由 yulihua49 于 2009-2-27 14:12 发表
[quote]原帖由 newkid 于 2009-2-24 23:53 发表

模板意味着动态SQL, 这个我是坚决反对的。它隐藏了数据库编程最有用的信息,SQL不可知,查询计划不可知,给调优、排错制造了障碍。

不是动态SQL,是自动生成的SQL,日志里有生成的语句。原来是带值语句,非常容易调试,粘到sqlplus里就可以执行。后来改bind,没那么方便了,但是还是可以打印一个bind区协助调试。况且,一个没有select的insert语句,有什么好看的呢?
查询计划可知。

___SQL_Exec(SQL_Connect,"set trace on");//语句可能不对,反正是给一条打开explain的语句就行了。

上边的程序看不到数据结构,太抽象了,只有抽象的东西才是通用的东西,具体的,只能是专用的。
框架面对形形色色的对象,所以,必须抽象,结果应用程序也抽象了。但是,这并不妨碍程序逻辑的阅读,
至少,应该在语法逻辑的理解没有太大问题,业务逻辑还真是一时半会交代不清,看你的造化了。


自动生成的SQL 也是动态语句,因为在你的C程序里,sql相当于一段字符串,你在编译C程序的时候,编译器能够识别sql的语法错误吗?应该不会,编译器只会把它认为普通的字符串而已;

你这句话 ___SQL_Exec(SQL_Connect,"set trace on"); 里的SQL_Connect 应该是个字符串变量参数吧,显然是动态语句处理;

  其实,只要是前台应用程序,访问数据库都是动态语句;比如简单的 select *from 之类,没什么业务处理,这些只能动态了;
但如果设计到大量的数据操作(update之类),就应该把它做成包或存储过程,这样过程里的语句都是静态语句,编译oracle自身做优化,
什么是静态:静态说白了,就是不运行,也能知道sql写的对否,因为是预编译的,比如在存储过程里的语句,任何语法错误都不允许,也不允许写错一个对象;当然过程里也可能有动态语句,比如 execute immediate 'select ...' 但是这些都是实在没办法才用;
所以说,只要不是pl/sql的过程或包;其他方式的与数据库交互的sql都是性能欠佳的动态语句;而且很多习惯不好的开发人员还不用变量绑定;好好的oracle数据库就让这些人瞎糟蹋,知道他们这么用,还不如让他们用Access算了;

使用道具 举报

回复
论坛徽章:
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
260#
 楼主| 发表于 2009-2-27 15:44 | 只看该作者
原帖由 qingyun 于 2009-2-27 14:57 发表


自动生成的SQL 也是动态语句,因为在你的C程序里,sql相当于一段字符串,你在编译C程序的时候,编译器能够识别sql的语法错误吗?应该不会,编译器只会把它认为普通的字符串而已;

你这句话 ___SQL_Exec(SQL_Connect,"set trace on"); 里的SQL_Connect 应该是个字符串变量参数吧,显然是动态语句处理;

  其实,只要是前台应用程序,访问数据库都是动态语句;比如简单的 select *from 之类,没什么业务处理,这些只能动态了;
但如果设计到大量的数据操作(update之类),就应该把它做成包或存储过程,这样过程里的语句都是静态语句,编译oracle自身做优化,
什么是静态:静态说白了,就是不运行,也能知道sql写的对否,因为是预编译的,比如在存储过程里的语句,任何语法错误都不允许,也不允许写错一个对象;当然过程里也可能有动态语句,比如 execute immediate 'select ...' 但是这些都是实在没办法才用;
所以说,只要不是pl/sql的过程或包;其他方式的与数据库交互的sql都是性能欠佳的动态语句;而且很多习惯不好的开发人员还不用变量绑定;好好的oracle数据库就让这些人瞎糟蹋,知道他们这么用,还不如让他们用Access算了;

学习了。我原来以为使用SQLDA结构接收变量的是动态语句(好像ORACLE的文档里这么说的,记不清了)。
那OCI全是动态了?PRO*C呢?
那newkid坚决反对就没法照办了,PRO*C和OCI总不能不用吧?JDBC呢?漫天漫地的啊,Hibernate都不太支持存储过程的啊都是用语句的。
好在我还是bind了,语句的解释只一次。像TUXEDO,启动后,第一次服务,语句就解释了,它是驻留的进程,以后的服务效率会很高的。

[ 本帖最后由 yulihua49 于 2009-2-27 15:58 编辑 ]

使用道具 举报

回复

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

本版积分规则 发表回复

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