楼主: yulihua49

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

[复制链接]
论坛徽章:
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
51#
 楼主| 发表于 2011-8-25 10:16 | 只看该作者
原帖由 newkid 于 2011-8-25 01:14 发表



设置环境:用DBA对该用户授权:
GRANT CREATE ANY CONTEXT TO XXXXX;

这里把XXXXX换成你真正的用户名。

然后用XXXXX登录:

CREATE OR REPLACE CONTEXT APP_CTX USING get_data;
---- 上面创建的CONTEXT是为了传递绑定变量。

CREATE OR REPLACE PACKAGE get_data
AS
PROCEDURE read (
          p_output     OUT SYS_REFCURSOR
         ,p_tablename   IN VARCHAR2
         ,p_where       IN VARCHAR2
         ,p_page_size   IN NUMBER DEFAULT 0
         ,p_page_idx    IN NUMBER DEFAULT 0
         ,p_values      IN VARCHAR2
         );
END;
/



CREATE OR REPLACE PACKAGE BODY get_data
AS
PROCEDURE read (
          p_output     OUT SYS_REFCURSOR
         ,p_tablename   IN VARCHAR2
         ,p_where       IN VARCHAR2
         ,p_page_size   IN NUMBER DEFAULT 0
         ,p_page_idx    IN NUMBER DEFAULT 0
         ,p_values      IN VARCHAR2
         )
AS
  lv_sql           VARCHAR2(32000);
  lv_where         VARCHAR2(32000) := p_where;
  lv_current_col   VARCHAR2(30);
  lv_col_predicate VARCHAR2(100);
  lv_values        VARCHAR2(32000) := p_values;
  lv_val1          VARCHAR2(1000);
  lv_pos           NUMBER;
  lv_min           NUMBER;
  lv_max           NUMBER;
  lv_cnt           NUMBER :=0;
  lv_data_type     USER_TAB_COLUMNS.DATA_TYPE%TYPE;
  lv_date_format   VARCHAR2(20) := 'YYYYMMDDHH24MISS';
  lv_time_format   VARCHAR2(20) := 'YYYYMMDDHH24MISS';
BEGIN
  WHILE lv_values IS NOT NULL
  LOOP
      lv_pos := INSTR(lv_values,',');
      IF lv_pos>0 THEN
         lv_val1 := SUBSTR(lv_values,1,lv_pos-1);
         lv_values := SUBSTR(lv_values,lv_pos+1);
      ELSE
         lv_val1 := lv_values;
         lv_values := NULL;
      END IF;
      lv_pos := INSTR(lv_val1,':');
      lv_current_col := TRIM(BOTH '"' FROM SUBSTR(lv_val1,1,lv_pos-1));
      BEGIN
         SELECT data_type INTO lv_data_type FROM USER_TAB_COLUMNS WHERE TABLE_NAME = UPPER(p_tablename) AND COLUMN_NAME=UPPER(lv_current_col);
      EXCEPTION
         WHEN NO_DATA_FOUND THEN
              RAISE_APPLICATION_ERROR(-20001,'invalid column name in parameter:'||lv_current_col);
      END;

      lv_cnt := lv_cnt+1;
      DBMS_SESSION.SET_CONTEXT('APP_CTX','$P'||lv_cnt, TRIM(BOTH '"' FROM SUBSTR(lv_val1,lv_pos+1)));
      CASE
      WHEN lv_data_type = 'NUMBER' THEN
           lv_col_predicate := 'TO_NUMBER(SYS_CONTEXT(''APP_CTX'',''$P'||lv_cnt||'''))';
      WHEN lv_data_type ='DATE' THEN
           lv_col_predicate := 'TO_DATE(SYS_CONTEXT(''APP_CTX'',''$P'||lv_cnt||'''),'''||lv_date_format||''')';
      WHEN lv_data_type LIKE '%TIMESTAMP%' THEN
           lv_col_predicate := 'TO_TIMESTAMP(SYS_CONTEXT(''APP_CTX'',''$P'||lv_cnt||'''),'''||lv_time_format||''')';
      ELSE
           lv_col_predicate := 'SYS_CONTEXT(''APP_CTX'',''$P'||lv_cnt||''')';
      END CASE;
      lv_where := REGEXP_REPLACE(lv_where,':'||lv_current_col,lv_col_predicate,1,1,'i');

  END LOOP;
  
  FOR lv_col IN (SELECT * FROM USER_TAB_COLUMNS WHERE TABLE_NAME = UPPER(p_tablename) ORDER BY COLUMN_ID)
  LOOP
      IF lv_col.COLUMN_ID=1 THEN
         lv_sql := 'SELECT ''{''';
      ELSE
         lv_sql := lv_sql||'||'',''';
      END IF;

      CASE
      WHEN lv_col.DATA_TYPE ='DATE' THEN
           lv_sql := lv_sql||   '||''"'||lv_col.column_name||'":"''||TO_CHAR('||lv_col.column_name||','''||lv_date_format||''')||''"''';
      WHEN lv_col.DATA_TYPE LIKE '%TIMESTAMP%' THEN
           lv_sql := lv_sql||   '||''"'||lv_col.column_name||'":"''||TO_CHAR('||lv_col.column_name||','''||lv_time_format||''')||''"''';
      ELSE
           lv_sql := lv_sql||   '||''"'||lv_col.column_name||'":"''||'||lv_col.column_name||'||''"''';
      END CASE;

  END LOOP;
  lv_sql := lv_sql||'||''}'' AS json FROM '||p_tablename||' '||lv_where;
  
  IF p_page_size>0 AND p_page_idx>0 THEN
     lv_min := (p_page_idx-1)*p_page_size+1;
     lv_max := p_page_idx*p_page_size;
     lv_sql :='SELECT json FROM (SELECT json,ROWNUM rn FROM ('||lv_sql||') v WHERE ROWNUM= :MIN_ROW';
     OPEN p_output FOR lv_sql USING lv_max,lv_min;
  ELSE
     OPEN p_output FOR lv_sql;
  END IF;
  
  DBMS_OUTPUT.PUT_LINE(lv_sql);
  RETURN;
END read;

END get_data;
/

这样已经是全部代码,包含了楼主的最底层的DAU_XXXX 那些东西的功能!

客户端怎么调用呢?比楼主简单多了,就CALL一次存储过程,访问游标即可。

我甚至模拟了楼主的测试数据:

CREATE TABLE trn_mmnt (trn_no VARCHAR2(20), stn_no NUMBER, stn_name VARCHAR2(20), trn_lvr VARCHAR2(10), arrive_time VARCHAR2(10), departure_time VARCHAR2(10), days NUMBER, run_minuts NUMBER, stop_minuts NUMBER);

insert into trn_mmnt values ('G7154', 1, '上海虹桥',  '高速', ''     , '12:05', 0, 0,   0   );
insert into trn_mmnt values ('G7154', 2, '昆山南',    '高速', '12:23', '12:24', 0, 18,  1   );
insert into trn_mmnt values ('G7154', 3, '无锡',      '高速', '12:46', '12:48', 0, 41,  2   );
insert into trn_mmnt values ('G7154', 4, '常州',      '高速', '13:01', '13:02', 0, 56,  1   );
insert into trn_mmnt values ('G7154', 5, '丹阳',      '高速', '13:17', '13:18', 0, 72,  1   );
insert into trn_mmnt values ('G7154', 6, '丹徒',      '高速', '13:28', '13:29', 0, 83,  1   );
insert into trn_mmnt values ('G7154', 7, '镇江',      '高速', '13:37', '13:38', 0, 92,  1   );
insert into trn_mmnt values ('G7154', 8, '南京',      '高速', '13:59', ''     , 0, 114, -1  );

到SQL PLUS下,声明一个游标:

VAR VRES REFCURSOR;

EXEC get_data.read(:vres,'trn_mmnt','where trn_no=:trn_no order by stn_no',3,1,'"trn_no":"G7154"');

--- 看输出:
PRINT VRES;

JSON
------------------------------------------------------------------------------------------------------------------------------------------------------
{"TRN_NO":"G7154","STN_NO":"1","STN_NAME":"上海虹桥","TRN_LVR":"高速","ARRIVE_TIME":"","DEPARTURE_TIME":"12:05","DAYS":"0","RUN_MINUTS":"0","STOP_MINUTS":"0"}
{"TRN_NO":"G7154","STN_NO":"2","STN_NAME":"昆山南","TRN_LVR":"高速","ARRIVE_TIME":"12:23","DEPARTURE_TIME":"12:24","DAYS":"0","RUN_MINUTS":"18","STOP_MINUTS":"1"}
{"TRN_NO":"G7154","STN_NO":"3","STN_NAME":"无锡","TRN_LVR":"高速","ARRIVE_TIME":"12:46","DEPARTURE_TIME":"12:48","DAYS":"0","RUN_MINUTS":"41","STOP_MINUTS":"2"}






很好很强大,这是柔性的了。学习一下再说。
执行时间?参考一下,我是担心正则表达式的性能。
分析表结构与生成语句揉在一起了。我是分开的,可以在不同场合用,也可以分析一次生成各种语句,插入啊,修改啊什么的,只是这个例子没这么用。
max和min用绑定变量,这个比我好,我将来可以改。

里边to_char啥的还得写,而且各dtime格式不一定相同(我是模板制定的)。我的那些都自动生成不用写的。

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

使用道具 举报

回复
论坛徽章:
2
蜘蛛蛋
日期:2011-08-31 12:44:35ITPUB十周年纪念徽章
日期:2011-11-01 16:26:29
52#
发表于 2011-8-25 10:23 | 只看该作者
是不是可以这么说:除去取全表数据必须写模板不论是用你的自动生成的sql,或者原本已经是sql不用生成
(原帖上说中对select开头的做了处理没对其他做处理不知道是否有改进)。也就是说别人写sql你写模板而已。
而且在我看来模板异常难写必须指定类型,长度,名称,长度是用来复制数据时定界用的(不知是否正确没看到
具体代码猜测),如果是这样的话,那这个长度异常重要例如:两个长度15的字串而在模板中定义成14,16。
你会发现有时结果是正确的有时是错误的(和你两个字串的数据有关,和你拷贝数据的顺序有关)。
还有就是你的包装现在应该是只针对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
53#
 楼主| 发表于 2011-8-25 10:37 | 只看该作者
原帖由 昨夜袜子 于 2011-8-25 10:23 发表
是不是可以这么说:除去取全表数据必须写模板不论是用你的自动生成的sql,或者原本已经是sql不用生成
(原帖上说中对select开头的做了处理没对其他做处理不知道是否有改进)。也就是说别人写sql你写模板而已。
而且在我看来模板异常难写必须指定类型,长度,名称,长度是用来复制数据时定界用的(不知是否正确没看到
具体代码猜测),如果是这样的话,那这个长度异常重要例如:两个长度15的字串而在模板中定义成14,16。
你会发现有时结果是正确的有时是错误的(和你两个字串的数据有关,和你拷贝数据的顺序有关)。
还有就是你的包装现在应该是只针对oracle并不具备你所说的数据度独立性(或许根本就没有这个需求)。

单表的模板是自动生成的。复合的模板可以用元数据写,见前边。用mktpl生成结构和模板,它们肯定是一致的,不会出现你说的情况。
类型长度等等是因为要映射到C的数据结构。一大堆的离散变量,如何在各个模块间传送?

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

使用道具 举报

回复
论坛徽章:
10
2011新春纪念徽章
日期:2011-02-18 11:43:332014年世界杯参赛球队: 加纳
日期:2014-05-28 11:43:47马上有对象
日期:2014-04-03 14:31:562013年新春福章
日期:2013-02-25 14:51:24蜘蛛蛋
日期:2013-01-30 15:04:41咸鸭蛋
日期:2013-01-21 09:45:36ITPUB 11周年纪念徽章
日期:2012-10-09 18:06:20ITPUB十周年纪念徽章
日期:2011-11-01 16:21:15紫蛋头
日期:2011-06-22 14:32:28双子座
日期:2015-11-06 11:03:23
54#
发表于 2011-8-25 10:40 | 只看该作者
一看标题,就知道是原先话题的 n V n 了,呵呵。
lz的柔性,强调了不更改服务器端“处理过程”而进行“透明数据采集”的目的,这里的强调的是采集,自身负责的数据传输完成,这个“传输层”任务就结束了,这里我同样有和kid的疑虑,作为软件服务商,你的业务逻辑后续处理难道真的都在client端?如果不是,谁来帮你做?如果是,可是诸多弊处。。。。。
kid的处理原则是物尽其用,被tom影响的不浅。

使用道具 举报

回复
论坛徽章:
2
蜘蛛蛋
日期:2011-08-31 12:44:35ITPUB十周年纪念徽章
日期:2011-11-01 16:26:29
55#
发表于 2011-8-25 10:41 | 只看该作者
如果真的需要数据库独立性以及快速开发我觉得可以直接转到ejb,Hibernate等成熟的技术(先声明我不懂ejb,Hibernate)。
抛弃你这个包装器(在我看来这个包装器是复杂、难懂、难维护的个人意见别生气)。那样的话写模板的”sql高手“也不需要了
成本进一步降低。而且你要找一个懂你这个包装器的人我觉得基本上是不可能的,但是要找懂ejb,Hibernate的还是很多的。

使用道具 举报

回复
论坛徽章:
1088
金色在线徽章
日期:2007-04-25 04:02:08金色在线徽章
日期:2007-06-29 04:02:43金色在线徽章
日期:2007-03-11 04:02:02在线时间
日期:2007-04-11 04:01:02在线时间
日期:2007-04-12 04:01:02在线时间
日期:2007-03-07 04:01:022008版在线时间
日期:2010-05-01 00:01:152008版在线时间
日期:2011-05-01 00:01:342008版在线时间
日期:2008-06-03 11:59:43ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30
56#
发表于 2011-8-25 10:44 | 只看该作者
原帖由 昨夜袜子 于 2011-8-25 10:41 发表
如果真的需要数据库独立性以及快速开发我觉得可以直接转到ejb,Hibernate等成熟的技术(先声明我不懂ejb,Hibernate)。
抛弃你这个包装器(在我看来这个包装器是复杂、难懂、难维护的个人意见别生气)。那样的话写模板的”sql高手“也不需要了
成本进一步降低。而且你要找一个懂你这个包装器的人我觉得基本上是不可能的,但是要找懂ejb,Hibernate的还是很多的。

公司内部使用的呗,这东西我们公司有很多
写c++数据库访问,sql层代码根本你不用写的,一个Makefile搞定,我们有专门的内部框架开发的研究院,什么soa,云计算等等,全都有,快速开发嘛
ejb,Hibernate那些东西对我们核心系统是不可能用的,不过有些web系统会用

使用道具 举报

回复
论坛徽章:
1088
金色在线徽章
日期:2007-04-25 04:02:08金色在线徽章
日期:2007-06-29 04:02:43金色在线徽章
日期:2007-03-11 04:02:02在线时间
日期:2007-04-11 04:01:02在线时间
日期:2007-04-12 04:01:02在线时间
日期:2007-03-07 04:01:022008版在线时间
日期:2010-05-01 00:01:152008版在线时间
日期:2011-05-01 00:01:342008版在线时间
日期:2008-06-03 11:59:43ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30
57#
发表于 2011-8-25 10:45 | 只看该作者
模板的东西,java有很多程序的技术,apache一堆搞template的framework
像我们公司从后台数据库访问,接口与代码生成,前台页面组件等等,全都有对应的框架,框架汇集成各种流行技术,所以,拉个刚毕业的搞一星期就可以干了

这样就可以有更多时间去做复杂的业务分析和业务建模了

[ 本帖最后由 dingjun123 于 2011-8-25 10:48 编辑 ]

使用道具 举报

回复
论坛徽章:
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
58#
 楼主| 发表于 2011-8-25 10:48 | 只看该作者
原帖由 dingjun123 于 2011-8-25 10:44 发表

公司内部使用的呗,这东西我们公司有很多
写c++数据库访问,sql层代码根本你不用写的,一个Makefile搞定,我们有专门的内部框架开发的研究院,什么soa,云计算等等,全都有,快速开发嘛
ejb,Hibernate那些东西对我们核心系统是不可能用的,不过有些web系统会用

当然,我们在讨论,各村有各村的高招,都可以拿出来交流。你们的好办法也可以晒晒。让我学习一下。
DAU仿hibernate的,因为是C程序,服务器必须用C的。不会比hibernate难学。我们自动生成模板就是hibernate自动生成.hbm。

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

使用道具 举报

回复
论坛徽章:
2
蜘蛛蛋
日期:2011-08-31 12:44:35ITPUB十周年纪念徽章
日期:2011-11-01 16:26:29
59#
发表于 2011-8-25 10:49 | 只看该作者
可不可以给我解释下为什么核心系统不能用ejb,Hibernate这些东西。

使用道具 举报

回复
论坛徽章:
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
60#
 楼主| 发表于 2011-8-25 10:53 | 只看该作者
原帖由 昨夜袜子 于 2011-8-25 10:49 发表
可不可以给我解释下为什么核心系统不能用ejb,Hibernate这些东西。

目前主要是担心JAVA服务器的稳定性,怕出个奥运门票事件什么的。
还有是性能。
07年公司做几种产品的压力测试,没敢让JAVA参加。

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

使用道具 举报

回复

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

本版积分规则 发表回复

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