使用delphi写了一套程序,目前数据库是SQL 2005,大部分业务功能已经完成,初始设计的时候,并没有考虑双数据库的支持,我们也不熟悉orcale.
客户要求还要支持orcale.请教各位高人,现在要进行双支持,是不是改动量很大?要涉及的地方,那些需要更改?是否有以下方面?1\所有业务功能中:连接数据库的代码
2\存储过程和视图.
3\表结构目前,我们应该怎么做?是不是还不如重新写一套了?
客户要求还要支持orcale.请教各位高人,现在要进行双支持,是不是改动量很大?要涉及的地方,那些需要更改?是否有以下方面?1\所有业务功能中:连接数据库的代码
2\存储过程和视图.
3\表结构目前,我们应该怎么做?是不是还不如重新写一套了?
持的数据库实现一次规范就基本可以解决多种数据库并行访问的问题。2、在数据设计中尽可能使用简单的数据类型如字符串和整数,少用时间、BLOB、自增等相对复杂
的设计。3、对查询语句中的字符串值进行统一的编码和解码,将单引号、双引号、斜线等可能导致问题的字符
通过编码隐藏起来。4、谨慎对待每种数据库的事务特性,和数据库编码特性(如PQ通常使用UTF-8编码),在实现数据库
统一操作界面的开发中从根上解决问题。我开发的一套软件最早使用MSSQL7.0,经过以上重整后,目前可以同时支持SQLServer所有版本、
FB/IB、Access和PostgreSQL,只要有需求,用不了半天就可以实现支持Oracle、MySQL等其他数据库。
建议:
1、增加一个数据配置窗口,里面有多种数据连接选择(选择好后保存为TXT或INI或注册表文件等)
2、数据库设计时应考虑到表名、字段设计相同,这样减少调试出错机会
3、注意存储的编写格式,因为每种数据库不同
針對多數據庫平台而又用基本相同的前端代碼必須在效率上大打折扣真正對於稍大型點的系統,建議采用對應的前端版本控制,即對應ORACLE一套,對應MSSQL一套當然,商業產品通常不太顧及客戶的系統運作效率問題,只是建議客戶買更高檔的服務器也是司空見貫
因为两种数据库是不同的,比如sqlserver用的是t-sql而oracle用的是pl-sql,所以相关的函数,存储过程,触发器都修改,而且两种数据库在锁机制中也不一样,这样在优化时也需要去测试.
在一般的商业软件中,都会用不同数据库开发相同的程序,整体架构虽然不变,但内部代码会有很大差别的.像楼主的这种情况,就针对oracle进行修改代码吧,如果不考虑性能,应该很快改完.
简单实用,数据表达尽可能简洁明了,从而保证软件在整体上是经过优化处理的。考虑到硬件
投资通常小于软件优化的成本,如果软件运行速度有些慢,加硬件就行了。2、现代的DBMS基本上都支持存储过程,触发器,更高端的还支持可修改的视图等特性,是否使用
这些特性必须考虑软件用户群的类型:如果是富有的用户,如银行和证卷,他们的机器通常是
小型机和巨型机,软件通常走批处理交易的模式,要求必须绝对保证数据的准确性,通常不会
使用过多的数据库特性,UPDATE、INSERT加上事务就够了;如果是不太富有的用户,如中小型
企业和机关事业单位,他们的机器普遍是PC服务器,性能不怎么样,系统软件和数据库软件可
能会使用盗版,Windows居多,这些软件的可靠性有时是无法得到保证的,比如触发器可能失效,
我始终认为:除非必须,只用最通用最简单的。3、软件的开发版本不是越多越好,针对不同用户、不同数据库系统进行定制是免不了的,但一定
要控制在允许的范围内。
看刘艺的《delphi面向对象的编程思想》有感:
首先是把界面和业务分离:把原来的数据库操作相关在一个DLL中封装成对象,不同数据库封装成不同的类,同时定义一个所有数据库类共同的抽象类作为接口提供给界面使用,再设置一个切换数据库的设置窗口剩下的就按那书的方法修改就成。
的確,商業軟件有其特點。或許因為我只求職於工廠,只面對工廠數據應用,所以思維上只針對單一平台應用
個人態度是比較反感只管完成任務而不講求效率的風格,就像中國人的浪費(像食物、時間等)
動則買更好的服務器雖然也是簡單處理問題的方法、方案,但個人並不認同 我在廣東東莞,就職於港資,所以用繁體字
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就可以操作任意类型的数据库了。
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;