#
对UUID几乎没有了解,google了一下,才知道是128位整数(16字节)的全局唯一标识符(Universally Unique Identifier)。
UUID是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。通常平台会提供生成UUID的API。UUID按照开放软件基金会(OSF)制定的标准计算,用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字。由以下几部分的组合:当前日期和时间(UUID的第一个部分与时间有关,如果你在生成一个UUID之后,过几秒又生成一个UUID,则第一个部分不同,其余相同),时钟序列,全局唯一的IEEE机器识别号(如果有网卡,从网卡获得,没有网卡以其他方式获得),UUID的唯一缺陷在于生成的结果串会比较长。关于UUID这个标准使用最普遍的是微软的GUID(Globals Unique Identifiers)。
在ColdFusion中可以用CreateUUID()函数很简单的生成UUID,其格式为:xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx(8-4-4-16),其中每个 x 是 0-9 或 a-f 范围内的一个十六进制的数字。而标准的UUID格式为:xxxxxxxx-xxxx-xxxx-xxxxxx-xxxxxxxxxx (8-4-4-4-12)
,可以从
cflib 下载
CreateGUID() UDF进行转换。
使用UUID的好处在分布式的软件系统中(比如:DCE/RPC, COM+,CORBA)就能体现出来,它能保证每个节点所生成的标识都不会重复,并且随着WEB服务等整合技术的发展,UUID的优势将更加明显。
关于UUID的更多信息可以多
google 一下。
|
|
|
Oracle9i 2.0.4在Red Hat Enterprise Linux AS 3上的安装
|
|
|
Oracle9i 2.0.4在Red Hat Enterprise Linux AS 3上的安装 (我测试了两遍都OK) 1、确认安装了以下软件包 [oracle@Gledeson oracle]$ rpm -qa | grep openmotif openmotif21-2.1.30-8 openmotif-devel-2.2.3-3.RHEL3 openmotif-2.2.3-3.RHEL3 [oracle@Gledeson oracle]$ rpm -qa |grep setarch setarch-1.3-1 [oracle@Gledeson oracle]$ rpm -qa|grep compat compat-gcc-c++-7.3-2.96.128 compat-glibc-7.x-2.2.4.32.6 compat-slang-1.4.5-5 compat-pwdb-0.62-3 compat-libstdc++-devel-7.3-2.96.128 compat-db-4.0.14-5 compat-gcc-7.3-2.96.128 compat-libstdc++-7.3-2.96.128
2、建立Oracle帐号 groupadd dba groupadd oinstall useradd -c "Oracle software owner" -g oinstall -G dba oracle passwd oracle 3、建立文件目录 su root mkdir /u01 mkdir /u01/oracle mkdir /u01/oracle/product mkdir /u01/oracle/product/9.2.0 chown -R oracle.oinstall /u01/oracle mkdir /var/opt/oracle chown oracle.dba /var/opt/oracle chmod 755 /var/opt/oracle 4、设置环境变量 用Oracle帐号执行下列命令:(或直接copy到.bash_profile文件中) # Set the LD_ASSUME_KERNEL environment variable only for Red Hat 9, # RHEL AS 3, and RHEL AS 4 !! # Use the "Linuxthreads with floating stacks" implementation instead of NPTL: #export LD_ASSUME_KERNEL=2.4.1 # for RH 9 and RHEL AS 3 #export LD_ASSUME_KERNEL=2.4.19 # for RHEL AS 4 export LD_ASSUME_KERNEL=2.4.1 export ORACLE_BASE=/u01/oracle export ORACLE_HOME=$ORACLE_BASE/product/9.2.0 export ORACLE_SID=ORADB01 export ORACLE_TERM=xterm export ORA_NLS33=$ORACLE_HOME/ocommon/nls/admin/data LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib export LD_LIBRARY_PATH # Set shell search paths export PATH=$PATH:$ORACLE_HOME/bin 保存后退出. 执行: source .bash_profile 然后。退出登录,再次进入,这时候oracle的环境就已经生效了 5、设置内核参数 su root 修改 /etc/sysctl.conf 这个文件,加入以下的语句: kernel.shmmax = 2147483648 kernel.shmmni = 4096 kernel.shmall = 2097152 kernel.sem = 250 32000 100 128 fs.file-max = 65536 net.ipv4.ip_local_port_range = 1024 65000 参数说明: sem 4个参数依次为SEMMSL(每个用户拥有信号量最大数); SEMMNS(系统信号量最大数); SEMOPM(每次semopm系统调用操作数); SEMMNI(系统辛苦量集数最大数). Shmmax 最大共享内存2GB 物理内存如果小的话可以设置成 536870912. Shmmni 最小共享内存 4096KB. Shmall 所有内存大小. 6、安装补丁 (ORACLE9i 9204版,只需在运行runInstall前打p3006854_9204_LINUX.zip 补丁即可, 其他补丁不用再打) 安装补丁前,却换到root用户的控制台,打补丁前执行以下语句: su root mv /usr/bin/gcc /usr/bin/gcc323 ln -s /usr/bin/gcc296 /usr/bin/gcc mv /usr/bin/g++296 /usr/bin/g++ ln -s /usr/bin/g++ /usr/bin/g++296 [root@localhost /]# sh rhel3_pre_install.sh Applying patch... Ensuring permissions are correctly set... Done. Patch successfully applied 7、解压文件 zcat ship_9204_linux_disk1.cpio | cpio -idmv zcat ship_9204_linux_disk2.cpio | cpio -idmv zcat ship_9204_linux_disk3.cpio | cpio -idmv 这时生成三个目录:Disk1、Disk2、Disk3 8、cd到Disk1中 cd /Disk1 ./runInstall.sh
| | |
对String的深刻理解
刚开始玩java,对其String类,使用有些感触;
1、"abc"与new String("abc");
经常会问到的面试题:String s = new String("abc");创建了几个String Object?【如这里创建了多少对象? 和一道小小的面试题 】
这个问题比较简单,涉及的知识点包括:
引用变量与对象的区别;
字符串文字"abc"是一个String对象;
文字池[pool of literal strings]和堆[heap]中的字符串对象。
一、引用变量与对象:除了一些早期的Java书籍和现在的垃圾书籍,人们都可以从中比较清楚地学习到两者的区别。A aa;语句声明一个类A的引用变量aa[我常常称之为句柄],而对象一般通过new创建。所以题目中s仅仅是一个引用变量,它不是对象。[ref 句柄、引用与对象]
二、Java中所有的字符串文字[字符串常量]都是一个String的对象。有人[特别是C程序员]在一些场合喜欢把字符串"当作/看成"字符数组,这也没有办法,因为字符串与字符数组存在一些内在的联系。事实上,它与字符数组是两种完全不同的对象。
System.out.println("Hello".length());
char[] cc={'H','i'};
System.out.println(cc.length);
三、字符串对象的创建:由于字符串对象的大量使用[它是一个对象,一般而言对象总是在heap分配内存],Java中为了节省内存空间和运行时间[如比较字符串时,==比equals()快],在编译阶段就把所有的字符串文字放到一个文字池[pool of literal strings]中,而运行时文字池成为常量池的一部分。文字池的好处,就是该池中所有相同的字符串常量被合并,只占用一个空间。我们知道,对两个引用变量,使用==判断它们的值[引用]是否相等,即指向同一个对象:
String s1 = "abc" ;
String s2 = "abc" ;
if( s1 == s2 )
System.out.println("s1,s2 refer to the same object");
else System.out.println("trouble");
这里的输出显示,两个字符串文字保存为一个对象。就是说,上面的代码只在pool中创建了一个String对象。
现在看String s = new String("abc");语句,这里"abc"本身就是pool中的一个对象,而在运行时执行new String()时,将pool中的对象复制一份放到heap中,并且把heap中的这个对象的引用交给s持有。ok,这条语句就创建了2个String对象。
String s1 = new String("abc") ;
String s2 = new String("abc") ;
if( s1 == s2 ){ //不会执行的语句}
这时用==判断就可知,虽然两个对象的"内容"相同[equals()判断],但两个引用变量所持有的引用不同,
BTW:上面的代码创建了几个String Object? [三个,pool中一个,heap中2个。]
[Java2 认证考试学习指南 (第4版)( 英文版)p197-199有图解。]
2、字符串的+运算和字符串转换
字符串转换和串接是很基础的内容,因此我以为这个问题简直就是送分题。事实上,我自己就答错了。
String str = new String("jf"); // jf是接分
str = 1+2+str+3+4;
一共创建了多少String的对象?[我开始的答案:5个。jf、new、3jf、3jf3、3jf34]
首先看JLS的有关论述:
一、字符串转换的环境[JLS 5.4 String Conversion]
字符串转换环境仅仅指使用双元的+运算符的情况,其中一个操作数是一个String对象。在这一特定情形下,另一操作数转换成String,表达式的结果是这两个String的串接。
二、串接运算符[JLS 15.18.1 String Concatenation Operator + ]
如果一个操作数/表达式是String类型,则另一个操作数在运行时转换成一个String对象,并两者串接。此时,任何类型都可以转换成String。[这里,我漏掉了"3"和"4"]
如果是基本数据类型,则如同首先转换成其包装类对象,如int x视为转换成Integer(x)。
现在就全部统一到引用类型向String的转换了。这种转换如同[as if]调用该对象的无参数toString方法。[如果是null则转换成"null"]。因为toString方法在Object中定义,故所有的类都有该方法,而且Boolean, Character, Integer, Long, Float, Double, and String改写了该方法。
关于+是串接还是加法,由操作数决定。1+2+str+3+4 就很容易知道是"3jf34"。[BTW :在JLS的15.18.1.3中举的一个jocular little example,真的很无趣。]
下面的例子测试了改写toString方法的情况.。
class A{
int i = 10;
public static void main(String []args){
String str = new String("jf");
str += new A();
System.out.print(str);
}
public String toString(){
return " a.i ="+i+"\n";
}
}
三、字符串转换的优化
按照上述说法,str = 1+2+str+3+4;语句似乎应该就应该生成5个String对象:
1+2 =3,then 3→Integer(3)→"3" in pool? [假设如此]
"3"+str(in heap) = "3jf" (in heap)
"3jf" +3 ,first 3→Integer(3)→"3" in pool? [则不创建] then "3jf3"
"3jf3"+4 create "4" in pool
then "3jf34"
这里我并不清楚3、4转换成字符串后是否在池中,所以上述结果仍然是猜测。
为了减少创建中间过渡性的字符串对象,提高反复进行串接运算时的性能,a Java compiler可以使用StringBuffer或者类似的技术,或者把转换与串接合并成一步。例如:对于 a + b + c ,Java编译器就可以将它视为[as if]
new StringBuffer().append(a).append(b).append(c).toString();
注意,对于基本类型和引用类型,在append(a)过程中仍然要先将参数转换,从这个观点看,str = 1+2+str+3+4;创建的字符串可能是"3"、"4"和"3jf34"[以及一个StringBuffer对象]。
现在我仍然不知道怎么回答str = 1+2+str+3+4;创建了多少String的对象,。或许,这个问题不需要过于研究,至少SCJP不会考它。
3、这又不同:str = "3"+"jf"+"3"+"4";
如果是一个完全由字符串文字组成的表达式,则在编译时,已经被优化而不会在运行时创建中间字符串。测试代码如下:
String str1 ="3jf34";
String str2 ="3"+"jf"+"3"+"4";
if(str1 == str2) {
System.out.println("str1 == str2");
}else {
System.out.println("think again");
}
if(str2.equals(str1))
System.out.println("yet str2.equals(str1)");
可见,str1与str2指向同一个对象,这个对象在pool中。所有遵循Java Language Spec的编译器都必须在编译时对constant expressions 进行简化。JLS规定:Strings computed by constant expressions (ý15.28) are computed at compile time and then treated as if they were literals.
对于String str2 ="3"+"jf"+"3"+"4";我们说仅仅创建一个对象。注意,“创建多少对象”的讨论是说运行时创建多少对象。
BTW:编译时优化
String x = "aaa " + "bbb ";
if (false) {
x = x + "ccc ";
}
x += "ddd ";
等价于:
String x = "aaa bbb ";
x = x + "ddd ";
4、不变类
String对象是不可改变的(immutable)。有人对str = 1+2+str+3+4;语句提出疑问,怎么str的内容可以改变?其实仍然是因为不清楚:引用变量与对象的区别。str仅仅是引用变量,它的值——它持有的引用可以改变。你不停地创建新对象,我就不断地改变指向。[参考TIJ的Read-only classes。]
不变类的关键是,对于对象的所有操作都不可能改变原来的对象[只要需要,就返回一个改变了的新对象]。这就保证了对象不可改变。为什么要将一个类设计成不变类?有一个OOD设计的原则:Law of Demeter。其广义解读是:
使用不变类。只要有可能,类应当设计为不变类。
1、tomcat下配置虚拟目录
打开TOMCAT文件下的conf\server.xml文件 ,查找到<ContextManager>标签,并在该标签的结束标签</ContextManager>前面加上:
<Context path="虚拟目录" docBase="硬盘目录" debug="0" reloadable="true" crossContext="true"/>
其中path的值是虚拟目录,docbase的值是你的硬盘的的目录的绝对路径。
如找不到<ContextManager>元素,可以找
<Host name="localhost" debug="0" appBase="webapps"
unpackWARs="true" autoDeploy="true"
xmlValidation="false" xmlNamespaceAware="false">
然后添加<Context path="虚拟目录" docBase="硬盘目录" debug="0" reloadable="true" crossContext="true"/>
2、禁止tomcat目录浏览,将listings设为false
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>
org.apache.catalina.servlets.DefaultServlet
</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
3、设置友好错误页面,配置web.xml
<error-page>
<error-code>404</error-code>
<location>/error.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error.jsp</location>
</error-page>
4、在IE中直接打开其他扩展名的文件
为了让能在IE浏览器中自动打开其他扩展文件名的文件的设置:
需要在WEB.XML中进行如下的设置:
在WEB.XML中添加<mime-mapping>,其中:
<extension>: 文件的扩展名
<mime-type>: 除了该类型文件的可执行文件,同WINDOW注册表中的 /HKEY_CLASSES_ROOT下该类文件的Content Type 的值一样.
如能在IE中自动打开DOC,XLS,PDF文件的配置如下:
<?xml version="1.0" ?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 1.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
<web-app>
<mime-mapping>
<extension>doc</extension>
<mime-type>application/msword</mime-type>
</mime-mapping>
<mime-mapping>
<extension>xls</extension>
<mime-type>application/msexcel</mime-type>
</mime-mapping>
<mime-mapping>
<extension>pdf</extension>
<mime-type>application/pdf</mime-type>
</mime-mapping>
</web-app>
- 确保运行 SQL Server 的服务器上的 Oracle 客户端软件已达到提供程序所要求的级别。用于 Oracle 的 Microsoft OLE DB 提供程序要求 Oracle 客户端软件支持文件的版本为 7.3.3.4.0 或更高版本,并且 SQL*Net 的版本为 2.3.3.0.4。
- 在运行 SQL Server 的服务器上创建指向 Oracle 数据库实例的 SQL*Net 别名。有关更多信息,请参见 Oracle 文档。
- 执行 sp_addlinkedserver 创建链接服务器,指定 MSDAORA 为 provider_name,指定用于 Oracle 数据库实例的 SQL*Net 别名为 data_ source。
以下示例假设已将一个 SQL*Net 别名定义为 OracleDB。
sp_addlinkedserver 'OrclDB', 'Oracle', 'MSDAORA', 'OracleDB'
- 使用 sp_addlinkedsrvlogin 创建从 SQL Server 登录到 Oracle 登录的登录映射。
以下示例通过 Oracle 登录名 OrclUsr 和密码 OrclPwd 将 SQL Server 登录 Joe 映射到步骤 3 中定义的链接服务器:
sp_addlinkedsrvlogin 'OrclDB', false, 'Joe', 'OrclUsr', 'OrclPwd'
每个 Oracle 数据库实例仅有一个名称为空的目录。Oracle 链接服务器中的表必须使用四部分名称格式 OracleLinkedServerName..OwnerUserName.TableName 进行引用。例如,以下 SELECT 语句引用 Oracle 用户 MARY 在 OrclDB 链接服务器映射的服务器上所拥有的表 SALES。
SELECT *
FROM OrclDB..MARY.SALES
注意需要 修改 注册表 :对于win2k/oracle 8i ,修改的内容为:
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSDTC\MTxOCI]
"OracleXaLib"="oraclient8.dll"
"OracleSqlLib"="orasql8.dll"
"OracleOciLib"="oci.dll"
其它事项:启动mstdc服务
说明:
建议在刚安装完的时候进行修改,对已经投产的系统,风险太大!
步骤如下:
1. Make sure the parallel_server parameter in INIT.ORA is set to false
or it is not set at all.
2. Execute the following commands in Server Manager (svrmgrl):
SVRMGR> SHUTDOWN IMMEDIATE; -- or NORMAL
SVRMGR> STARTUP MOUNT;
SVRMGR> ALTER SYSTEM ENABLE RESTRICTED SESSION;
SVRMGR> ALTER SYSTEM SET JOB_QUEUE_PROCESSES=0;
SVRMGR> ALTER SYSTEM SET AQ_TM_PROCESSES=0;
SVRMGR> ALTER DATABASE OPEN;
SVRMGR> ALTER DATABASE [NATIONAL] CHARACTER SET INTERNAL_USE ;
SVRMGR> SHUTDOWN IMMEDIATE; -- OR NORMAL
SVRMGR> STARTUP RESTRICT;
3. Restore the parallel_server parameter in INIT.ORA, if necessary.
4. Execute the following commands in Server Manager:
SVRMGR> SHUTDOWN IMMEDIATE; -- OR NORMAL
SVRMGR> STARTUP;
如果没有登陆,首先执行
SVRMGR> connect internal;
软件环境:
1、Windows 2000+ORACLE
2、ORACLE安装路径为:C:\ORACLE
实现方法:
1、 开始->设置->控制面板->管理工具->服务停止所有Oracle服务。
2、 开始->程序->Oracle - OraHome81->Oracle Installation Products->Universal Installer卸装所有Oracle产品,但Universal Installer本身不能被删除
5、 运行regedit,选择HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE,按del键删除这个入口。
6、 运行regedit,选择HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services,滚动这个列表,删除所有Oracle入口。
7、 运行refedit,HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application,
删除所有Oracle入口。
8、 开始->设置->控制面板->系统->高级->环境变量删除环境变量CLASSPATH和PATH中有关Oracle的设定
9、 从桌面上、STARTUP(启动)组、程序菜单中,删除所有有关Oracle的组和图标
10、 删除\Program Files\Oracle目录
11、 重新启动计算机,重起后才能完全删除Oracle所在目录
12、 删除与Oracle有关的文件,选择Oracle所在的缺省目录C:\Oracle,删除这个入口目录及所有子目录,并从C:\WINNT下删除以下文件ORACLE.INI、oradim73.INI、oradim80.INI、oraodbc.ini等等。
13、 WIN.INI文件中若有[ORACLE]的标记段,删除该段
14、 如有必要,删除所有Oracle相关的ODBC的DSN
15、 到事件查看器中,删除Oracle相关的日志
说明:
如果有个别DLL文件无法删除的情况,则不用理会,重新启动,开始新的安装,安装时,选择一个新的目录,则,安装完毕并重新启动后,老的目录及文件就可以删除掉了。
pro*c and vc++ error
From the oracle metalink -
Problem Description
-------------------
You are trying to compile a precompiled Pro*C application.
You are using Microsoft Visual C++ 6.0. At compile time,
you get the error message:
C2079: 'SQLSTM" uses undefined struct 'SQLEXD'
Solution Description
--------------------
In Visual C++, under Project -> Settings -> Precompiled Headers,
set this to "Automatic Use of Precompiled Headers", with the "Through
Header"
option left blank.
HTH.,
Ora600
"Glen"
wrote in message
news:69867261.0110312021.3ba2f3ee@posting.google.com...
> Hi,
>
> I have precompiled some pro*c code which worked fine and outputted a
> c++ file which is included in my project. I have included the
> orasql8.lib and when I try to compile the project receive the
> following error:
>
> error C2079: 'sqlstm' uses undefined struct 'sqlexd'
>
> I don't understand why, the following code appears before where the
> error is encountered.
>
> static struct sqlexd {
> unsigned int sqlvsn;
> unsigned int arrsiz;
> unsigned int iters;
> unsigned int offset;
> unsigned short selerr;
> unsigned short sqlety;
> unsigned int occurs;
> const short *cud;
> unsigned char *sqlest;
> const char *stmt;
> sqladts *sqladtp;
> sqltdss *sqltdsp;
> void **sqphsv;
> unsigned int *sqphsl;
> int *sqphss;
> void **sqpind;
> int *sqpins;
> unsigned int *sqparm;
> unsigned int **sqparc;
> unsigned short *sqpadto;
> unsigned short *sqptdso;
> void *sqhstv[4];
> unsigned int sqhstl[4];
> int sqhsts[4];
> void *sqindv[4];
> int sqinds[4];
> unsigned int sqharm[4];
> unsigned int *sqharc[4];
> unsigned short sqadto[4];
> unsigned short sqtdso[4];
> } sqlstm = {10,4};
>
> If anyone has any ideas i would be most appreciative.
>
> Cheers
> Glen
用VC开发基于ORACLE数据库方法 |
作者:黎杰 麦中凡 更新时间: 2005-05-07 |
|
|
1. 引言 ORACLE 公司自1979 年推出基于SQL 标准的关系数据库产品到1997 年版本8 的推出,ORACLE 数据库以其支持大数据库、多用户的高性能事务处理,对业界各项工业标准的支持,完整的安全和完整性控制,支持分布式数据库和分布处理,具有可移植性、可兼容性和可连接性等突出优点倍受用户喜爱,根据IDG1992 年全球UNIX 数据库的市场报告,ORACLE 占市场销售量的50%。而在客户端的开发工具方面,Visual C++ 也因其强大的功能和高度的灵活性等特点深受广大程序员的喜爱,因此本文旨在介绍使用Visual C++ 开发基于ORACLE 数据库应用程序的两种方法。
2. 使用PRO*C 开发数据库应用
2.1 PRO*C 工作原理
PRO 系列是ORACLE 公司提供的在第三代高级程序设计语言中嵌入SQL 语句来访问数据库的一套预编译程序,包括PRO*Ada、PRO*C、PRO*COBOL、PRO*Fortran、PRO*Pascal 和PRO*PL/I 六种。程序员用相应的高级语言编写嵌入SQL 语句的PRO 源程序(若用C 语言则称为PRO*C 源程序)后运行相应的预编译程序,把嵌入的SQL 语句转换为标准的ORACLE 调用并生成目标源程序,即纯高级语言格式的源程序,然后就可以将这些源程序加入用户的程序中调用,其处理过程如下图。
ORACLE 预编译程序提供如下功能:
⑴能用六种通用的高级程序设计语言中的任何一种编写应用程序。
⑵遵循ANSI 标准,在高级语言中嵌入SQL 语句。
⑶可采用动态SQL 方法,让程序在运行时接受或构造一个有效的SQL 语句。
⑷实现ORACLE 内部数据类型和高级语言数据类型之间的自动转换。
⑸可通过在应用程序中嵌入PL/SQL 事物处理块来改进性能。
⑹能在程序行和命令行上指定所需要的预编译可选项,并可在预编译的过程中改变它们的值。
⑺能全面检查嵌入的SQL 数据操纵语句和PL/SQL 块的文法和语义。
⑻可用SQL*Net 并行存取多个地点的ORACLE 数据库。
⑼可把数组作为输入和输出程序变量使用。
⑽能对应用程序中的代码段进行条件预编译。
⑾提供了较强的异常处理功能。
由此可见,通过预编译程序与其它高级语言的结合,既可以利用SQL 强有力的功能和灵活性为数据库应用系统的开发提供强有力的手段,又可以充分利用高级语言自身在系统开发方面的优势,从而提供一个完备的基于ORACLE 数据库应用程序的开发解决方案。
2.2 在VC 中使用PRO*C
每个PRO*C 源文件一般由程序头和程序体两部分组成。程序头包含宿主变量(SQL 语句中所包含的变量)说明、通讯区定义和C 外部表示符的说明等。程序体一般是由若干函数组成,这些函数内含有SQL 语句(以EXEC SQL 起头的语句)。
PRO*C 支持的数据类型包括VARCHAR2( 变长字符串)、NUMBER( 二进制数)、INTGER( 有符号整数)、FLOAT( 浮点数)、STRING( 以NULL 结尾的字符串)、VARNUM( 变长二进制数)、LONG( 变长字符串)、VARCHAR( 变长字符串)、ROWID( 二进制值)、DATE( 定长日期/ 时间值)、VARRAW( 变长二进制数据)、RAW( 定长二进制数据) 、LONGRAW( 变长二进制数据)、UNSIGNED( 无符号整数)、LONGVARCHAR( 变长字符串)、LONGVARRAW( 变长二进制数据)、CHAR( 定长字符串)、CHARZ(C 中定长以NULL 结尾的字符串)、MLSLABEL( 变长二进制数据)。
在PRO*C 中不能使用'l' 或'u' 作词尾或'0x' 作词头修饰常量;在SQL 语句中使用单引号来定义字符串,用双引号来定义特殊的或小写字符的标识符( 如表名等);SQL 语句中不允许使用C 中的寻址、间接、位逻辑、复合赋值、?=、-、++、%、<<、>> 操作符并且用NOT、AND、OR、= 代替!、&&、||、==。
下面的程序是一个联结数据库的PRO*C 源程序例子。
#include < sqlca.h > //声明SQL通讯区 #include < string.h > #include < afxwin.h > EXEC SQL BEGIN DECLARE SECTION; VARCHAR username[20]; //声明宿主变量 VARCHAR password[20]; VARCHAR dbname[20]; EXEC SQL END DECLARE SECTION; void db_connect() { strcpy((char *)username.arr,"SCOTT"); username.len = strlen((char *)username.arr); strcpy((char *)password.arr,"TIGER"); password.len = strlen((char *)password.arr); strcpy((char *)dbname.arr,"SUNDB"); dbname.len = strlen((char *)dbname.arr); EXEC SQL WHENEVER SQLERROR STOP; //隐式异常处理 EXEC SQL CONNECT :username IDENTIFIED BY :password USING :dbname; /*if (sqlca.sqlcode != 0) //显式异常处理 { AfxMessageBox("\n与Oracle数据库连接失败!"); return; }*/ }
在VC 中使用PRO*C 时,先用PRO*C 编写所需的操作数据库的子程序,再运行PRO*C 预编译程序把PRO*C 源程序转成相应的CPP 源程序,将该程序插入到用户工程文件中并在需要对插入函数进行调用的模块中说明函数,然后就可以在此模块中调用所需的函数。
3. 使用ODBC 中间件访问数据库
3.1 ODBC 工作原理
DBC 是Open Database Connect 即开放数据库互连的简称,它是由Microsoft 公司于1991 年提出的一个用于访问数据库的统一界面标准,是应用程序和数据库系统之间的中间件。它通过使用相应应用平台上和所需数据库对应的驱动程序与应用程序的交互来实现对数据库的操作,避免了在应用程序中直接调用与数据库相关的操作,从而提供了数据库的独立性。
ODBC 主要由驱动程序和驱动程序管理器组成。驱动程序是一个用以支持ODBC 函数调用的模块(在WIN95 下通常是一个DLL),每个驱动程序对应于相应的数据库,当应用程序从基于一个数据库系统移植到另一个时,只需更改应用程序中由ODBC 管理程序设定的与相应数据库系统对应的别名即可。驱动程序管理器(包含在ODBC32.DLL 中)可链接到所有ODBC 应用程序中,它负责管理应用程序中ODBC 函数与DLL 中函数的绑定。
ODBC 使用层次的方法来管理数据库,在数据库通信结构的每一层,对可能出现依赖数据库产品自身特性的地方,ODBC 都引入一个公共接口以解决潜在的不一致性,从而很好地解决了基于数据库系统应用程序的相对独立性,这也是ODBC 一经推出就获得巨大成功的重要原因之一。
从结构上分,ODBC 分为单束式和多束式两类。
⑴单束式驱动程序
单束式驱动程序介于应用程序和数据库之间,像中介驱动程序一样数据提供一个统一的数据访问方式。
当用户进行数据库操作时,应用程序传递一个ODBC 函数调用给ODBC 驱动程序管理器,由ODBC API 判断该调用是由它直接处理并将结果返回还是送交驱动程序执行并将结果返回。
由上可见,单束式驱动程序本身是一个数据库引擎,由它直接可完成对数据库的操作,尽管该数据库可能位于网络的任何地方。
⑵多束式驱动程序
多束式驱动程序负责在数据库引擎和客户应用程序之间传送命令和数据,它本身并不执行数据处理操作而用于远程操作的网络通信协议的一个界面。
前端应用程序提出对数据库处理的请求,该请求转给ODBC 驱动程序管理器,驱动程序管理器依据请求的情况,就地完成或传给多束驱动程序,多束式驱动程序将请求翻译为特定厂家的数据库通信接口(如Oracle 的SQLNet)所能理解的形式并交于接口去处理,接口把请求经网络传送给服务器上的数据引擎,服务器处理完后把结果发回给数据库通信接口,数据库接口将结果传给多束式ODBC 驱动程序,再由驱动程序将结果传给应用程序。
3.2 在VC 中使用ODBC
Visual C++ 中提供了CDatabase、CRecordset、CRecordView、CDBException 和CFieldExchange 五个类,这些类封装了ODBC SDK 函数,从而使用户可以无需了解SDK 函数就可以很方便地操作支持ODBC 的数据库。
CDatabase 类:封装了与数据库建立连接,控制事务的提交和回滚及执行SQL 语句的方法。
CRecordset 类:封装了大部分操纵数据库的方法,包括浏览、修改记录,控制游标移动,排序等操作。
CRecordView 类:提供了与recordset 对象相连接的视,可以建立视中的控件与数据库数据的对应,同时支持移动游标,修改记录等操作。
CDBException 类:提供了对数据库操作的异常处理,可以获得操作异常的相关返回代码。
CFieldExchange 类:提供了用户变量与数据库字段之间的数据交换,如果不需要使用自定义类型,你将不用直接调用该类的函数,MFC Wizard 将自动为程序员建立连接。
4. 两种方法的比较
综上所述,使用这两种方法在Visual C++ 中都可以很方便地开发出基于ORACLE 数据库的应用程序,同时,这两种方法又各有其优缺点。ODBC 由于有MFC 强大的类库支持而使得编程实现非常方便,同时可移植性也很强,在异构的数据库之间移植也只需更改很少的一部分程序,但是,由ODBC 的实现机制我们可以看到,与PRO*C 相比,应用程序需要经过ODBC 驱动程序管理器和ODBC 驱动程序两层才能和数据库通信接口建立联系,而PRO*C 是直接与通信接口联系,因此建立在ODBC 上应用程序的执行效率会相对低一些。PRO*C 具有执行效率高,支持嵌入式PL/SQL 块等ORACLE 自身特有的优点,但正因为有了这些优点,使得用PRO*C 开发出的应用程序无法向异构数据库平台移植。 | |