使用delphi写了一套程序,目前数据库是SQL 2005,大部分业务功能已经完成,初始设计的时候,并没有考虑双数据库的支持,我们也不熟悉orcale.
客户要求还要支持orcale.请教各位高人,现在要进行双支持,是不是改动量很大?要涉及的地方,那些需要更改?是否有以下方面?1\所有业务功能中:连接数据库的代码
2\存储过程和视图.
3\表结构目前,我们应该怎么做?是不是还不如重新写一套了?

解决方案 »

  1.   

    支持多种数据库对程序的改动量并不大,根据我的经验,只需做好以下工作就可以了。1、统一数据库操作界面。为所有可能用到的数据库操作命令建立统一的调用规范,为每种需要支
       持的数据库实现一次规范就基本可以解决多种数据库并行访问的问题。2、在数据设计中尽可能使用简单的数据类型如字符串和整数,少用时间、BLOB、自增等相对复杂
       的设计。3、对查询语句中的字符串值进行统一的编码和解码,将单引号、双引号、斜线等可能导致问题的字符
       通过编码隐藏起来。4、谨慎对待每种数据库的事务特性,和数据库编码特性(如PQ通常使用UTF-8编码),在实现数据库
       统一操作界面的开发中从根上解决问题。我开发的一套软件最早使用MSSQL7.0,经过以上重整后,目前可以同时支持SQLServer所有版本、
    FB/IB、Access和PostgreSQL,只要有需求,用不了半天就可以实现支持Oracle、MySQL等其他数据库。
      

  2.   

    十分感谢楼上的回复.只是这个软件业务功能已经完毕了,设计初期并没有考虑多数据库的支持.不知道是否还有改进办法?请与我联系:[email protected]  以便请教.
      

  3.   

    我不是沈阳人,也不在沈阳,技术交流请加我的MSN:[email protected]
      

  4.   


    建议:
    1、增加一个数据配置窗口,里面有多种数据连接选择(选择好后保存为TXT或INI或注册表文件等)
    2、数据库设计时应考虑到表名、字段设计相同,这样减少调试出错机会
    3、注意存储的编写格式,因为每种数据库不同
      

  5.   

    個人態度,如果一個內容比較多應用稍復雜點的系統若不用或少用SP or Trigger,簡直難以想像
    針對多數據庫平台而又用基本相同的前端代碼必須在效率上大打折扣真正對於稍大型點的系統,建議采用對應的前端版本控制,即對應ORACLE一套,對應MSSQL一套當然,商業產品通常不太顧及客戶的系統運作效率問題,只是建議客戶買更高檔的服務器也是司空見貫
      

  6.   

    支持两种数据库是没有问题,但需要一些修改.
    因为两种数据库是不同的,比如sqlserver用的是t-sql而oracle用的是pl-sql,所以相关的函数,存储过程,触发器都修改,而且两种数据库在锁机制中也不一样,这样在优化时也需要去测试.
    在一般的商业软件中,都会用不同数据库开发相同的程序,整体架构虽然不变,但内部代码会有很大差别的.像楼主的这种情况,就针对oracle进行修改代码吧,如果不考虑性能,应该很快改完.
      

  7.   

    dgdba用的是繁体字,现在在台湾吗?谈些个人看法:1、应用软件,特别是商用软件通常优先考虑软件的可用性和可靠性,这迫使软件设计必须尽可能
       简单实用,数据表达尽可能简洁明了,从而保证软件在整体上是经过优化处理的。考虑到硬件
       投资通常小于软件优化的成本,如果软件运行速度有些慢,加硬件就行了。2、现代的DBMS基本上都支持存储过程,触发器,更高端的还支持可修改的视图等特性,是否使用
       这些特性必须考虑软件用户群的类型:如果是富有的用户,如银行和证卷,他们的机器通常是
       小型机和巨型机,软件通常走批处理交易的模式,要求必须绝对保证数据的准确性,通常不会
       使用过多的数据库特性,UPDATE、INSERT加上事务就够了;如果是不太富有的用户,如中小型
       企业和机关事业单位,他们的机器普遍是PC服务器,性能不怎么样,系统软件和数据库软件可
       能会使用盗版,Windows居多,这些软件的可靠性有时是无法得到保证的,比如触发器可能失效,
       我始终认为:除非必须,只用最通用最简单的。3、软件的开发版本不是越多越好,针对不同用户、不同数据库系统进行定制是免不了的,但一定
       要控制在允许的范围内。
      

  8.   

    我市菜鸟,但也给个建议:
    看刘艺的《delphi面向对象的编程思想》有感:
    首先是把界面和业务分离:把原来的数据库操作相关在一个DLL中封装成对象,不同数据库封装成不同的类,同时定义一个所有数据库类共同的抽象类作为接口提供给界面使用,再设置一个切换数据库的设置窗口剩下的就按那书的方法修改就成。
      

  9.   

    TO BUDI:
       的確,商業軟件有其特點。或許因為我只求職於工廠,只面對工廠數據應用,所以思維上只針對單一平台應用
    個人態度是比較反感只管完成任務而不講求效率的風格,就像中國人的浪費(像食物、時間等)
       動則買更好的服務器雖然也是簡單處理問題的方法、方案,但個人並不認同   我在廣東東莞,就職於港資,所以用繁體字
      

  10.   

    我也展示一些事例代码,语言是Free Pascal,处理方法和smallBridge的不一样,互相借鉴一下:1、定义数据库基本操作及其提供者信息:
    RLseDB = packed record
      db_size       : cardinal;             {<--record size}
      db_object     : pointer;              {<--database object}
      ...............
      db_setConnStr : TLseDB_setConnStr;    {<--set connection string}
      db_connect    : TLseDB_connect;       {<--connect to database}
      db_disconnect : TLseDB_disconnect;    {<--close database connection}
      db_execSQL    : TLseDB_execSQL;       {<--execute SQL statement}
      db_transact   : TLseDB_transact;      {<--begin transaction}
      db_commit     : TLseDB_commit;        {<--commit transaction}
      db_rollback   : TLseDB_rollback;      {<--rollback transaction}
      ...............
      db_encode     : TLSeDB_encode;        {<--encode SQL statement}
      db_decode     : TLSeDB_decode;        {<--decode string field value}
      db_escape     : TLSeDB_escape;        {<--escape SQL value string}
    end;
    PLseDB = ^RLseDB;RLseDBVendor = packed record
      dv_name: array[0..31] of char; // MSSQL FB/IB POSTGRES ACCESS ODBC ....
      dv_desc: array[0..91] of char;
      dv_create: function:PLseDB;{$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
    end;
    PLseDBVendor = ^RLseDBVendor;
    2、支持PostgreSQL的代码,支持MSSQL, FB/IB, ODBC等其它数据库的代码雷同
    type
      TLiSysDB = class(TPQConnection)
      private
        FDB: PLseDB;
        FError: string;
        FRefcount: integer;
        FConnStr: string;
      public
        constructor Create(AOwner: TComponent);override;
        FQuery: TSQLQuery;
        FTransaction: TSQLTransaction;
        procedure SetConnStr(const ConnectionStr: string);
        procedure HandleError;
        function ExecSQL(const SQL: string): integer;
      end;function pqdb_dv_create: PLseDB;{$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
    var
      sysdb: TLiSysDB;
    begin
      try
        GetMem(Result, sizeof(RLseDB));
        FillChar(Result^, sizeof(RLseDB), 0);
        Result^.db_size       := sizeof(RLseDB);
        sysdb := TLiSysDB.Create(nil);
        sysdb.FTransaction := TSQLTransaction.Create(sysdb);
        sysdb.Transaction := sysdb.FTransaction;
        sysdb.FDB := Result;
        Result^.db_object     := sysdb;
        .........
        Result^.db_setConnStr := pqdb_setConnStr;
        Result^.db_connect    := pqdb_connect;
        Result^.db_disconnect := pqdb_disconnect;
        Result^.db_execSQL    := pqdb_execSQL;
        Result^.db_transact   := pqdb_transact;
        Result^.db_commit     := pqdb_commit;
        Result^.db_rollback   := pqdb_rollback;
        ..........
      except
        Result := nil;
      end;
    end;const
      postgres_vendor: RLseDBVendor = (
        dv_name  :'postgres';
        dv_desc  :'postgreSQL database vendor';
        dv_create: pqdb_dv_create
      );initialization
    begin
      dbv_register(@postgres_vendor); // register postgreSQL vendor
    end;
    3、把PLseDB包装成类:
    type
      TLseDatabase = class
      private
        FDB: PLseDB;
        procedure SetConnectionString(const Value: string);
        ........
      public
        constructor Create(DBRec: PLseDB);
        procedure Connect(const ConnectionString: string);
        procedure Disconnect;
        procedure Transact;
        procedure Commit;
        procedure Rollback;
        function Escape(const S: string): string;
        function Encode(const S: string): string;
        function Decode(const S: string): string;
        function ExecSQL(const SQL: string): integer;
        ........
        property DBRec: PLseDB read FDB;
        property ConnectionString: string read GetConnectionString write SetConnectionString;
        ........
      end;function dbv_provide(const Vendor: string): PLseDB;
    var
      index: integer;
    begin
      for index := 0 to Length(db_vendor_list) - 1 do
        if AnsiSameText(Vendor, db_vendor_list[index].dv_name) then
        begin
          Result := db_vendor_list[index].dv_create();
          Break;
        end;
      Result := nil;
    end;function dbv_database(const Vendor: string): TLseDatabase;
    begin
      Result := TLseDatabase.Create(dbv_provide(Vendor));
    end;
    这样使用TLseDatabase就可以操作任意类型的数据库了。
      

  11.   

    删的太多,有一个错误,抱歉:
    function dbv_provide(const Vendor: string): PLseDB;
    var
      index: integer;
    begin
      for index := 0 to Length(db_vendor_list) - 1 do
        if AnsiSameText(Vendor, db_vendor_list[index].dv_name) then
        begin
          Result := db_vendor_list[index].dv_create(); 
          Exit;
        end;
      Result := nil;
    end;